Skip to content

Instantly share code, notes, and snippets.

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.
Configure an AWS EC2 instance running Ubuntu Server 22.04 LTS to run a Rails 7 app using Capistrano for deployment
#!/bin/bash
# This scrips takes a clean Ubuntu Server 20.04 LTS AMI and installs and configures
# everything needed to deploy a Rails app to it. The resulting state is a clean
# instance that can be used to build a base AMI in AWS.
# --- AESTHETICS ---
# Define the color code for green for echo messages
GREEN='\033[0;32m'
# Define the escape sequence for the alien emoji (U+1F47D)
ALIEN='\xF0\x9F\x91\xBD'
# Define the variable for resetting the color back to the default
NC='\033[0m'
# --- CONFIG SCRIPT STARTS ---
# Create rails user and add sudo privileges
# rails is the user we'll use for deploying and running the app
echo -e "${GREEN}${ALIEN} Creating rails user for Capistrano to use...${NC}"
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
echo -e "${GREEN}${ALIEN} User rails created with appropriate permissions.${NC}"
# Update package list and install essential packages
echo -e "${GREEN}${ALIEN} Installing required packages for a Rails production environment...${NC}"
sudo apt-get update -y
sudo apt-get upgrade -y
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
# Import RVM GPG keys as the rails user
echo -e "${GREEN}${ALIEN} Importing GPG keys for RVM...${NC}"
sudo -u rails gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
# Install RVM
echo -e "${GREEN}${ALIEN} Installing RVM to manage Ruby versions...${NC}"
sudo -u rails bash -c "cd /home/rails && curl -sSL https://get.rvm.io | bash -s stable"
# Install Ruby 3.1.2 using RVM
echo -e "${GREEN}${ALIEN} Installing Ruby 3.1.2...${NC}"
sudo -u rails bash -c "cd /home/rails && source ~/.rvm/scripts/rvm && rvm install 3.1.2 && rvm use 3.1.2 --default"
# Install Bundler 2.3.19
echo -e "${GREEN}${ALIEN} Installing Bundler...${NC}"
sudo -u rails bash -c "cd /home/rails && source ~/.rvm/scripts/rvm && gem install bundler -v 2.3.19"
# Install Node.js and yarn
echo -e "${GREEN}${ALIEN} Installing Node and yarn...${NC}"
sudo apt-get install -y nodejs
sudo -u rails curl --compressed -o- -L https://yarnpkg.com/install.sh | bash
# Install nginx
echo -e "${GREEN}${ALIEN} Installing Nginx...${NC}"
sudo apt-get install -y nginx
# Configure Nginx
echo -e "${GREEN}${ALIEN} Configuring Nginx...${NC}"
sudo mkdir -p /etc/nginx/sites-available/
sudo mkdir -p /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
# Now that the www-data user is configured for nginx, let's write the proper nginx configuration
echo -e "${GREEN}${ALIEN} Setting up global Nginx configuration...${NC}"
sudo sh -c 'cat > /etc/nginx/nginx.conf <<NGINX_CONF
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
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;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
# Set Real IPs for Cloudflare.
# The following are Cloudflare IP ranges from here (https://www.cloudflare.com/ips/)
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
}
NGINX_CONF'
# Install Redis server
echo -e "${GREEN}${ALIEN} Installing Redis...${NC}"
sudo apt-get install -y redis
sudo systemctl enable redis-server
sudo systemctl start redis-server
# Install a more recent version of Redis, following official instructions
# from: https://redis.io/docs/install/install-redis/install-redis-on-linux/
# We do this because the current Ubuntu package is Redis 6.0, but Sidekiq needs 6.2 at least
# This installs Redis 7.x
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 redis
# Install Certbot
echo -e "${GREEN}${ALIEN} Installing Certbot...${NC}"
sudo snap install --classic certbot
# Install libvips for image processing
echo -e "${GREEN}${ALIEN} Installing libvips...${NC}"
sudo apt-get install -y libvips-dev libvips
# --- SECURITY HARDENING ---
echo -e "${GREEN}${ALIEN} Configuring the firewall with ufw...${NC}"
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
sudo ufw enable
echo -e "${GREEN}${ALIEN} Disabling password-based SSH authentication...${NC}"
sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
echo -e "${GREEN}${ALIEN} Installing and configuring fail2ban...${NC}"
sudo apt-get install -y fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# --- FINISHING UP ---
sudo hostnamectl set-hostname ubuntu-rails
# TODO: probably a good idea to remove the SSH key used to spin up this instance under /home/ubuntu/.ssh/authorized_keys so the new instances created using the resulting AMI start with a clean state and don't have a random SSH key already configured?
# Delete previous command history so we leave the AMI in a clean state
history -c
echo -e "${GREEN}${ALIEN} Ubtuntu 22.04 LTS machine initial setup for Rails 7 + Capistrano completed successfully.${NC}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment