Last active
April 11, 2022 07:49
-
-
Save ARozputnii/ed4709786db2d62c04ea1d00bba65f39 to your computer and use it in GitHub Desktop.
Setup Rails app on Ubuntu 20.04 LTS (DigitalOcean or AWS EC2)
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
// Basic server setup | |
1) Connect to your server | |
your_machine$ ssh root@server_host | |
2) Update/Upgrade your system packages | |
root# apt-get update && apt-get upgrade | |
3) Add swap space | |
https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-20-04-ru | |
root# fallocate -l 4G /swapfile | |
root# chmod 600 /swapfile | |
root# mkswap /swapfile | |
root# swapon /swapfile | |
root# swapon --show | |
root# free -h | |
root# cp /etc/fstab /etc/fstab.bak | |
root# echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab | |
4) Install dependencies for Ruby | |
root# apt install curl | |
root# curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - | |
root# apt-get install -y nodejs | |
root# curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - | |
root# echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list | |
root# apt-get update && apt-get install yarn | |
root# apt-get install git-core zlib1g-dev build-essential libssl-dev libreadline-dev \ | |
libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev \ | |
software-properties-common libffi-dev unzip | |
5) Postgresql | |
root# apt update | |
root# apt install postgresql postgresql-contrib libpq-dev | |
6) Fix perl: warning: Setting locale failed. | |
root# echo -e 'LANG="en_US.UTF-8"\nLC_ALL="en_US.UTF-8"\nLANGUAGE="en_US:en"' > /etc/default/locale | |
7) Mainline nginx with stable ngx_pagespeed | |
root# bash <(curl -f -L -sS https://ngxpagespeed.com/install) -y --nginx-version latest -a ' \ | |
--prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf \ | |
--error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid \ | |
--lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp \ | |
--http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \ | |
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx \ | |
--group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module \ | |
--with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module \ | |
--with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module \ | |
--with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module \ | |
--with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module \ | |
--with-stream_ssl_module --with-stream_ssl_preread_module' | |
root# adduser --system --no-create-home --shell /bin/false --group --disabled-login nginx | |
root# wget -O /etc/nginx/nginx.conf https://gist.githubusercontent.com/PavelBezpalov/6525017b7ab61c843264a0b544acfdd6/raw/nginx.conf | |
root# mkdir /etc/nginx/sites-enabled | |
root# mkdir /etc/nginx/sites-available | |
root# mkdir /var/cache/nginx | |
root# mkdir -p /var/ngx_pagespeed_cache | |
root# chown nginx:nginx /var/ngx_pagespeed_cache | |
root# wget -O /etc/init.d/nginx https://gist.githubusercontent.com/PavelBezpalov/6525017b7ab61c843264a0b544acfdd6/raw/nginx | |
root# chmod +x /etc/init.d/nginx | |
root# systemctl enable nginx.service | |
8) Nginx | |
root# apt update | |
root# apt install nginx | |
# choose everywhere -Y- | |
9) UFW | |
// https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-ubuntu-20-04 | |
root# ufw status | |
root# ufw enable | |
root# ufw app list | |
root# ufw allow 'OpenSSH' | |
root# ufw allow 'Nginx Full' | |
root# ufw app list | |
10) Install Certbot | |
root# apt-get install software-properties-common | |
root# apt install certbot python3-certbot-nginx | |
root# apt-get update | |
root# apt-get install certbot | |
root$ nano /etc/letsencrypt/cli.ini | |
// ADD LINE | |
renew-hook = systemctl restart nginx | |
11) Add deployer user in sudo group | |
root# adduser deployer | |
root# gpasswd -a deployer sudo | |
12) Disable ssh root login, permit password login | |
root# nano /etc/ssh/sshd_config | |
EDIT: | |
PermitRootLogin no | |
PasswordAuthentication yes | |
SAVE CHANGES | |
root# service ssh restart | |
root# exit | |
13) Add authorized keys | |
your_machine$ cat ~/.ssh/id_rsa.pub | ssh deployer@IP_SERVER "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys" | |
your_machine$ ssh deployer@server_host | |
deployer$ mkdir apps & mkdir backup_files | |
14) RVM, Ruby 2.7.2, bundler | |
https://github.com/rvm/ubuntu_rvm | |
deployer$ sudo apt-get install libgdbm-dev libncurses5-dev automake libtool bison libffi-dev | |
deployer$ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB | |
deployer$ curl -sSL https://get.rvm.io | bash -s stable | |
deployer$ echo "gem: --no-document" > ~/.gemrc | |
deployer$ source ~/.rvm/scripts/rvm | |
deployer$ rvm install 2.7.2 && rvm use 2.7.2 --default && ruby -v | |
deployer$ gem install bundler | |
15) For postgresql deployer user, project db | |
deployer$ sudo su - postgres | |
postgres$ createuser --pwprompt deployer | |
postgres$ createdb -O deployer <<APP_DB_NAME>> | |
postgres$ psql -U postgres -W | |
postgres$ \list | |
postgres$ \q | |
postgres$ exit | |
16) PostgreSQL Remote Connections | |
https://www.digitalocean.com/community/tutorials/how-to-secure-postgresql-against-automated-attacks | |
deployer$ sudo ufw allow 5432 | |
deployer$ sudo ufw status | |
deployer$ sudo nano /etc/postgresql/12/main/pg_hba.conf | |
host DB_NAME deployer all md5 | |
deployer$ sudo nano /etc/postgresql/12/main/postgresql.conf | |
listen_addresses = '*' | |
// testing | |
deployer$ sudo service postgresql restart | |
your_machine$ psql -U deployer -h IP_SERVER -d DB_NAME | |
// Capistrano | |
17) Capistrano gems | |
Add to Gemfile: | |
_________________________ | |
group :development do | |
gem "capistrano" | |
gem "capistrano-rvm" | |
gem "capistrano-rails" | |
gem "capistrano3-puma", github: "seuros/capistrano-puma" | |
gem "capistrano-nginx", "~> 1.0" | |
gem "capistrano-upload-config" | |
gem "sshkit-sudo" | |
end | |
_________________________ | |
RUN: | |
your_app$ bundle | |
your_app$ cap install | |
18) Edit Capfile | |
_________________________ | |
require 'capistrano/setup' | |
require 'capistrano/deploy' | |
require 'capistrano/scm/git' | |
install_plugin Capistrano::SCM::Git | |
require 'capistrano/rvm' | |
require 'capistrano/rails' | |
require 'capistrano/puma' | |
install_plugin Capistrano::Puma | |
install_plugin Capistrano::Puma::Nginx | |
install_plugin Capistrano::Puma::Jungle | |
require 'capistrano/nginx' | |
require 'capistrano/upload-config' | |
require 'sshkit/sudo' | |
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r } | |
___________________________________________________________________________ | |
19) Edit config/deploy.rb | |
EDIT config/deploy.rb AS ATTACHED deploy.rb AND CHANGE VARIABLES IN IT | |
______________________________________________________________________ | |
lock "~> 3.15.0" | |
set :repo_url, "" | |
ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp | |
set :user, "deployer" | |
set :rvm_ruby_version, "2.7.2" | |
set :pty, true | |
set :linked_files, fetch(:linked_files, []).push("config/database.yml", "config/secrets.yml", "config/master.key", "config/puma.rb") | |
set :linked_dirs, fetch(:linked_dirs, []).push("log", "tmp/pids", "tmp/cache", "tmp/sockets", "vendor/bundle", "public/system", "public/uploads", "public/images", "storage") | |
set :config_example_suffix, ".example" | |
set :config_files, ["config/database.yml", "config/secrets.yml"] | |
set :nginx_use_ssl, false | |
namespace :deploy do | |
before 'check:linked_files', 'set:master_key' | |
before 'check:linked_files', 'config:push' | |
before 'check:linked_files', 'puma:jungle:setup' | |
before 'check:linked_files', 'puma:nginx_config' | |
end | |
after "deploy:finished", "nginx:restart" | |
after "deploy:finished", "puma:start" | |
_______________________________________ | |
20) Edit config/deploy/production.rb | |
_________________________________________________ | |
server "server IP", user: "#{fetch(:user)}", roles: %w{app db web}, primary: true | |
set :application, "app-name" | |
set :deploy_to, "/home/#{fetch(:user)}/apps/#{fetch(:application)}" | |
set :environment, "production" | |
set :rails_env, "production" | |
set :nginx_server_name, "server IP" | |
set :puma_conf, "#{shared_path}/config/puma.rb" | |
__________________________________________________ | |
21) Create rake tasks | |
loading master_key | |
your_app$ cd lib/capistrano/tasks | |
add file set_master_key.rake | |
____________________________ | |
namespace :set do | |
task :master_key do | |
on roles(:app), in: :sequence, wait: 10 do | |
unless test("[ -f #{shared_path}/config/master.key ]") | |
upload! 'config/master.key', "#{shared_path}/config/master.key" | |
end | |
end | |
end | |
end | |
_________________________________ | |
your_app$ cd lib/capistrano/tasks | |
add file puma_restart.rake | |
_________________________________ | |
namespace :puma do | |
bundle_wrapper_path = "/home/deployer/.rvm/gems/ruby-2.7.2/wrappers/bundle" | |
desc "Start puma" | |
task :start do | |
on roles(:app) do | |
execute "cd #{release_path} && #{bundle_wrapper_path} exec pumactl -P #{shared_path}/tmp/pids/puma.pid start" | |
end | |
end | |
desc "Stop puma" | |
task :stop do | |
on roles(:app) do | |
execute "cd #{release_path} && #{bundle_wrapper_path} exec pumactl -P #{shared_path}/tmp/pids/puma.pid stop" | |
end | |
end | |
desc "Restart puma" | |
task :restart do | |
on roles(:app) do | |
execute "cd #{release_path} && #{bundle_wrapper_path} exec pumactl -P #{shared_path}/tmp/pids/puma.pid stop" | |
sudo "service puma restart" | |
end | |
end | |
end | |
_________________________________ | |
22) Add config files | |
RUN: | |
your_app$ cp config/database.yml config/database.yml.example | |
your_app$ echo 'secret_key_base: <%= Rails.application.credentials.secret_key_base %>' >> config/secrets.yml | |
your_app$ cp config/secrets.yml config/secrets.yml.example | |
your_app$ cap production config:init | |
your_app$ echo '/config/database.yml' >> .gitignore | |
your_app$ echo '/config/database.production.yml' >> .gitignore | |
your_app$ echo '/config/secrets.yml' >> .gitignore | |
your_app$ echo '/config/secrets.production.yml' >> .gitignore | |
Edit with your parameters | |
/config/database.production.yml | |
/config/secrets.production.yml | |
23) Generate Nginx/puma config: | |
your_app$ rails g capistrano:nginx_puma:config | |
Edit or leave as is: | |
config/deploy/templates/nginx_conf.erb | |
config/deploy/templates/puma.rb.erb | |
24) Add Ruby-Version file for Puma Jungle | |
your_app$ echo 'ruby-VERSION' > .ruby-version | |
25) GIT commit and push changes | |
26) Deploy | |
your_app$ cap production deploy | |
27) Edit deploy.rb | |
change - after "deploy:finished", "puma:start" | |
on - after "deploy:finished", "puma:restart" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment