Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rameerez/a3f88dff54737345c69c21be0ab31425 to your computer and use it in GitHub Desktop.
Save rameerez/a3f88dff54737345c69c21be0ab31425 to your computer and use it in GitHub Desktop.
Configure an AWS EC2 instance running Amazon Linux 2023 (AL2023) to run a Rails 7 app using Capistrano for deployment
#!/bin/bash
# This scrips takes a clean AWS Amazon Linux 2023 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 for an EC2 ASG.
# --- 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 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}"
# Switch to the new rails user from now on
su -l rails <<EOF
# Update package list and install essential packages
# --allowerasing allows us to remove gnupg2-minimal, because we're using gnupg2 instead
echo -e "${GREEN}${ALIEN} Installing required packages for a Rails production environment...${NC}"
sudo dnf update -y
sudo dnf install -y git zlib-devel openssl-devel readline-devel sqlite-devel libyaml-devel libxml2-devel libxslt-devel libcurl-devel libffi-devel gcc gcc-c++ patch make automake autoconf bison postgresql-devel gdbm-devel ncurses-devel ruby-devel jq gnupg2 postgresql15 htop ImageMagick --allowerasing
# crontab does not come installed by default in AL2023 (wtf?)
echo -e "${GREEN}${ALIEN} Installing crontab to run scheduled background jobs...${NC}"
sudo dnf install -y cronie
sudo systemctl enable crond.service
sudo systemctl start crond.service
# Install RVM and Ruby 3.1.2
echo -e "${GREEN}${ALIEN} Installing RVM to manage Ruby versions...${NC}"
gpg2 --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
curl -sSL https://get.rvm.io | bash -s stable
source ~/.rvm/scripts/rvm
echo -e "${GREEN}${ALIEN} Installing Ruby v3.1.2...${NC}"
rvm install 3.1.2
echo -e "${GREEN}${ALIEN} Setting Ruby v3.1.2 as system default...${NC}"
rvm use 3.1.2 --default
# Install Bundler 2.3.19
echo -e "${GREEN}${ALIEN} Installing Bundler...${NC}"
gem install bundler -v 2.3.19
# Install Node.js and yarn
echo -e "${GREEN}${ALIEN} Installing Node and yarn...${NC}"
sudo dnf install -y nodejs
curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
sudo dnf install -y yarn
# Install and configure Nginx
echo -e "${GREEN}${ALIEN} Installing Nginx...${NC}"
sudo dnf install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx
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
# Add nginx www-data following Ubuntu conventions (AL2023 has nginx user by default)
# This creates the www-data user with the www-data group as its primary group, sets its shell to /sbin/nologin (which prevents login), and omits creating a home directory with the -M flag
echo -e "${GREEN}${ALIEN} Adding group www-data to follow Ubuntu naming conventions (instead of using group nginx)...${NC}"
sudo groupadd www-data
sudo useradd -g www-data -s /sbin/nologin -M www-data
sudo chown -R www-data:www-data /var/log/nginx
sudo usermod -a -G www-data rails
sudo systemctl restart nginx
# Now that the www-data user is created 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 dnf install -y redis6
sudo systemctl enable redis6
sudo systemctl start redis6
# Install Certbot
# Certbot cannot be installed with dnf, must be installed using Python3 env
# Source: https://certbot.eff.org/instructions?ws=nginx&os=pip via https://repost.aws/questions/QUKV7YqM2HR_a1p_pSlCkk3g/installing-let-s-encrypt-on-amazon-linux2023
echo -e "${GREEN}${ALIEN} Installing Certbot...${NC}"
sudo dnf install -y python3 augeas-libs
sudo python3 -m venv /opt/certbot/
sudo /opt/certbot/bin/pip install --upgrade pip
sudo /opt/certbot/bin/pip install certbot certbot-nginx
sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
EOF
# Configure SSH key for the rails user (same as ec2-user, AWS configured key)
echo -e "${GREEN}${ALIEN} Adding ec2-user ssh key to user rails...${NC}"
sudo mkdir /home/rails/.ssh
sudo cp ~/.ssh/authorized_keys /home/rails/.ssh
sudo chown -R rails:rails /home/rails/.ssh
sudo chmod 700 /home/rails/.ssh
sudo chmod 600 /home/rails/.ssh/authorized_keys
echo -e "${GREEN}${ALIEN} You can now ssh as user rails using the same keypair as ec2-user.${NC}"
# Delete previous command history so we leave the AMI in a clean state
history -c
echo -e "${GREEN}${ALIEN} Amazon Linux 2023 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