Deploying to EC2 (with Capistrano) - restarone/violet_rails GitHub Wiki

Deploying to EC2

install app dependencies

sudo apt-get update -y && sudo apt-get upgrade -y
sudo apt install curl -y 
sudo apt install nodejs -y && sudo apt install npm -y

sudo apt-get install htop imagemagick build-essential zlib1g-dev openssl libreadline6-dev git-core zlib1g libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf automake libtool bison libgecode-dev -y && sudo apt-get install libpq-dev -y



echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc && echo 'eval "$(rbenv init -)"' >> ~/.bashrc
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv && git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
source ~/.bashrc
rbenv install 2.6.6 && rbenv global 2.6.6 && echo 'gem: --no-ri --no-rdoc' >> ~/.gemrc && source ~/.bashrc && gem install bundler:2.1.4 && gem install rails -v 6.1.3


curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update -y
sudo apt install yarn -y
sudo apt install redis-server -y

sudo apt-get install nginx -y

Database setup (RDS)

connect to the server as the default postgres user

psql -h endpoint.compute-1.amazonaws.com -p 5432 -d postgres -U postgres

Create a new user for the application and assign a strong password

CREATE ROLE username;
ALTER ROLE  username  WITH LOGIN;
ALTER USER  username  CREATEDB;
ALTER USER  username  WITH PASSWORD 'passwordhere';

create the database

psql -h endpoint.amazonaws.com -p 5432 -U username -d postgres -c 'CREATE DATABASE violet_production'

If you want to setup your own postgres server on EC2 you can follow the documentation here: https://gist.github.com/donrestarone/c1c7ca2e289313e757c2f8ef98c6aa86

allow ubuntu to write to /var/www

sudo chown -R ubuntu /var/www

try to run a deployment

it will fail, but capistrano will create the file structure needed by the application. Set the IP address of your server in config/deploy/production.rb and run:

bundle exec cap production deploy

create configuration files

After creation, copy paste the configurations found in the repository (eg: config/cable.yml, config/database.yml, config/secrets.yml etc)

cd /var/www/violet/shared/config
touch cable.yml database.yml secrets.yml  storage.yml webpacker.yml sidekiq.yml

make env variables available to the app (for rbenv and rbenv vars)

clone the rbenv repo:

git clone https://github.com/rbenv/rbenv-vars.git $(rbenv root)/plugins/rbenv-vars

to load env variables in rails console put this in in ~/.bashrc

export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$HOME/.rbenv/bin:$PATH"

env vars

create these at /var/www/violet/.rbenv-vars

RAILS_ENV=staging
DATABASE_HOST=ec2-3-83-199-128.compute-1.amazonaws.com
DATABASE_USERNAME=violet_staging_ubuntu
DATABASE_PASSWORD=xxx
DATABASE_NAME=violet_staging
DATABASE_PORT=5432
APP_HOST=restarone.solutions
RAILS_SERVE_STATIC_FILES=true
SECRET_KEY_BASE=foo

#optional
MAILGUN_API_KEY=foo
MAILGUN_INGRESS_SIGNING_KEY=foo
AWS_ACCESS_KEY_ID=foo
AWS_SECRET_ACCESS_KEY=foo
AWS_REGION=us-east-1
AWS_BUCKET=restarone.solutions
RECAPTCHA_SITE_KEY=foo
RECAPTCHA_SECRET_KEY=foo

service files

for the server (in /etc/systemd/system/puma.service)

[Unit]
Description=violet rails server
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/var/www/violet/current
EnvironmentFile=/var/www/violet/.rbenv-vars
ExecStart=/home/ubuntu/.rbenv/bin/rbenv exec bundle exec puma -C /var/www/violet/current/config/puma.rb
ExecStop=/home/ubuntu/.rbenv/bin/rbenv exec bundle exec pumactl -S /var/www/violet/current/config/puma.rb stop
ExecReload=/home/ubuntu/.rbenv/bin/rbenv exec bundle exec pumactl -F /var/www/violet/current/config/puma.rb phased-restart
TimeoutSec=15
Restart=always


[Install]
WantedBy=multi-user.target

for sidekiq (in /etc/systemd/system/sidekiq.service)

To view the sidekiq logs:

journalctl -u sidekiq.service -f

the service should look something like:

[Unit]
Description=sidekiq
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/var/www/violet/current
EnvironmentFile=/var/www/violet/.rbenv-vars
ExecStart=/home/ubuntu/.rbenv/bin/rbenv exec bundle exec sidekiq -C config/sidekiq.yml
ExecStop=ps -ef | grep sidekiq | grep -v grep | awk '{print $2}' | xargs kill -9
TimeoutSec=15
Restart=always


[Install]
WantedBy=multi-user.target

enable the service by running

sudo systemctl daemon-reload
sudo systemctl enable puma.service
sudo systemctl start puma.service
sudo systemctl status puma.service

sudo systemctl enable sidekiq.service
sudo systemctl start sidekiq.service
sudo systemctl status sidekiq.service

tail the logs for sidekiq:

journalctl -u sidekiq.service -f

nginx setup (/etc/nginx/sites-available/restarone.solutions.conf)

the setup for restarone.solutions looks something like this (with SSL configuration in place). For more information see here: https://github.com/restarone/violet_rails/wiki/nginx-configurations

server {
    listen      80;


    #Rewrite all nonssl requests to ssl.
    return 301 https://$host$request_uri;
}



server {

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    client_max_body_size 4G;

    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/restarone.solutions/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/restarone.solutions/privkey.pem;
}

But a good starting point would be:

server {
    listen 80;
    server_name  yourwebsitename.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_set_header Upgrade $http_upgrade;

        proxy_http_version 1.1;
        proxy_set_header Upgrade websocket;
        proxy_set_header Connection Upgrade;
    }
    client_max_body_size 4G;
}

then symlink it

sudo ln -s /etc/nginx/sites-available/restarone.solutions.conf /etc/nginx/sites-enabled/restarone.solutions.conf

and restart nginx

sudo service nginx configtest
sudo service nginx reload

remove the default nginx configuration

sudo rm /etc/nginx/sites-enabled/default
sudo rm /etc/nginx/sites-available/default

create the global admin and domain apex 'subdomain'

ssh into the violet rails server, navigate to /var/www/violet/current and follow the guide here: https://github.com/restarone/violet_rails/wiki/User-and-domain-setup-scripts

setup SSL and certbot

sudo apt-get install python3-certbot-nginx
sudo certbot certonly --manual --preferred-challenges=dns --email [email protected] --server https://acme-v02.api.letsencrypt.org/directory  --agree-tos --manual-public-ip-logging-ok -d "*.restarone.solutions" -d "restarone.solutions"
sudo service nginx reload
# run the above script again to renew
more info on renewing available here: https://community.letsencrypt.org/t/an-authentication-script-must-be-provided-with-manual-auth-hook/74301/2

if you dont want wildcard domain support with lets encrpy (ie your app is only hosted at; foo.example.com)

sudo certbot --nginx -d your-domain.com
sudo certbot renew

setting up multiple wildcard domains with certbot SSL

pass every domain under the -d flag like so:

sudo certbot certonly --manual --preferred-challenges=dns --email [email protected] --server https://acme-v02.api.letsencrypt.org/directory  --agree-tos --manual-public-ip-logging-ok -d "*.everybodyisdoingdrugs.com" -d "everybodyisdoingdrugs.com" -d "*.everyoneisdoingdrugs.com" -d "everyoneisdoingdrugs.com"

AWS setup

for storage, follow the guide here: https://github.com/restarone/violet_rails/wiki/Production-AWS-setup