Differences

This shows you the differences between two versions of the page.

Link to this comparison view

deploying_a_rails_app_on_debian_jessie_with_capistrano_nginx_and_puma_en [2017/09/05 12:18] (current)
Line 1: Line 1:
 +====== Deploying a Rails App on Debian Jessie with Capistrano, Nginx, and Puma ======
  
 +Rails is an open source web application framework written in Ruby. It follows the Convention over Configuration philosophy by making assumptions that there is the '​best'​ way of doing things. This allows you to write less code while accomplishing more without having you go through endless config files.
 +
 +Nginx is a high performance HTTP server, reverse proxy, and a load balancer known for its focus on concurrency,​ stability, scalability,​ and low memory consumption. Like Nginx, Puma is another extremely fast and concurrent web server with a very small memory footprint but built for Ruby web applications.
 +
 +Capistrano is a remote server automation tool focusing mainly on Ruby web apps. It's used to reliably deploy web apps to any number of remote machines by scripting arbitrary workflows over SSH and automate common tasks such as asset pre-compilation and restarting the Rails server.
 +
 +In this tutorial we'll install Ruby and Nginx on Debian Jessie and configure Puma and Capistrano in our web app. Nginx will be used to capture client requests and pass them over to the Puma web server running Rails. We'll use Capistrano to automate common deployment tasks, so every time we have to deploy a new version of our Rails app to the server, we can do that with a few simple commands.
 +
 +Let's configure the repositories
 +<sxh bash>
 +vi /​etc/​apt/​sources.list
 +# OFFICIAL REPOSITORY
 +deb http://​httpredir.debian.org/​debian jessie main contrib non-free
 +deb-src http://​httpredir.debian.org/​debian jessie main contrib non-free
 +
 +# SECURITY UPDATE REPOSITORY
 +deb http://​security.debian.org/​ jessie/​updates main contrib non-free
 +deb-src http://​security.debian.org/​ jessie/​updates main contrib non-free
 +
 +# PROPOSE UPDATE REPOSITORY
 +deb http://​httpredir.debian.org/​debian jessie-proposed-updates main contrib non-free
 +deb-src http://​httpredir.debian.org/​debian jessie-proposed-updates main contrib non-free
 +</​sxh>​
 +
 +Now we need to update the repositories
 +<sxh bash>
 +apt-get update
 +</​sxh>​
 +
 +Now we need to install the Nginx and the git
 +<sxh bash>
 +apt-get install curl vim git-core nginx -y
 +</​sxh>​
 +
 +Now let's create a user that will be used to deploy the application
 +<sxh bash>
 +useradd -m deploy -s /bin/bash
 +</​sxh>​
 +
 +Now let's set up a password to the new user
 +<sxh bash>
 +passwd deploy
 +</​sxh>​
 +
 +===== Configuring Nginx =====
 +
 +Let's configure the Nginx with some basic configuration to work without any problem
 +
 +Now let's create a backup of the nginx configuration file.
 +<sxh bash>
 +cp -Rfa /​etc/​nginx/​nginx.conf /​etc/​nginx/​nginx.conf.bkp
 +</​sxh>​
 +
 +Now let's create our configuration as follows.
 +<sxh nginx>
 +vim /​etc/​nginx/​nginx.conf
 +#/​etc/​nginx/​nginx.conf
 +## User that the server runs as
 +user www-data;
 +## how many nginx instances actually run
 +worker_processes 4;
 +## Where it stores the process ID of the master process.
 +pid /​run/​nginx.pid;​
 +
 +## defines how the daemon incoming requests at the system level
 +events {
 +        ## how many connections a sinble worker thread is allowed to process
 +        worker_connections 768;
 +        ## keep accepting connections even though the server hasn't finished handeling incoming connections.
 +        # multi_accept on;
 +}
 +
 +## This is where most of your tuning will take place
 +http {
 +        ## GLOBAL
 +        ## Enabling this will increase the speed that nginx can cache, and retreive from cache
 +        sendfile on;
 +        ## This option causes nginx to attempt to send it's HTTP response headers in one packet.
 +        tcp_nopush on;
 +        ## This disables a buffer that when used with keep-alive connections,​ can slow things down
 +        tcp_nodelay on;
 +        ## Defines the maximum time between keepalive requests from client browsers.
 +        keepalive_timeout 65;
 +        ## Defines the maximum size of hash tables. This directly influences cache performance. Higher numbers use more memory, and offer potentially higher performance.
 +        types_hash_max_size 2048;
 +        ## Sets the maximum allowed size of the client request body, specified in the “Content-Length” request header field.
 +        client_max_body_size 20M;
 +        ## Sets buffer size for reading client request body.
 +        client_body_buffer_size 128k;
 +        ## Enables or disables emitting nginx version in error messages and in the “Server” response header field.
 +        server_tokens off;
 +        ## Sets the bucket size for the server names hash tables.
 +        # server_names_hash_bucket_size 64;
 +        ## Enables or disables the use of the primary server name, specified by the server_name directive, in redirects issued by nginx.
 +        # server_name_in_redirect off;
 +        ## Includes mime.types configuration file
 +        include /​etc/​nginx/​mime.types;​
 +        ## Defines the default MIME type of a response. Mapping of file name extensions to MIME types can be set with the types directive.
 +        default_type application/​octet-stream;​
 +
 +        ## Logging Settings
 +        access_log /​var/​log/​nginx/​access.log combined;
 +        error_log /​var/​log/​nginx/​error.log;​
 +
 +        ## Gzip Settings
 +        ## Enables or disables gzipping of responses. ​
 +        gzip on;
 +        ## Disables gzipping of responses for requests with “User-Agent” header fields matching any of the specified regular expressions.
 +        gzip_disable "​msie6";​
 +        ## Enables or disables inserting the “Vary: Accept-Encoding” response header field if the directives gzip, gzip_static,​ or gunzip are active
 +        gzip_vary on;
 +        ## Enables or disables gzipping of responses for proxied requests depending on the request and response.
 +        gzip_proxied any;
 +        ## Sets a gzip compression level of a response. Acceptable values are in the range from 1 to 9. 
 +        gzip_comp_level 6;
 +        ## Sets the number and size of buffers used to compress a response. By default, the buffer size is equal to one memory page.
 +        gzip_buffers 16 8k;
 +        ## Sets the minimum HTTP version of a request required to compress a response.
 +        gzip_http_version 1.1;
 +        ##  Enables gzipping of responses for the specified MIME types in addition to “text/​html”.
 +        gzip_types text/plain text/css application/​json application/​x-javascript text/xml application/​xml application/​xml+rss text/​javascript;​
 +
 +
 +        ## Virtual Host Configs
 +        include /​etc/​nginx/​conf.d/​*.conf;​
 +        include /​etc/​nginx/​sites-enabled/​*;​
 +}
 +</​sxh>​
 +
 +Now we need to disable the default virtual Host 
 +<sxh bash>
 +unlink /​etc/​nginx/​sites-enabled/​default
 +</​sxh>​
 +===== Installing the MySQL Server =====
 +
 +Now let's update the repositories
 +<sxh bash>
 +apt-get update
 +</​sxh>​
 +
 +Now let's install the MySQL
 +<sxh bash>
 +apt-get install mysql-server mysql-client libmysqlclient-dev libmysql++-dev libmysqld-dev -y
 +</​sxh>​
 +
 +**Note:** You will be asked about the root password, so set it up.
 +
 +Now let's create a database and an user to administrate the database
 +
 +Let's access the MySQL
 +<sxh bash>
 +mysql -u root -p
 +Enter password:
 +Welcome to the MySQL monitor. ​ Commands end with ; or \g.
 +Your MySQL connection id is 37
 +Server version: 5.5.49-0+deb8u1 (Debian)
 +
 +Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 +
 +Oracle is a registered trademark of Oracle Corporation and/or its
 +affiliates. Other names may be trademarks of their respective
 +owners.
 +
 +Type '​help;'​ or '​\h'​ for help. Type '​\c'​ to clear the current input statement.
 +
 +mysql>
 +</​sxh>​
 +
 +Now we need to create the database
 +<sxh sql>
 +CREATE DATABASE deploy_production;​
 +</​sxh>​
 +
 +Now we need to give the permission to the database ​
 +<sxh sql>
 +GRANT ALL PRIVILEGES ON deploy_production.* TO deploy@'​localhost'​ IDENTIFIED BY '​deploy_password';​
 +</​sxh>​
 +
 +Now let's logout from the MySQL
 +<sxh bash>
 +\q
 +</​sxh>​
 +
 +Now let's test the connection
 +<sxh bash>
 +mysql -u deploy -h localhost -p deploy_production
 +Enter password:
 +Welcome to the MySQL monitor. ​ Commands end with ; or \g.
 +Your MySQL connection id is 42
 +Server version: 5.5.49-0+deb8u1 (Debian)
 +
 +Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 +
 +Oracle is a registered trademark of Oracle Corporation and/or its
 +affiliates. Other names may be trademarks of their respective
 +owners.
 +
 +Type '​help;'​ or '​\h'​ for help. Type '​\c'​ to clear the current input statement.
 +
 +mysql> \q
 +Bye
 +</​sxh>​
 +===== Installing the PostgreSQL Server =====
 +
 +Now let's update the repositories
 +<sxh bash>
 +apt-get update
 +</​sxh>​
 +
 +Now let's install the PostgreSQL
 +<sxh bash>
 +aptitude install postgresql-server-dev-all postgresql postgresql-client -y
 +</​sxh>​
 +
 +Now let's create a user to use the postgresql
 +
 +Let's change the user to postgres
 +<sxh bash>
 +su - postgres
 +</​sxh>​
 +
 +Now let's call the psql
 +<sxh bash>
 +psql
 +psql (9.4.8)
 +Type "​help"​ for help.
 +</​sxh>​
 +
 +Now let's create a new user
 +<sxh postgres>​
 +CREATE USER deploy PASSWORD '​deploy_password';​
 +</​sxh>​
 +
 +Now we need to create the database that will be used by the application.
 +<sxh postgres>​
 +CREATE DATABASE deploy_production with OWNER deploy;
 +</​sxh>​
 +
 +Now we can logout from the psql
 +<sxh postgres>​
 +postgres=# \q
 +</​sxh>​
 +
 +Now we can back to the root user
 +<sxh bash>
 +exit
 +</​sxh>​
 +
 +Now we can test the connection
 +<sxh bash>
 +psql -h localhost -U deploy -W -d deploy_production
 +Password for user deploy: ​
 +psql (9.4.8)
 +SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384,​ bits: 256, compression:​ off)
 +Type "​help"​ for help.
 +
 +deploy_production=>​ \q
 +</​sxh>​
 +
 +===== Installing the RVM =====
 +
 +Let's import the rvm gpg key
 +<sxh bash>
 +gpg --keyserver hkp://​keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
 +</​sxh>​
 +
 +Now let's install the rvm to manage our Rubies
 +<sxh bash;>
 +curl -sSL https://​get.rvm.io | bash -s stable
 +</​sxh>​
 +
 +Now if you have more users that will be using the rvm we need to add them into the rvm's group
 +<sxh bash>
 +gpasswd -a deploy rvm
 +</​sxh>​
 +
 +Now we need to import the environment variables
 +<sxh bash;>
 +source /​etc/​profile.d/​rvm.sh
 +</​sxh>​
 +
 +Now let's install the dependencies of the rvm
 +<sxh bash>
 +rvm requirements
 +</​sxh>​
 +
 +Now we need to install the ruby 
 +<sxh bash>
 +rvm install 2.3.0
 +</​sxh>​
 +
 +Now we need to set as the default
 +<sxh bash>
 +rvm use 2.3.0 --default
 +</​sxh>​
 +
 +Now we need to install the rails and the bundler
 +<sxh bash>
 +gem install rails -V --no-ri --no-rdoc
 +gem install bundler -V --no-ri --no-rdoc
 +</​sxh>​
 +
 +Three flags were used:
 +  * <​nowiki>​-V</​nowiki>​ (Verbose Output): Prints detailed information about Gem installation
 +  * <​nowiki>​--no-ri</​nowiki>​ - (Skips Ri Documentation):​ Doesn'​t install Ri Docs, saving space and making installation fast
 +  * <​nowiki>​--no-rdoc</​nowiki>​ - (Skips RDocs): Doesn'​t install RDocs, saving space and speeding up installation
 +
 +**Note:** You can also install a specific version of Rails according to your requirements by using the <​nowiki>​-v</​nowiki>​ flag:
 +
 +<sxh bash;>
 +gem install rails -v '​4.2.0'​ -V --no-ri --no-rdoc
 +</​sxh>​
 +
 +Now let's get rid of some warnings that will be generate by the rvm about the ruby version
 +<sxh bash>
 +rvm rvmrc warning ignore allGemfiles
 +</​sxh>​
 +===== Setting up SSH Keys  =====
 +
 +**Note:** This process needs to be configure in both machines in the server that will host the Rails app and in the client machine the developer uses to work with the git that will used to update the sources.
 +
 +Since we want to set up smooth deployments,​ we'll be using SSH Keys for authorization. First shake hands with GitHub, Bitbucket, or any other Git Remote where the codebase for your Rails app is hosted:
 +<sxh bash>
 +ssh -T git@github.com
 +ssh -T git@bitbucket.org
 +</​sxh>​
 +
 +Don't worry if you get a Permission denied (publickey) message. Now, generate a SSH key (a Public/​Private Key Pair) for your server:
 +<sxh bash>
 +ssh-keygen -t rsa 
 +ssh-keygen -t dsa
 +</​sxh>​
 +
 +Add the newly created public key (~/​.ssh/​id_rsa.pub) to your repository'​s deployment keys:
 +  * [[https://​developer.github.com/​guides/​managing-deploy-keys/​|Instructions for Github]]
 +  * [[https://​confluence.atlassian.com/​display/​BITBUCKET/​Use+deployment+keys|Instructions for Bitbucket]]
 +
 +If all the steps were completed correctly, you should now be able to clone your git repository (over the SSH Protocol, not HTTP) without entering your password:
 +
 +<sxh bash>
 +git clone git@example.com:​username/​appname.git
 +</​sxh>​
 +
 +If you need a sample app for testing, you can fork the following test app specifically created for this tutorial: [[https://​github.com/​douglasqsantos/​dqs-rails-base|Sample App written in Ruby on Rails  on GitHub]]
 +
 +The git clone command will create a directory with the same name as your app. For example, a directory named dqs-rails-base will be created.
 +
 +We are cloning only to check if our deployment keys are working, we don't need to clone or pull our repository every time we push new changes. We'll let Capistrano handle all that for us. You can now delete this cloned directory if you want to.
 +
 +Open a terminal on your local machine. If you don't have a SSH Key for your local computer, create one for it as well. In your local terminal session:
 +<sxh bahs>
 +ssh-keygen -t rsa 
 +</​sxh>​
 +
 +Add your local SSH Key to your Debian Jessie Authorized Keys file (**remember to replace the port number with your customized port number**):
 +<sxh bash>
 +cat ~/​.ssh/​id_rsa.pub | ssh -p your_port_num deploy@your_server_ip 'cat >> ~/​.ssh/​authorized_keys'​
 +</​sxh>​
 +
 +Now we need to add private key identities to the authentication agent
 +<sxh bash>
 +ssh-add ~/​.ssh/​id_dsa
 +ssh-add ~/​.ssh/​id_rsa
 +</​sxh>​
 +
 +
 +Now let's clone a project to use as test
 +<sxh bash>
 +git clone https://​github.com/​douglasqsantos/​dqs-rails-base.git
 +</​sxh>​
 +
 +Now let's access the project
 +<sxh bash>
 +cd dqs-rails-base/​
 +</​sxh>​
 +
 +===== Adding Deployment Configurations in the Rails App =====
 +
 +On your local machine, create configuration files for Nginx and Capistrano in your Rails application. Start by adding these lines to the Gemfile in the Rails App:
 +<sxh ruby>
 +vim Gemfile
 +ruby '​2.3.0'​
 +[...]
 +group :​development do
 +  # Access an IRB console on exception pages or by using <%= console %> in views
 +  gem '​web-console',​ '~> 2.0'
 +
 +  # Spring speeds up development by keeping your application running in the background. Read more: https://​github.com/​rails/​spring
 +  gem '​spring'​
 +  gem '​capistrano', ​        ​require:​ false
 +  gem '​capistrano-rvm', ​    ​require:​ false
 +  gem '​capistrano-rails', ​  ​require:​ false
 +  gem '​capistrano-bundler',​ require: false
 +  gem '​capistrano3-puma', ​  ​require:​ false
 +end
 +
 +gem '​puma'​
 +</​sxh>​
 +
 +Use bundler to install the gems you just specified in your Gemfile. Enter the following command to bundle your Rails app:
 +<sxh bash>
 +bundle install
 +</​sxh>​
 +
 +Now we need to create the production key to run the application
 +<sxh yaml>
 +rake secret
 +46d1feba0000226fdf16e9bd94739c7a09fd24401ff8ba33945161fe613a0211459a9167b6267eb796b66167ddf187f4a40a44460a46a9adfeecd875161ea5ac
 +</​sxh>​
 +
 +Now we need to pass it into config/​secrets.yml
 +<sxh yaml>
 +vim config/​secrets.yml
 +[...]
 +production:
 +  secret_key_base:​ b98f316c6a54b6c76ab01859945b78aef9ec0e051e55a30b530957441420057ab3e42fcff7fa308a488a689ee61f10e10ccc07040b190d839f96c7803f50e078
 +</​sxh>​
 +
 +After bundling, run the following command to configure Capistrano:
 +<sxh bash>
 +cap install
 +</​sxh>​
 +
 +This will create:
 +  * Capfile in the root directory of your Rails app
 +  * deploy.rb file in the config directory
 +  * deploy directory in the config directory
 +
 +Replace the contents of your Capfile with the following:
 +<sxh ruby>
 +vim Capfile
 +# Load DSL and Setup Up Stages
 +require '​capistrano/​setup'​
 +require '​capistrano/​deploy'​
 +
 +require '​capistrano/​rails'​
 +require '​capistrano/​bundler'​
 +require '​capistrano/​rvm'​
 +require '​capistrano/​puma'​
 +
 +# Loads custom tasks from `lib/​capistrano/​tasks'​ if you have any defined.
 +Dir.glob('​lib/​capistrano/​tasks/​*.rake'​).each { |r| import r }
 +</​sxh>​
 +
 +
 +This Capfile loads some pre-defined tasks in to your Capistrano configuration files to make your deployments hassle-free,​ such as automatically:​
 +
 +  * Selecting the correct Ruby
 +  * Pre-compiling Assets
 +  * Cloning your Git repository to the correct location
 +  * Installing new dependencies when your Gemfile has changed
 +
 +Replace the contents of config/​deploy.rb with the following, updating fields marked as **change_me** with your app and Debian Jessie parameters: ​
 +<sxh ruby>
 +vim config/​deploy.rb
 +# Change these
 +server '​change_me',​ port: change_me, roles: [:web, :app, :db], primary: true
 +
 +set :​repo_url, ​       '​git@github.com:​change_me/​dqs-rails-base.git'​
 +set :​application, ​    '​dqs-rails-base'​
 +set :​user, ​           '​deploy'​
 +set :​puma_threads, ​   [4, 16]
 +set :​puma_workers, ​   0
 +
 +# Don't change these unless you know what you're doing
 +set :pty,             true
 +set :​use_sudo, ​       false
 +set :​stage, ​          :​production
 +set :​deploy_via, ​     :​remote_cache
 +set :​deploy_to, ​      "/​home/#​{fetch(:​user)}/​apps/#​{fetch(:​application)}"​
 +set :​puma_bind, ​      "​unix://#​{shared_path}/​tmp/​sockets/#​{fetch(:​application)}-puma.sock"​
 +set :​puma_state, ​     "#​{shared_path}/​tmp/​pids/​puma.state"​
 +set :​puma_pid, ​       "#​{shared_path}/​tmp/​pids/​puma.pid"​
 +set :​puma_access_log,​ "#​{release_path}/​log/​puma.error.log"​
 +set :​puma_error_log, ​ "#​{release_path}/​log/​puma.access.log"​
 +set :​ssh_options, ​    { forward_agent:​ true, port: 22022, ​ user: fetch(:​user),​ keys: %w(~/​.ssh/​id_rsa.pub) }
 +set :​puma_preload_app,​ true
 +set :​puma_worker_timeout,​ nil
 +set :​puma_init_active_record,​ true  # Change to false when not using ActiveRecord
 +
 +## Defaults:
 +# set :scm,           :git
 +# set :​branch, ​       :master
 +# set :​format, ​       :pretty
 +# set :​log_level, ​    :​debug
 +# set :​keep_releases,​ 5
 +
 +## Linked Files & Directories (Default None):
 +# set :​linked_files,​ %w{config/​database.yml}
 +# set :​linked_dirs, ​ %w{bin log tmp/pids tmp/cache tmp/sockets vendor/​bundle public/​system}
 +
 +namespace :puma do
 +  desc '​Create Directories for Puma Pids and Socket'​
 +  task :make_dirs do
 +    on roles(:app) do
 +      execute "mkdir #​{shared_path}/​tmp/​sockets -p"
 +      execute "mkdir #​{shared_path}/​tmp/​pids -p"
 +    end
 +  end
 +
 +  before :start, :make_dirs
 +end
 +
 +namespace :deploy do
 +  desc "Make sure local git is in sync with remote."​
 +  task :​check_revision do
 +    on roles(:app) do
 +      unless `git rev-parse HEAD` == `git rev-parse origin/​master`
 +        puts "​WARNING:​ HEAD is not the same as origin/​master"​
 +        puts "Run `git push` to sync changes."​
 +        exit
 +      end
 +    end
 +  end
 +
 +  desc '​Initial Deploy'​
 +  task :initial do
 +    on roles(:app) do
 +      before '​deploy:​restart',​ '​puma:​start'​
 +      invoke '​deploy'​
 +    end
 +  end
 +
 +  desc '​Restart application'​
 +  task :restart do
 +    on roles(:​app),​ in: :sequence, wait: 5 do
 +      invoke '​puma:​restart'​
 +    end
 +  end
 +
 +  desc '​Seeding Database'​
 +  task :seed do
 +   puts "\n=== Seeding Database ===\n"
 +   on primary :db do
 +    within current_path do
 +      with rails_env: fetch(:​stage) do
 +        execute :rake, '​db:​seed'​
 +      end
 +    end
 +   end
 +  end
 +
 +  desc '​Migrating Down Database'​
 +  task :​migrate_down do
 +   puts "\n=== Migrating Up Database ===\n"
 +   on primary :db do
 +    within current_path do
 +      with rails_env: fetch(:​stage) do
 +        execute :rake, '​db:​migrate VERSION=0 --trace'​
 +      end
 +    end
 +   end
 +  end
 +
 +  desc '​Migrating Up Database'​
 +  task :migrate_up do
 +   puts "\n=== Migrating Up Database ===\n"
 +   on primary :db do
 +    within current_path do
 +      with rails_env: fetch(:​stage) do
 +        execute :rake, '​db:​migrate --trace'​
 +      end
 +    end
 +   end
 +  end
 +
 +  before :​starting, ​    :​check_revision
 +  after  :​finishing, ​   :​compile_assets
 +  after  :​finishing, ​   :cleanup
 +  after  :​finishing, ​   :restart
 +end
 +
 +# ps aux | grep puma    # Get puma pid
 +# kill -s SIGUSR2 pid   # Restart puma
 +# kill -s SIGTERM pid   # Stop puma
 +</​sxh>​
 +
 +This deploy.rb file contains some sane defaults that work out-of-the-box to help you manage your app releases and automatically perform some tasks when you make a deployment:
 +  * Uses production as the default environment for your Rails app
 +  * Automatically manages multiple releases of your app
 +  * Uses optimized SSH options
 +  * Checks if your git remotes are up to date
 +  * Manages your app's logs
 +  * Preloads the app in memory when managing Puma workers
 +  * Starts (or restarts) the Puma server after finishing a deployment
 +  * Opens a socket to the Puma server at a specific location in your release
 +
 +You can change all options depending on your requirements. Now, Nginx needs to be configured. Create config/​nginx.conf in your Rails project directory, and add the following to it (again, replacing with your parameters):​
 +<sxh nginx>
 +vim config/​nginx.conf
 +#​config/​nginx.conf
 +upstream puma {
 +  server unix:///​home/​deploy/​apps/​dqs-rails-base/​shared/​tmp/​sockets/​appname-puma.sock;​
 +}
 +
 +# Default server configuration
 +server {
 +
 +  ## Sets the address and port for IP, or the path for a UNIX-domain socket on which the server will accept requests.
 +  listen 80;
 +  ​
 +  ## Sets names of a virtual server
 +  server_name rails.douglasqsantos.com.br;​
 +
 +  ## Enables or disables emitting nginx version in error messages and in the “Server” response header field.
 +  server_tokens off;
 +  ​
 +  ## Sets the root directory for requests
 +  root /​home/​deploy/​apps/​dqs-rails-base/​current/​public;​
 +  ​
 +  ## Logging
 +  access_log /​home/​deploy/​apps/​dqs-rails-base/​current/​log/​nginx.access.log;​
 +  error_log /​home/​deploy/​apps/​dqs-rails-base/​current/​log/​nginx.error.log info;
 +
 +  ## Sets configuration for assets
 +  location ^~ /assets/ {
 +    gzip_static on;
 +    expires max;
 +    add_header Cache-Control public;
 +  }
 +
 +  ## Sets the configuration for all files and the puma web server
 +  try_files $uri/​index.html $uri @puma;
 +  location @puma {
 +    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;​
 +    proxy_set_header Host $http_host;
 +    proxy_redirect off;
 +
 +    proxy_pass http://​puma;​
 +  }
 +
 +  ## Default error pages
 +  error_page 500 502 503 504 /500.html;
 +  ​
 +  ## Sets configuration for max body size as 10MB
 +  client_max_body_size 10M;
 +  ​
 +  ## Sets How long an idle keepalive connection remains open.
 +  keepalive_timeout 10;
 +}
 +</​sxh> ​
 +
 +Like the previous file, this nginx.conf contains defaults that work out-of-the-box with the configurations in your deploy.rb file. This listens for traffic on port 80 and passes on the request to your Puma socket, writes nginx logs to the '​current'​ release of your app, compresses all assets and caches them in the browser with maximum expiry, serves the HTML pages in the public folder as static files, and sets default maximum Client Body Size and Request Timeout values. ​
 +
 +
 +===== Deploying your Rails Application =====
 +
 +If you are using your own Rails app, commit the changes you just made, and push them to remote from your Local Machine:
 +<sxh bash>
 +git add -A
 +git commit -m "Set up Puma, Nginx & Capistrano"​
 +git push origin master
 +</​sxh>​
 +
 +Note: If this is the first time using GitHub from this system, you might have to issue the following commands with your GitHub username and email address:
 +<sxh bash>
 +git config --global user.name 'Your Name'
 +git config --global user.email you@example.com
 +</​sxh>​
 +
 +Again, from your local machine, make your first deployment:
 +<sxh bash>
 +cap production deploy:​initial
 +</​sxh>​
 +
 +This will push your Rails app to the Debian Jessie, install all required gems for your app, and start the Puma web server. This may take anywhere between 5-15 minutes depending on the number of Gems your app uses. You will see debug messages as this process occurs.
 +
 +If you need to run a seed of the database for example we can use the following command
 +<sxh bash>
 +cap production deploy:seed
 +</​sxh>​
 +
 +If you need to run a migration to a version 0
 +<sxh bash>
 +cap production deploy:​migrate_down
 +</​sxh>​
 +
 +If you need to run a migration
 +<sxh bash>
 +cap production deploy:​migrate_up
 +</​sxh>​
 +
 +Another good feature that we need to run sometimes is restart the puma server
 +<sxh bash>
 +cap production deploy:​restart
 +</​sxh>​
 +
 +If everything goes smoothly, we're now ready to connect your Puma web server to the Nginx reverse proxy.
 +
 +On the Debian Jessie, Symlink the nginx.conf to the sites-enabled directory:
 +<sxh bash>
 +ln -nfs "/​home/​deploy/​apps/​dqs-rails-base/​current/​config/​nginx.conf"​ "/​etc/​nginx/​sites-enabled/​dqs-rails-base"​
 +</​sxh>​
 +
 +Restart the Nginx service:
 +<sxh bash>
 +systemctl restart nginx
 +</​sxh>​
 +
 +You should now be able to point your web browser to your server IP and see your Rails app in action!
 +
 +===== Normal Deployments =====
 +
 +Whenever you make changes to your app and want to deploy a new release to the server, commit the changes, push to your git remote like usual, and run the deploy command:
 +<sxh bash>
 +git add -A
 +git commit -m "​Deploy Message"​
 +git push origin master
 +cap production deploy
 +</​sxh>​
 +
 +Note: If you make changes to your config/​nginx.conf file, you'll have to reload or restart your Nginx service on the server after deploying your app:
 +<sxh bash>
 +service nginx restart
 +</​sxh>​
 +
 +
 +===== Configuring the SystemD to handle the Puma =====
 +
 +The idea here is when we restart the server machine for some reason we will get the puma server working in the boot time with the system and everything will work properly.
 +
 +Let's create the service
 +<sxh bash>
 +vim /​etc/​systemd/​system/​puma.service
 +[Unit]
 +Description=Puma Control
 +After=network.target auditd.service
 +
 +[Service]
 +Type=oneshot
 +RemainAfterExit=yes
 +ExecStart=/​etc/​puma/​puma-start
 +ExecStop=/​etc/​puma/​puma-stop
 +
 +[Install]
 +WantedBy=multi-user.target
 +</​sxh>​
 +
 +Now we need to create the directory that will store the scripts
 +<sxh bash>
 +mkdir /etc/puma
 +</​sxh>​
 +
 +Now let's create the script that will start the service
 +<sxh bash>
 +vim /​etc/​puma/​puma-start
 +#!/bin/bash
 +
 +cd /​home/​deploy/​apps/​dqs-rails-base/​current && ( export RACK_ENV="​production"​ ; /​usr/​local/​rvm/​bin/​rvm default do bundle exec puma -C /​home/​deploy/​apps/​dqs-rails-base/​shared/​puma.rb --daemon )
 +
 +</​sxh>​
 +
 +Now let's give the permission to the script
 +<sxh bash>
 +chmod +x /​etc/​puma/​puma-start
 +</​sxh>​
 +
 +Now let's create the script that will stop the service
 +<sxh bash>
 +vim /​etc/​puma/​puma-stop
 +#!/bin/bash
 +
 +cd /​home/​deploy/​apps/​dqs-rails-base/​current && ( export RACK_ENV="​production"​ ; /​usr/​local/​rvm/​bin/​rvm default do bundle exec pumactl -S /​home/​deploy/​apps/​dqs-rails-base/​shared/​tmp/​pids/​puma.state stop )
 +</​sxh>​
 +
 +Now let's give the permission to the script
 +<sxh bash>
 +chmod +x /​etc/​puma/​puma-stop
 +</​sxh>​
 +
 +Now let's enable the service
 +<sxh bash>
 +systemctl enable puma
 +</​sxh>​
 +
 +Now we can handle the puma service with the systemd
 +<sxh bash>
 +systemctl start puma
 +systemctl stop puma
 +systemctl restart puma
 +systemctl status puma
 +</​sxh>​
 +
 +Now we can restart the server and check if everything is working properly.
 +===== Enabling the HTTPS =====
 +
 +Let's access the root directory of the application on the local machine
 +<sxh bash>
 +cd ~/​dev/​dqs-rails-base
 +</​sxh>​
 +
 +Let's create the directory to store the certificates
 +<sxh bash>
 +mkdir config/ssl
 +</​sxh>​
 +
 +Let's access the directory
 +<sxh bash>
 +cd config/ssl
 +</​sxh>​
 +
 +Let's create the certificate key
 +<sxh bash>
 +openssl genrsa -des3 -out server.key 1024
 +Generating RSA private key, 1024 bit long modulus
 +..............................++++++
 +.++++++
 +e is 65537 (0x10001)
 +Enter pass phrase for server.key: #PASSWORD
 +Verifying - Enter pass phrase for server.key: #PASSWORD
 +</​sxh>​
 +
 +Now we need to create the certificate sign request
 +<sxh bash>
 +openssl req -new -key server.key -out server.csr
 +Enter pass phrase for server.key: #PASSWORD
 +You are about to be asked to enter information that will be incorporated
 +into your certificate request.
 +What you are about to enter is what is called a Distinguished Name or a DN.
 +There are quite a few fields but you can leave some blank
 +For some fields there will be a default value,
 +If you enter '​.',​ the field will be left blank.
 +-----
 +Country Name (2 letter code) [AU]:BR
 +State or Province Name (full name) [Some-State]:​Parana
 +Locality Name (eg, city) []:Curitiba
 +Organization Name (eg, company) [Internet Widgits Pty Ltd]:DQS
 +Organizational Unit Name (eg, section) []:IT
 +Common Name (e.g. server FQDN or YOUR name) []:​rails.douglasqsantos.com.br
 +Email Address []:​douglas.q.santos@gmail.com
 +
 +Please enter the following '​extra'​ attributes
 +to be sent with your certificate request
 +A challenge password []:
 +An optional company name []:DQS
 +</​sxh>​
 +
 +Now we need to change the certificate permissions
 +<sxh bash>
 +chmod 0400 server.*
 +cp server.key server.key.orig
 +</​sxh>​
 +
 +Now we need to auto sign the certificate
 +<sxh bash>
 +openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt
 +Signature ok
 +subject=/​C=BR/​ST=Parana/​L=Curitiba/​O=DQS/​OU=IT/​CN=rails.douglasqsantos.com.br/​emailAddress=douglas.q.santos@gmail.com
 +Getting Private key
 +Enter pass phrase for server.key: #PASSWORD
 +</​sxh>​
 +
 +Now let's remove the password from our certificate,​ otherwise we need to put the password every nginx start.
 +<sxh bash>
 +openssl rsa -in server.key.orig -out server.key
 +Enter pass phrase for server.key.orig:​ #PASSWORD
 +writing RSA key
 +</​sxh>​
 +
 +Let's change the certificates permissions.
 +<sxh bash>
 +chmod 0400 ~/​dev/​dqs-rails-base/​config/​ssl/​* ​
 +</​sxh>​
 +
 +Now let's create a backup of the nginx configuration
 +<sxh bash>
 +cp -Rfa ~/​dev/​dqs-rails-base/​config/​nginx.conf{,​.bkp}
 +</​sxh>​
 +
 +Now let's configure the nginx to use the ssl
 +<sxh nginx>
 +vim /​var/​www/​html/​dqs-rails-base/​config/​nginx.conf
 +# Puma configuration
 +upstream puma {
 +  server unix:///​home/​deploy/​apps/​mygym/​shared/​tmp/​sockets/​mygym-puma.sock;​
 +}
 +
 +# Default server configuration
 +server {
 +  ## Sets the address and port for IP, or the path for a UNIX-domain socket on which the server will accept requests.
 +  listen 443;
 +  ​
 +  ## Sets names of a virtual server
 +  server_name rails.douglasqsantos.com.br;​
 +  ​
 +  ## Enables or disables emitting nginx version in error messages and in the “Server” response header field.
 +  server_tokens off;
 +  ​
 +  ## Enables the HTTPS protocol for the given virtual server.
 +  ssl on;
 +  ​
 +  ## Specifies a file with the certificate in the PEM format for the given virtual server.
 +  # if you are using an valid certificate need to do the following process to use it.
 +  # cat server_name.crt CertCA.crt >> server.crt
 +  ssl_certificate /​home/​deploy/​apps/​dqs-rails-base/​current/​config/​ssl/​server.crt;​
 +  ​
 +  ## Specifies a file with the secret key in the PEM format for the given virtual server.
 +  ssl_certificate_key /​home/​deploy/​apps/​dqs-rails-base/​current/​config/​ssl/​server.key;​
 +
 +  ### Enable the timout of the ssl session to 5 minutes
 +  ssl_session_timeout ​ 5m;
 +  ​
 +  ## Specifies the enabled protocols
 +  ssl_protocols ​ SSLv2 SSLv3 TLSv1;
 +  ​
 +  ## Specifies the enabled ciphers
 +  ssl_ciphers ​ HIGH:​!aNULL:​!MD5;​
 +  ​
 +  ## Specifies the enabled ciphers
 +  ssl_prefer_server_ciphers ​  on;
 +
 +  ## Sets the root directory for requests
 +  root /​home/​deploy/​apps/​dqs-rails-base/​current/​public;​
 +  ​
 +  ## Logging
 +  access_log /​home/​deploy/​apps/​dqs-rails-base/​current/​log/​nginx.access.log;​
 +  error_log /​home/​deploy/​apps/​dqs-rails-base/​current/​log/​nginx.error.log info;
 +
 +  ## Sets configuration for assets
 +  location ^~ /assets/ {
 +    gzip_static on;
 +    expires max;
 +    add_header Cache-Control public;
 +  }
 +
 +  ## Sets the configuration for all files and the puma web server
 +  try_files $uri/​index.html $uri @puma;
 +  location @puma {
 +    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;​
 +    proxy_set_header Host $http_host;
 +    proxy_set_header X-Forwarded-Proto https;
 +    proxy_redirect off;
 +    proxy_pass http://​puma;​
 +  }
 +
 +  ## Default error pages
 +  error_page 500 502 503 504 /500.html;
 +  ​
 +  ## Sets configuration for max body size as 10MB
 +  client_max_body_size 10M;
 +  ​
 +  ## How long an idle keepalive connection remains open.
 +  keepalive_timeout 10;
 +}
 +</​sxh>​
 +
 +Now After change the file needs to commit and push to the repo, after that we need to deploy to the server
 +<sxh bash>
 +cap production deploy
 +</​sxh>​
 +
 +Now we need to restart the Nginx
 +<sxh bash>
 +systemctl restart nginx
 +</​sxh>​
 +
 +Now we can access https://​ip_server or https://​rails.douglasqsantos.com.br
 +
 +===== Conclusion =====
 +
 +Okay, so by now you would be running a Rails app on your Debian Jessie with Puma as your Web Server as well as Nginx and Capistrano configured with basic settings. ​
 +
 +You should now take a look at other docs that can help you optimize your configurations to get the maximum out of your Rails application:​
 +  - [[https://​github.com/​puma/​puma/​|Puma Configurations]]
 +  - [[https://​github.com/​seuros/​capistrano-puma|Puma DSL in Capistrano]]
 +  - [[https://​github.com/​stve/​capistrano-local-precompile|Local Asset Pre-compilation in Capistrano]]
 +  - [[https://​github.com/​schneems/​puma_worker_killer|Automatically restart Puma workers based on RAM]]
 +  - [[https://​blog.martinfjordvald.com/​2011/​04/​optimizing-nginx-for-high-traffic-loads/​|Optimizing Nginx for High Traffic Loads]]
 +
 +
 +====== References ======
 +  - http://​nginx.org/​
 +  - http://​nginx.org/​en/​docs/​ -> ** Modules reference**
 +  - http://​nginx.com/​resources/​admin-guide/​restricting-access/​
 +  - http://​nginx.com/​resources/​admin-guide/​
 +  - http://​wiki.nginx.org/​NginxHttpCoreModule
 +  - http://​wiki.nginx.org/​Pitfalls
 +  - http://​nginx.org/​en/​docs/​http/​ngx_http_core_module.html
 +  - http://​wiki.nginx.org/​Main
 +  - http://​wiki.nginx.org/​Install
 +  - http://​wiki.nginx.org/​Configuration
 +  - https://​www.nginx.com/​blog/​tuning-nginx/​
 +  - https://​www.digitalocean.com/​community/​tutorials/​deploying-a-rails-app-on-ubuntu-14-04-with-capistrano-nginx-and-puma