SingleStore Script

March 14, 2022 (2y ago)

The following script is designed to set up a SingleStore database on a dedicated server. It will prompt you for the

  • App domain
  • Git repository
  • PHP version
  • Email
  • Node.js version
  • and whether you want to lock down the machine to a specific IP.

It will then update the system, install PHP, Composer, Node.js, Yarn, Git, Nginx, UFW, and Redis.

It will also configure Nginx, set up a cron job, install Let's Encrypt, configure Redis, install Supervisor, set up a SingleStore cluster, and configure the firewall. Finally, it will install SingleStore Studio and set up recommended vm settings.
# Prompt user for app domain
read -p "Enter the app domain (default: " APP_DOMAIN
# Prompt user for Git repository
read -p "Enter the Git repository (default: track/ " GIT_REPO
# Prompt user for PHP version
read -p "Enter the PHP version (default: 8.2): " PHP_VERSION
# Prompt user for email
read -p "Enter your email: " EMAIL
# Prompt user for Node.js version
read -p "Enter the Node.js version (default: 18): " NODE_MAJOR
# Prompt user if they want to lock down the machine to a specific IP
read -p "Do you want to lock down the machine to a specific IP? (y/n): " LOCK_IP
if [ "$LOCK_IP" == "y" ]; then
    read -p "Enter the IP address: " VPN_IP
# Update system
sudo apt upgrade -y
sudo apt update -y
# PHP installation
sudo apt install lsb-release apt-transport-https ca-certificates software-properties-common -y
sudo wget -O /etc/apt/trusted.gpg.d/php.gpg
sudo sh -c "echo 'deb $(lsb_release -sc) main' > /etc/apt/sources.list.d/php.list"
sudo apt update
sudo apt install php$PHP_VERSION php$PHP_VERSION-{cli,zip,mysql,fpm,bz2,curl,mbstring,intl,redis,dom,common} -y
systemctl enable php$PHP_VERSION-fpm
systemctl start php$PHP_VERSION-fpm
export PHP_INI_PATH="/etc/php/$PHP_VERSION/fpm/php.ini"
sed -i 's/max_execution_time = 30/max_execution_time = 180/' $PHP_INI_PATH
sed -i 's/memory_limit = 128M/memory_limit = 512M/' $PHP_INI_PATH
sudo systemctl restart php$PHP_VERSION-fpm
# Composer installation
cd ~
curl -sS -o composer-setup.php
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
rm -rf composer-setup.php
# Node.js and Yarn installation
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg]$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
sudo apt update
sudo apt install nodejs -y
npm install --global yarn
# Git installation and configuration
sudo apt install git -y
ssh-keygen -t ed25519 -C "$EMAIL"
eval "$(ssh-agent -s)"
git config --global pull.rebase false
echo "Add the following key to your GitHub ("
cat ~/.ssh/
echo ""
echo "Then press any key to continue."
# Wait for a key press to continue
read -s -n 1
# Project setup
git clone$GIT_REPO.git /var/www/$APP_DOMAIN
cd /var/www/$APP_DOMAIN
composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev
yarn install --prod
cp -rf .env.example .env
yarn build
setfacl -R -m g:www-data:rwx /var/www/
# Add Cronjob
(crontab -l; echo "* * * * * cd /var/www/$APP_DOMAIN && php artisan schedule:run >> /dev/null 2>&1") | awk '!x[$0]++' | crontab -
# Nginx configuration
sudo apt install ufw nginx -y
# Path to the script
# Create the script
# Define the URLs for the Cloudflare IP lists
# Fetch the IP lists
IPV4_LIST=$(curl -s $IPV4_URL)
IPV6_LIST=$(curl -s $IPV6_URL)
# Prepare the Nginx configuration content
CF_PROXIES="# Cloudflare IPs\n"
# Add the IPv4 addresses
for IP in $IPV4_LIST; do
    CF_PROXIES+="set_real_ip_from $IP;\n"
# Add the IPv6 addresses
for IP in $IPV6_LIST; do
    CF_PROXIES+="set_real_ip_from $IP;\n"
