# DigitalOcean Rails/Ubuntu/NGINX (16.04) Setup 1. Setup 2. Swapfile 3. NGINX 4. ElasticSearch 5. RVM 6. Rails 7. Postgres 8. Capistrano 9. Let's Encrypt 10. Firewall ## Droplet Create a new, start with the smallest droplet. Use **Ubuntu 16.04**, log in as **root**. ## 1. Create non-root user 'rails' [Initial Server Setup with Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-16-04) create user 'rails' ``` adduser rails ``` Add to sudoers group ``` usermod -aG sudo rails ``` Switch user to 'rails' ``` su - rails ``` Create ssh key ``` ssh-keygen ``` Create sym link for webroot ``` cd ~ ln -s /var/www/html html ``` ## 2. Swapfile [How To Add Swap Space on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-16-04) Check swapfile ``` free -h ``` Check freespace ``` df -h ``` Create a 4gb Swap File ``` sudo fallocate -l 4G /swapfile ``` Verify ``` ls -lh /swapfile ``` Lock it down ``` sudo chmod 600 /swapfile ``` Make it swap ``` sudo mkswap /swapfile ``` Enable it ``` sudo swapon /swapfile ``` Verify ``` sudo swapon --show ``` Check swapfile ``` free -h ``` Make it permanent ``` sudo cp /etc/fstab /etc/fstab.bak; echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab ``` ## 3. NGINX [How To Install Nginx on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-16-04) Install NGINX ``` sudo apt-get update sudo apt-get install nginx ``` Check status ``` systemctl status nginx ``` Tweak UFW firewall ``` sudo ufw allow 'OpenSSH' sudo ufw allow 'Nginx Full' sudo ufw enable sudo ufw status ``` Install CURL, get your IP, and check that you can request a page in your browser! ``` sudo apt-get install curl curl -4 icanhazip.com ``` **Actions*** ``` sudo systemctl start nginx ``` ``` sudo systemctl stop nginx ``` ``` sudo systemctl restart nginx ``` **Server Configuration** ```/etc/nginx``` - The nginx configuration directory. All of the Nginx configuration files reside here. ```/etc/nginx/nginx.conf``` The main Nginx configuration file. This can be modified to make changes to the Nginx global configuration. ```/etc/nginx/sites-available/``` The directory where per-site "server blocks" can be stored. Nginx will not use the configuration files found in this directory unless they are linked to the sites-enabled directory (see below). Typically, all server block configuration is done in this directory, and then enabled by linking to the other directory. ```/etc/nginx/sites-enabled/``` The directory where enabled per-site "server blocks" are stored. Typically, these are created by linking to configuration files found in the sites-available directory. ```/etc/nginx/snippets``` This directory contains configuration fragments that can be included elsewhere in the Nginx configuration. Potentially repeatable configuration segments are good candidates for refactoring into snippets. **Server Logs** ```/var/log/nginx/access.log``` Every request to your web server is recorded in this log file unless Nginx is configured to do otherwise. ```/var/log/nginx/error.log``` Any Nginx errors will be recorded in this log. ## 4. ElasticSearch [How To Install and Configure Elasticsearch on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-elasticsearch-on-ubuntu-16-04) Elastic search requires at least 2GB of ram to work for some reason. Install JAVA ``` sudo add-apt-repository ppa:webupd8team/java sudo apt-get install oracle-java8-installer ``` Get ElasticSearch ``` sudo apt-get update wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.0.deb ``` Install ``` sudo dpkg -i elasticsearch-5.4.0.deb ``` Remove DEB file ``` rm elasticsearch-5.4.0.deb ``` Enable ``` sudo systemctl enable elasticsearch.service ``` Configure ``` sudo nano /etc/elasticsearch/elasticsearch.yml ``` Edit Config File ``` ... cluster.name: mycluster1 node.name: "My First Node" ... ``` Restart ``` sudo systemctl start elasticsearch.service ``` Tweak UFW firewall ``` sudo ufw allow from 127.0.0.1 to any port 9200 sudo ufw status ``` Test ``` curl -X GET 'http://localhost:9200' ``` Status ``` sudo systemctl status elasticsearch.service ``` ## 5. RVM [How To Install Ruby on Rails with RVM on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-install-ruby-on-rails-with-rvm-on-ubuntu-16-04) Add key ``` gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 ``` Move to a writeable directory ``` cd /tmp ``` Get latest Ruby ``` curl -sSL https://get.rvm.io -o rvm.sh ``` Compile ``` cat /tmp/rvm.sh | bash -s stable --rails ``` Reload your source file ``` source /etc/profile.d/rvm.sh ``` Install your Ruby VERSION ``` rvm install VERSION --default ``` ## 6. Rails [Deploying a Rails App on Ubuntu 14.04 with Capistrano, Nginx, and Puma](https://www.digitalocean.com/community/tutorials/deploying-a-rails-app-on-ubuntu-14-04-with-capistrano-nginx-and-puma) Install Rails and bundler ``` gem install rails -v '5.0.1' -V --no-ri --no-rdoc gem install bundler -V --no-ri --no-rdoc ``` Authorize your server to read from your repo, you'll have to add a deployment key to your repo. To do this you must copy your ```~/.ssh/id_rsa.pub``` file to your repo (make sure this is your deployment user, eg. ```rails```) ``` ssh -T git@github.com ssh -T git@bitbucket.org ssh -T git@gitlab.com ``` Change Permissions on html directory ``` sudo chown rails:rails /var/www/html/ ``` Clone repo ``` git clone git@gitlab.com:gituser/example.git ``` Add your local key to the server, if this doesn't work just add your local public key (id_rsa.pub) to ```/home/rails/.ssh/authorized_keys``` ``` ssh-copy-id rails@example.com ``` ## 7. Postgres [How To Install and Use PostgreSQL on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-16-04) Install Postgres ``` sudo apt-get update sudo apt-get install postgresql postgresql-contrib ``` Create 'rails' postgres user ``` sudo -i -u postgres createuser --interactive ``` Make it look like this: ``` Enter name of role to add: rails Shall the new role be a superuser? (y/n) y ``` Create the database for rails user ``` createdb rails ``` libpq has to be installed separately ``` sudo apt-get install libpq-dev ``` ## 8. Capistrano Add gems to deployment ``` group :development do gem 'capistrano' gem 'capistrano-rails' gem 'capistrano-rvm' gem 'capistrano3-puma', github: 'seuros/capistrano-puma' gem 'capistrano-bundler' gem 'capistrano-rails-console' end ``` Install Capistrano ``` cap install ``` Capfile ``` require 'capistrano/setup' require 'capistrano/deploy' require 'capistrano/rails' require 'capistrano/rvm' require 'capistrano/bundler' require 'capistrano/puma' require 'capistrano/scm/git' require 'capistrano/rails/console' set :rvm_type, :user set :rvm_ruby_version, '2.3.1' install_plugin Capistrano::Puma install_plugin Capistrano::SCM::Git Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r } ``` Deploy.rb, replace (APP_NAME) ``` lock "3.8.1" set :application, "APP_NAME" set :repo_url, "git@gitlab.com:gituser/example.git" set :deploy_to, "/home/rails/html" set :pty, true set :puma_conf, "#{shared_path}/config/puma.rb" append :linked_files, "config/database.yml", "config/secrets.yml", ".env" append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system" ``` Production.rb, replace SERVER_IP ``` server 'SERVER_IP', user: 'rails', roles: %w{app db web} ``` Create shared config files ``` mkdir -p /var/www/html/shared/config touch /var/www/html/shared/config/database.yml touch /var/www/html/shared/config/secrets.yml touch /var/www/html/shared/config/puma.rb touch /home/rails/html/shared/.env ``` Copy config in databse.yml ``` production: adapter: postgresql encoding: unicode pool: 5 database: APP_PRODUCTION username: rails url: localhost password: <%= ENV['DATABASE_PASSWORD'] %> ``` Copy config into secrets.yml ``` production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> ``` Copy config into .env ``` SECRET_KEY_BASE=mysupersecretkeybase DATABASE_URL=127.0.0.1 DATABASE_PASSWORD=mysupersecretdatabasepassword ``` Copy config in puma.rb ``` #!/usr/bin/env puma directory '/home/rails/html/current' rackup "/home/rails/html/current/config.ru" environment 'production' tag '' pidfile "/home/rails/html/shared/tmp/pids/puma.pid" state_path "/home/rails/html/shared/tmp/pids/puma.state" stdout_redirect '/home/rails/html/shared/log/puma_access.log', '/home/rails/html/shared/log/puma_error.log', true threads 0,16 bind 'unix:///home/rails/html/shared/tmp/sockets/puma.sock' workers 0 prune_bundler on_restart do puts 'Refreshing Gemfile' ENV["BUNDLE_GEMFILE"] = "/home/rails/html/current/Gemfile" end ``` May need Node.js for Javascript Runtime ``` sudo apt-get install nodejs ``` ## 9 Let's Encrypt [How To Secure Nginx with Let's Encrypt on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04) Install Certbot ``` sudo add-apt-repository ppa:certbot/certbot sudo apt-get update sudo apt-get install certbot ``` Edit NGINX ``` sudo nano /etc/nginx/sites-available/default ``` Inside the server block, add this location block ``` location ~ /.well-known { allow all; } ``` Check your NGINX config file ``` sudo nginx -t ``` Restart NGINX ``` sudo systemctl restart nginx ``` Get your cert (make sure you know your webroot) ``` sudo certbot certonly --webroot --webroot-path=/var/www/html -d example.com -d www.example.com ``` Generate strong diff ``` sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048 ``` Create configuration snippet ``` sudo nano /etc/nginx/snippets/ssl-example.com.conf ``` Paste in your certificates ``` ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ``` Create strong encryption params ``` sudo nano /etc/nginx/snippets/ssl-params.conf ``` Paste in params ``` # from https://cipherli.st/ # and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; ssl_ecdh_curve secp384r1; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s; # disable HSTS header for now #add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; ssl_dhparam /etc/ssl/certs/dhparam.pem; ``` ## Nginx Server finalization [How To Secure Nginx with Let's Encrypt on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04) create a new Nginx config file ``` touch /etc/nginx/sites-available/rails chmod 644 rails ``` Update your APPLICATIONSOCKET.sock, server_name, snippet location ``` upstream app_server { server unix:///home/rails/html/shared/tmp/sockets/APPLICATIONSOCKET.sock fail_timeout=0; } server { listen 80 default_server; listen [::]:80 default_server; server_name EXAMPLE.COM; return 301 https://$server_name$request_uri; } server { # SSL configuration listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; include snippets/ssl-example.com.conf; include snippets/ssl-params.conf; root /home/rails/html/current/public; index index.htm index.html; location / { try_files $uri/index.html $uri.html $uri @app; } location ~* ^.+\.(jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|mp3|flv|mpeg|avi)$ { try_files $uri @app; } location @app { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://app_server; } location ~ /.well-known { allow all; } error_page 500 502 503 504 /500.html; client_max_body_size 4G; keepalive_timeout 10; } ``` Update symobolic link ``` cd /etc/nginx/sites-enabled rm default ln -s /etc/nginx/sites-available/rails default ``` Restart NGINX ``` sudo systemctl restart nginx ```