Installing and Configuring Nginx with Puma + MySQL for Rails on Debian Jessie
Hey guys, here I will show you how to configure the Nginx with Puma and MySQL to host a Rails application.
I will consider that you have a minimal Debian Jessie installation, so we need to install some dependencies and prepare the system.
Let's configure the repositories
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
Now we need to update the repositories
apt-get update
Now we need to install the Nginx and the git
apt-get install curl vim git-core nginx -y
Installing the MySQL Server
Now let's update the repositories
apt-get update
Now let's install the MySQL
apt-get install mysql-server mysql-client libmysqlclient-dev libmysql++-dev libmysqld-dev -y
Note: You will be asked about the root password, so set it up.
Installing the RVM
Let's import the rvm gpg key
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
Now let's install the rvm to manage our Rubies
curl -sSL https://get.rvm.io | bash -s stable
Now if you have more users that will be using the rvm we need to add them into the rvm's group
gpasswd -a douglas rvm
Now we need to import the environment variables
source /etc/profile.d/rvm.sh
Now let's install the dependencies of the rvm
rvm requirements
Now we need to install the ruby
rvm install 2.3.0
Now we need to set as the default
rvm use 2.3.0 --default
Now we need to install the rails and the bundler
gem install rails -V --no-ri --no-rdoc gem install bundler -V --no-ri --no-rdoc
Three flags were used:
- -V (Verbose Output): Prints detailed information about Gem installation
- --no-ri - (Skips Ri Documentation): Doesn't install Ri Docs, saving space and making installation fast
- --no-rdoc - (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 -v flag:
gem install rails -v '4.2.0' -V --no-ri --no-rdoc
Now let's clone a project to use as test
cd /var/www/html && git clone https://github.com/douglasqsantos/dqs-rails-base.git
Now let's access the project
cd dqs-rails-base/
Now we need to add the puma into the Gemfile and change the sqlite3 to MySQL
vim Gemfile ruby '2.3.0' [...] # Use sqlite3 as the database for Active Record #gem 'sqlite3' gem 'mysql2' [...] # Use ActiveModel has_secure_password gem 'bcrypt', '~> 3.1.7' # app server gem 'puma' [...]
Now let's run the bundler, it will take a little while.
bundle install
Now we need to create the production key to run the application
rake secret 46d1feba0000226fdf16e9bd94739c7a09fd24401ff8ba33945161fe613a0211459a9167b6267eb796b66167ddf187f4a40a44460a46a9adfeecd875161ea5ac
Now we need to pass it into config/secrets.yml
vim config/secrets.yml [...] production: secret_key_base: b98f316c6a54b6c76ab01859945b78aef9ec0e051e55a30b530957441420057ab3e42fcff7fa308a488a689ee61f10e10ccc07040b190d839f96c7803f50e078
Now we need to compile the assets
RAILS_ENV=production rake assets:precompile
Now let's configure the database connection
vim config/database.yml default: &default adapter: mysql2 encoding: utf8 pool: 5 username: dqs_rails password: 'dqs_rails_passwd' port: 3306 development: <<: *default database: dqs_rails_base_dev test: <<: *default database: dqs_rails_base_test production: <<: *default database: dqs_rails_base_prod
Now let's create the database
mysql -u root -p CREATE DATABASE dqs-rails-base-prod; GRANT ALL PRIVILEGES ON dqs_rails_base_prod.* to dqs_rails@localhost IDENTIFIED BY 'dqs_rails_passwd'; FLUSH PRIVILEGES; quit
Now we can migrate the database
RAILS_ENV=production rake db:migrate
After migrate the database we can seed the database
RAILS_ENV=production rake db:seed --trace
Now let's get rid of some warnings that will be generate by the rvm about the ruby version
rvm rvmrc warning ignore allGemfiles
Configuring the Puma
Before configuring Puma, you should look up the number of CPU cores your server has. You can easily to that with this command:
grep -c processor /proc/cpuinfo
Now we need to configure the puma server
vim config/puma.rb # Change to match your CPU core count workers 4 # Min and Max threads per worker threads 1, 6 app_dir = File.expand_path("../..", __FILE__) shared_dir = "#{app_dir}/shared" # Default to production rails_env = ENV['RAILS_ENV'] || "production" environment rails_env # Set up socket location bind "unix://#{shared_dir}/sockets/puma.sock" # Logging stdout_redirect "#{shared_dir}/log/puma.stdout.log", "#{shared_dir}/log/puma.stderr.log", true # Set master PID and state locations pidfile "#{shared_dir}/pids/puma.pid" state_path "#{shared_dir}/pids/puma.state" activate_control_app on_worker_boot do require "active_record" ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished ActiveRecord::Base.establish_connection(YAML.load_file("#{app_dir}/config/database.yml")[rails_env]) end
Now create the directories that were referred to in the configuration file:
mkdir -p shared/pids shared/sockets shared/log
Now let's start the puma server
cd /var/www/html/dqs-rails-base && ( export RACK_ENV="production" ; /usr/local/rvm/bin/rvm default do bundle exec puma -C /var/www/html/dqs-rails-base/config/puma.rb --daemon )
To stop the puma server
cd /var/www/html/dqs-rails-base && ( export RACK_ENV="production" ; rvm all do bundle exec pumactl -S /var/www/html/dqs-rails-base/shared/pids/puma.state stop )
Configuring the Nginx
Getting the vim nginx syntax
wget -c https://raw.githubusercontent.com/douglasqsantos/easy-debian/master/nginx.vim -O /usr/share/vim/vim74/syntax/nginx.vim
Now we need to create the configuration for Nginx
vim config/nginx.conf # Puma configuration upstream puma { server unix:///var/www/html/dqs-rails-base/shared/sockets/puma.sock; } # Default server configuration server { listen 80 default_server deferred; server_name rails.douglasqsantos.com.br; server_tokens off; root /var/www/html/dqs-rails-base/public; access_log /var/www/html/dqs-rails-base/log/nginx.access.log; error_log /var/www/html/dqs-rails-base/log/nginx.error.log info; location ^~ /assets/ { gzip_static on; expires max; add_header Cache-Control public; } 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; } error_page 500 502 503 504 /500.html; client_max_body_size 10M; keepalive_timeout 10; }
Now let's remove the default site for Nginx
rm /etc/nginx/sites-enabled/default ln -nfs "/var/www/html/dqs-rails-base/config/nginx.conf" "/etc/nginx/sites-enabled/rails"
Now let's start the Puma server
cd /var/www/html/dqs-rails-base && ( export RACK_ENV="production" ; /usr/local/rvm/bin/rvm default do bundle exec puma -C /var/www/html/dqs-rails-base/config/puma.rb --daemon )
Now let's restart the Nginx Server
systemctl restart nginx
Now we can check the status of the service
systemctl status nginx
Now we can check the status of the app http://ip_server or http://rails.douglasqsantos.com.br
Now let's create a script to handle the puma service
vim /var/www/html/dqs-rails-base/bin/handle_puma.sh #!/bin/bash #------------------------------------------------------------------------- # Name: /var/www/html/dqs-rails-base/bin/handle_puma.sh # # Site: http://wiki.douglasqsantos.com.br # Autor: Douglas Quintiliano dos Santos <douglas.q.santos@gmail.com> # Management: Douglas Quintiliano dos Santos <douglas.q.santos@gmail.com> # #------------------------------------------------------------------------- # License: [MIT license](http://opensource.org/licenses/MIT) # #------------------------------------------------------------------------- ### CORES UTILIZADAS NO SCRIPT ### GREY="\033[01;30m" RED="\033[01;31m" GREEN="\033[01;32m" YELLOW="\033[01;33m" BLUE="\033[01;34m" PURPLE="\033[01;35m" CYAN="\033[01;36m" WHITE="\033[01;37m" CLOSE="\033[m" case $1 in start) echo -e "${GREEN}[ Starting Puma ]${CLOSE}" cd /var/www/html/dqs-rails-base && ( export RACK_ENV="production" ; /usr/local/rvm/bin/rvm default do bundle exec puma -C /var/www/html/dqs-rails-base/config/puma.rb --daemon ) echo -e "${GREEN}[ Puma Started ]${CLOSE}" ;; stop) echo -e "${RED}[ Stopping Puma ]${CLOSE}" cd /var/www/html/dqs-rails-base && ( export RACK_ENV="production" ; rvm all do bundle exec pumactl -S /var/www/html/dqs-rails-base/shared/pids/puma.state stop ) echo -e "${RED}[ Puma Stopped Puma ]${CLOSE}" ;; restart) echo -e "${GREEN}[ Restarting Puma ]${CLOSE}" $0 stop $0 start echo -e "${GREEN}[ Puma Restarted ]${CLOSE}" ;; *) echo -e "${RED} Valid Options: (start|stop|restart) ${CLOSE}" ;; esac
Now we need to give the correct permission to the script
chmod +x /var/www/html/dqs-rails-base/bin/handle_puma.sh
Now we can call the script such as
/var/www/html/dqs-rails-base/bin/handle_puma.sh start /var/www/html/dqs-rails-base/bin/handle_puma.sh stop /var/www/html/dqs-rails-base/bin/handle_puma.sh restart
Configuring the SystemD to handle the Puma
Let's create the service
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
Now we need to create the directory that will store the scripts
mkdir /etc/puma
Now let's create the script that will start the service
vim /etc/puma/puma-start #!/bin/bash cd /var/www/html/dqs-rails-base && ( export RACK_ENV="production" ; /usr/local/rvm/bin/rvm all do bundle exec puma -C /var/www/html/dqs-rails-base/config/puma.rb --daemon )
Now let's give the permission to the script
chmod +x /etc/puma/puma-start
Now let's create the script that will stop the service
vim /etc/puma/puma-stop #!/bin/bash cd /var/www/html/dqs-rails-base && ( export RACK_ENV="production" ; /usr/local/rvm/bin/rvm all do bundle exec pumactl -S /var/www/html/dqs-rails-base/shared/pids/puma.state stop )
Now let's give the permission to the script
chmod +x /etc/puma/puma-stop
Now let's enable the service
systemctl enable puma
Now we can handle the puma service with the systemd
systemctl start puma systemctl stop puma systemctl restart puma systemctl status puma
Now we can restart the service and check if everything is working properly.
Enabling the HTTPS
Now let's enable the https
Let's create the directory to store the certificates
mkdir /var/www/html/dqs-rails-base/config/ssl
Let's access the directory
cd /var/www/html/dqs-rails-base/config/ssl
Let's create the certificate key
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
Now we need to create the certificate sign request
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
Now we need to change the certificate permissions
chmod 0400 server.* cp server.key server.key.orig
Now we need to auto sign the certificate
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
Now let's remove the password from our certificate, otherwise we need to put the password every nginx start.
openssl rsa -in server.key.orig -out server.key Enter pass phrase for server.key.orig: #PASSWORD writing RSA key
Let's change the certificates permissions.
chmod 0400 /var/www/html/dqs-rails-base/config/ssl/*
Now let's create a backup of the nginx configuration
cp -Rfa /var/www/html/dqs-rails-base/config/nginx.conf{,.bkp}
Now let's configure the nginx to use the ssl
vim /var/www/html/dqs-rails-base/config/nginx.conf # Puma configuration upstream puma { server unix:///var/www/html/dqs-rails-base/shared/sockets/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 /var/www/html/dqs-rails-base/config/ssl/server.crt; ## Specifies a file with the secret key in the PEM format for the given virtual server. ssl_certificate_key /var/www/html/dqs-rails-base/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 /var/www/html/dqs-rails-base/public; ## Logging access_log /var/www/html/dqs-rails-base/log/nginx.access.log; error_log /var/www/html/dqs-rails-base/log/nginx.error.log info; ## Sets configuration for assets location ^~ /assets/ { gzip_static on; expires max; add_header Cache-Control public; } 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; } error_page 500 502 503 504 /500.html; client_max_body_size 10M; keepalive_timeout 10; }
Now we need to restart the Nginx
systemctl restart nginx
Now we need to restart the Puma
systemctl restart puma
Now we can access https://ip_server or https://rails.douglasqsantos.com.br
References
- http://nginx.org/en/docs/ → Modules reference