# Add the real_ip_header directive
CF_PROXIES+="real_ip_header CF-Connecting-IP;"
# Write the configuration to the file
echo -e "$CF_PROXIES" > "/etc/nginx/snippets/proxies.conf"
# Reload Nginx to apply the new configuration
nginx -t && nginx -s reload
# Make the script executable
# Add the cron job to run the script weekly
(crontab -l 2>/dev/null; echo "0 0 * * 0 $UPDATE_SCRIPT") | crontab -
CONFIG="server {
    server_name $APP_DOMAIN;
    root /var/www/$APP_DOMAIN/public;
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";
    real_ip_header X-Forwarded-For;
    include /etc/nginx/snippets/proxies.conf;
    ssl_client_certificate /etc/ssl/certs/cloudflare.crt;
    ssl_verify_client on;
    index index.php;
    fastcgi_buffers 16 16k;
    fastcgi_buffer_size 32k;
    proxy_buffer_size   128k;
    proxy_buffers   4 256k;
    proxy_busy_buffers_size   256k;
    charset utf-8;
    client_max_body_size 4M;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }
    error_page 404 /index.php;
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php$PHP_VERSION-fpm.sock;
echo "$CONFIG" > "/etc/nginx/sites-available/$APP_DOMAIN.conf"
sudo ln -s /etc/nginx/sites-available/$APP_DOMAIN.conf /etc/nginx/sites-enabled
sudo curl -L -o /etc/ssl/certs/cloudflare.crt
nginx -s reload
ufw allow 'Nginx Full'
# Firewall configuration
if [ "$LOCK_IP" == "y" ]; then
    ufw allow from $VPN_IP to any port 8080
    ufw allow from $VPN_IP to any port 8081
    ufw allow from $VPN_IP to any port 3306
    ufw allow from $VPN_IP to any port 22
    ufw allow 8080/tcp
    ufw allow 8081/tcp
    ufw allow 3306/tcp
    ufw allow 22/tcp
# Enable the firewall
ufw enable
# LetsEncrypt
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx --non-interactive --agree-tos -m $EMAIL -d $APP_DOMAIN
# Redis installation and configuration
sudo apt install redis-server -y
sudo systemctl enable redis-server.service
sudo systemctl start redis-server.service
# Supervisor installation and configuration
sudo apt install supervisor
sudo systemctl enable supervisor.service
sudo systemctl start supervisor.service
# Define the content of the file
command=php /var/www/$APP_DOMAIN/artisan horizon
echo "$CONTENT" > "/etc/supervisor/conf.d/horizon.conf"
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start "horizon:*"
# SingleStore installation
wget -O - '' 2>/dev/null | sudo apt-key add - && apt-key list
apt-cache policy apt-transport-https
echo "deb [arch=amd64] memsql main" | sudo tee /etc/apt/sources.list.d/memsql.list
sudo apt update && sudo apt -y install singlestoredb-toolbox singlestoredb-studio
sudo systemctl start singlestoredb-studio
sudo systemctl enable singlestoredb-studio.service
# Function to calculate min_free_kbytes based on system RAM
calculate_min_free_kbytes() {
    total_ram_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
    min_free_kb=$((total_ram_kb / 100))  # 1% of total RAM
    if (( min_free_kb > 4000000 )); then
        min_free_kb=4000000  # Cap at 4 GB
    echo $min_free_kb
# Set recommended vm settings (According to SingleStore)
echo "Setting recommended vm settings..."
sudo sysctl -w vm.max_map_count=1000000000
sudo sysctl -w vm.overcommit_memory=0
sudo sysctl -w vm.swappiness=10
sudo sysctl -w vm.overcommit_ratio=99  # Only if vm.overcommit_memory is set to 2
sudo sysctl -w net.core.rmem_max=8388606
sudo sysctl -w net.core.wmem_max=8388606
# Calculate min_free_kbytes
# Set min_free_kbytes
sudo sysctl -w vm.min_free_kbytes=$min_free_kbytes
# Prompt user for SingleStore key
read -p "Enter your SingleStore license key (from " SINGLESTORE_KEY
high_availability: false
memsql_server_version: 8.5.15
  - hostname: $PUBLIC_IP
      - role: Master
          port: 3306
      - role: Leaf
          port: 3307
    localhost: true"
echo "$CLUSTER_YAML" > "cluster.yml"
sdb-deploy setup-cluster --cluster-file cluster.yml
rm -rf cluster.yml