Last active
January 15, 2025 14:06
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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