Last active
January 12, 2024 01:56
-
-
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
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 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