Skip to content

Instantly share code, notes, and snippets.

@rameerez
Last active January 15, 2025 14:06
Show Gist options
  • Save rameerez/4813291ad6e21766e05718a961276341 to your computer and use it in GitHub Desktop.
Save rameerez/4813291ad6e21766e05718a961276341 to your computer and use it in GitHub Desktop.
Rails Production Server Setup - Set up a new Ubuntu Server 24.04 LTS to run a Rails 7 app, using Capistrano for deployment
#!/bin/bash
# This script takes a clean Ubuntu Server 24.04 LTS AMI and installs and configures
# everything needed to deploy a Rails 7 app to it. The resulting state is a secure,
# production-ready instance.
set -euo pipefail
# --- AESTHETICS ---
GREEN='\033[0;32m'
ALIEN='\xF0\x9F\x91\xBD'
NC='\033[0m'
# --- HELPER FUNCTIONS ---
log() {
echo -e "${GREEN}${ALIEN} $1${NC}"
}
# --- SECURITY FUNCTIONS ---
configure_firewall() {
log "Configuring the firewall with ufw..."
sudo apt-get install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
echo "y" | sudo ufw enable
}
harden_ssh() {
log "Hardening SSH configuration..."
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo tee /etc/ssh/sshd_config > /dev/null <<EOF
Port 22
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
UsePrivilegeSeparation yes
KeyRegenerationInterval 3600
ServerKeyBits 1024
SyslogFacility AUTH
LogLevel INFO
LoginGraceTime 120
PermitRootLogin prohibit-password
StrictModes yes
RSAAuthentication yes
PubkeyAuthentication yes
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
PasswordAuthentication no
X11Forwarding no
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
UsePAM yes
MaxAuthTries 6
AllowUsers root rails
EOF
sudo systemctl restart ssh.service
}
setup_fail2ban() {
log "Installing and configuring fail2ban..."
sudo apt-get install -y fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo sed -i 's/bantime = 10m/bantime = 1h/' /etc/fail2ban/jail.local
sudo sed -i 's/findtime = 10m/findtime = 30m/' /etc/fail2ban/jail.local
sudo sed -i 's/maxretry = 5/maxretry = 3/' /etc/fail2ban/jail.local
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
}
setup_user_ssh() {
log "Setting up SSH for rails user..."
# Setup for rails user
sudo mkdir -p /home/rails/.ssh
sudo chmod 700 /home/rails/.ssh
# Check if root's authorized_keys exists and copy to rails user
if [ -f /root/.ssh/authorized_keys ]; then
sudo cp /root/.ssh/authorized_keys /home/rails/.ssh/
sudo chmod 600 /home/rails/.ssh/authorized_keys
sudo chown -R rails:rails /home/rails/.ssh
else
log "Warning: /root/.ssh/authorized_keys not found. You may need to set up SSH keys manually."
fi
log "NOTE: GitHub SSH key setup required for rails user. Please follow the post-installation instructions."
}
# --- MAIN SCRIPT ---
# Update and upgrade packages
log "Updating and upgrading packages..."
sudo apt-get update -y
sudo apt-get upgrade -y
# Install essential packages
log "Installing required packages for a Rails production environment..."
sudo apt-get install -y git zlib1g-dev libssl-dev libreadline-dev libsqlite3-dev libyaml-dev \
libxml2-dev libxslt1-dev libcurl4-openssl-dev libffi-dev build-essential libpq-dev \
libgdbm-dev libncurses5-dev libgmp-dev libgdbm-compat-dev autoconf bison \
libreadline-dev postgresql-server-dev-all postgresql postgresql-contrib imagemagick \
jq gnupg2 htop nginx redis-server libcrypt-dev libcrypt1 libcryptsetup12 \
libvips-dev libvips poppler-utils
# Create rails user and add sudo privileges
log "Creating rails user for Capistrano to use..."
sudo adduser --disabled-password --gecos "" rails
sudo chmod 755 /home/rails
echo 'rails ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/rails
sudo chmod 0440 /etc/sudoers.d/rails
# Install RVM and Ruby
log "Installing RVM and Ruby 3.3.4..."
sudo -u rails gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
sudo -u rails bash -c "curl -sSL https://get.rvm.io | bash -s stable"
sudo -u rails bash -c "source ~/.rvm/scripts/rvm && rvm install 3.3.4 && rvm use 3.3.4 --default"
# Install Bundler
log "Installing Bundler..."
sudo -u rails bash -c "source ~/.rvm/scripts/rvm && gem install bundler -v 2.3.19"
# Install Node.js and Yarn
log "Installing Node.js and Yarn..."
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo -u rails curl --compressed -o- -L https://yarnpkg.com/install.sh | bash
# Configure Nginx
log "Configuring Nginx..."
sudo mkdir -p /etc/nginx/sites-available/ /etc/nginx/sites-enabled/
sudo sed -i '/http {/a \ include /etc/nginx/sites-enabled/*;' /etc/nginx/nginx.conf
sudo chown -R www-data:www-data /var/log/nginx
sudo usermod -a -G www-data rails
sudo systemctl enable nginx
sudo systemctl start nginx
# Write Nginx configuration
log "Setting up global Nginx configuration..."
cat << EOF | sudo tee /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
# Set Real IPs for Cloudflare
# The following are Cloudflare IP ranges from https://www.cloudflare.com/ips/
include /etc/nginx/cloudflare_real_ip.conf;
real_ip_header CF-Connecting-IP;
real_ip_recursive on;
}
EOF
# Create Cloudflare real IP configuration
log "Creating Cloudflare real IP configuration..."
curl -sSL https://www.cloudflare.com/ips-v4 | sed 's/^/set_real_ip_from /' | sed 's/$/;/' | sudo tee /etc/nginx/cloudflare_real_ip.conf
echo "" | sudo tee -a /etc/nginx/cloudflare_real_ip.conf # Add a newline between IPv4 and IPv6 addresses
curl -sSL https://www.cloudflare.com/ips-v6 | sed 's/^/set_real_ip_from /' | sed 's/$/;/' | sudo tee -a /etc/nginx/cloudflare_real_ip.conf
# Install and configure Redis
log "Installing and configuring Redis..."
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt-get update
sudo apt-get install -y redis
sudo sed -i 's/^# maxmemory-policy.*/maxmemory-policy allkeys-lru/' /etc/redis/redis.conf
sudo sed -i 's/^# maxmemory .*/maxmemory 256mb/' /etc/redis/redis.conf
sudo systemctl enable redis-server
sudo systemctl start redis-server
# Install Certbot
log "Installing Certbot..."
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# Install additional useful tools
log "Installing additional tools..."
sudo apt-get install -y bat btop lsd
# Set up aliases
log "Setting up aliases for cat, top and ls..."
sudo tee /etc/profile.d/custom_aliases.sh > /dev/null <<EOF
# Custom aliases
alias ls='lsd -lah'
alias cat='batcat'
alias top='btop'
EOF
log "Alias setup complete. Changes will take effect on next login or shell start."
# Configure security
configure_firewall
harden_ssh
setup_fail2ban
setup_user_ssh
# Set hostname
sudo hostnamectl set-hostname ubuntu-rails-production
# --- CLEANUP AND FINALIZATION ---
# Clean up
log "Cleaning up..."
sudo apt-get autoremove -y
sudo apt-get clean
# Delete command history
history -c
log "Ubuntu 24.04 LTS machine initial setup for Rails 7 + Capistrano completed successfully."
log "IMPORTANT: Please follow the post-installation instructions for setting up the GitHub SSH key."
# --- POST-INSTALLATION INSTRUCTIONS ---
cat << EOF
POST-INSTALLATION INSTRUCTIONS:
1. SSH keys have been set up for the rails user using the root's authorized_keys.
Verify that you can SSH into the server as the rails user:
- ssh rails@<your-server-ip>
2. Root login is still allowed with public key authentication for maintenance.
However, it's recommended to use the rails user for regular operations.
3. For GitHub SSH key setup for the rails user:
a. SSH into your server as the rails user: ssh rails@<your-server-ip>
b. Generate a new SSH key: ssh-keygen -t ed25519 -C "your_email@users.noreply.github.com"
c. Add the public key to your GitHub account: cat ~/.ssh/id_ed25519.pub
d. Test the connection: ssh -T git@github.com
4. If you encounter any issues:
- Check the SSH configuration: cat /etc/ssh/sshd_config
- Verify firewall settings: sudo ufw status
- Check SSH service status: sudo systemctl status ssh
5. Remember, password authentication has been disabled for security reasons.
Always use SSH keys to log into the server.
EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment