Original article on my blog: https://chienkira.github.io/blog/posts/Installing Server Running Rails App On Production Using Puma + Nginx
Puma is a compact web server built into Rails that helps developers start coding as quickly as possible. However, making it a real web server to run on production environments is not ok. In this article, I want the memo to share with you the steps to install the server so that the Rails application runs smoothly on the production environment.
Prerequisite
- OS environment is Amazon linux
- Database used is Postgres
System configuration
Puma acts as an application server for the Rails application, and Nginx will act as a reverse proxy – receiving requests and passing responses between the client and Puma. Puma and Nginx communicate with each other via sockets.
- rbenv + Ruby 2.5
- Rails 5 + Puma + Nginx
Source Image: http://codeonhill.com
Ok, ssh on the server and start the installation! ↓↓↓
1. Prepare the environment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # Cài đặt các package cơ bản # ※ Riêng cái htop thì optional, mình thích dùng htop để xem trạng thái server nên có thói quen cài nó $ sudo yum update $ sudo yum install git make gcc-c++ patch openssl-devel libyaml-devel libffi-devel libicu-devel libxml2 libxslt libxml2-devel libxslt-devel zlib-devel readline-devel postgresql-libs postgresql-devel epel-release htop $ sudo amazon-linux-extras install epel $ sudo yum install nodejs npm --enablerepo=epel |
2. Create a user
A good habit is not to use the default user / ec2-user, so we will create a new user to serve the installation and launch of the Rails application.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # Tạo user deploy $ sudo adduser deploy $ sudo passwd deploy # Cài đặt password cho user deploy $ sudo visudo # Gán quyền cho user deploy ----------------------------- # vim khởi động lên, thêm quyền bằng cách thêm dòng sau root ALL=(ALL) ALL deploy ALL=(ALL) ALL # ← thêm dòng này ----------------------------- $ sudo su - deploy # Chuyển qua user deploy # Cài đặt timezone $ sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime # Cài đặt alias ll, hữu dụng và dễ đọc file size hơn lệnh ls $ echo 'alias ll="ls -lh --color=auto"' >> ~/.bash_profile $ source ~/.bash_profile |
3. Install rbenv and Ruby
Use rbenv to manage versions of ruby.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # Cài đặt rbenv $ sudo su - deploy $ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source ~/.bash_profile $ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build $ rbenv rehash # Cài đặt ruby 2.5 $ rbenv install -v 2.5.1 $ rbenv global 2.5.1 $ rbenv rehash $ ruby -v |
4. Prepare for the Rails application
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Lấy source của ứng dụng về $ sudo mkdir -p /var/www $ sudo chown -R deploy:deploy /var/www $ sudo chmod 775 /var/www/ $ cd /var/www $ git clone <a class="__cf_email__" href="/cdn-cgi/l/email-protection" data-cfemail="caaba8a98aafb2aba7baa6afe4a9a5a7">[email protected]</a> :/great_app.git && cd great_app # bundle install $ gem install bundler -v 1.16.6 # check bundler's version in Gemfile.lock $ bundle i $ source ~/.bash_profile # Phải generate mới credential cho Rail vì những file này bị ignore khỏi git repository $ rm config/credentials.yml.enc $ rm config/master.key $ EDITOR=vim bin/rails credentials:edit # Tạo file .env vì file này cơ bản cũng bị ignore khỏi git repository $ touch .env $ vi .env # Cài đặt các biến môi trường bạn cần dùng # Precompile $ RAILS_ENV=production rails assets:precompile |
5. Install Puma as a service – run in the background and start automatically
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # Đầu tiên cần tạo file cấu hình cho service puma $ sudo touch /etc/systemd/system/puma.service # Nội dung file puma.service tham khảo mình để ở dưới $ sudo vi /etc/systemd/system/puma.service $ sudo systemctl daemon-reload # Cho phép chạy puma khi boot $ sudo systemctl enable puma # Khởi động puma $ sudo systemctl restart puma # Nếu cần khởi động puma bằng tay, chạy lệnh sau $ RAILS_ENV=production /home/deploy/.rbenv/shims/puma -C /var/www/great_app/config/puma.rb |
Reference puma.service file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | [Unit] Description=Puma HTTP Server After=network.target # Uncomment for socket activation (see below) # Requires=puma.socket [Service] # Foreground process (do not use --daemon in ExecStart or config.rb) Type=simple # Preferably configure a non-privileged user # User= # The path to the your application code root directory. # Also replace the "<YOUR_APP_PATH>" place holders below with this path. # Example /home/username/myapp WorkingDirectory=/var/www/great_app # Helpful for debugging socket activation, etc. # Environment=PUMA_DEBUG=1 # SystemD will not run puma even if it is in your path. You must specify # an absolute URL to puma. For example /usr/local/bin/puma # Alternatively, create a binstub with `bundle binstubs puma --path ./sbin` in the WorkingDirectory Environment=RAILS_ENV=production ExecStart=/home/deploy/.rbenv/shims/puma -C /var/www/great_app/config/puma.rb Restart=always [Install] WantedBy=multi-user.target |
6. Install Nginx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # cài nginx $ sudo yum -y install nginx # Nội dung file greatapp.nginx.conf tham khảo mình để ở dưới $ sudo vi /etc/nginx/conf.d/greatapp.nginx.conf # Cho phép chạy nginx khi boot $ sudo systemctl enable nginx # Khởi động nginx $ sudo systemctl restart nginx $ sudo chown -R nginx:nginx /var/lib/nginx/ # 1回権限エラーで困った為、このフォルダーの権限を変更しておく # Thay đổi quyền cho log folders $ sudo chown -R deploy:deploy /var/log/nginx $ sudo chown -R deploy:deploy /var/log/nginx/* $ sudo chown -R deploy:deploy /var/www/great_app/log/* |
File greatapp.nginx.conf for reference
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | # log directory error_log /var/www/great_app/log/nginx.error.log; access_log /var/www/great_app/log/nginx.access.log; upstream app_server { # for UNIX domain socket setups server unix:///var/www/great_app/puma/puma.sock fail_timeout=0; } server { listen 80; server_name great-app.com *.great-app.com; # path for static files root /var/www/great_app/public; # page cache loading try_files $uri/index.html $uri @app_server; location / { # If requested files exists serve them try_files $uri $uri @app; } location @app { # When nginx should return maintenance page? # - when tmp/maintenance.txt file exists if (-f $document_root/../tmp/maintenance.txt) { set $maint_mode 1; } if ($remote_addr = 127.0.0.1) { set $maint_mode 0; } if ($maint_mode) { return 503; } # HTTP headers proxy_pass http://app_server; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; } # Maintenance page error_page 503 /maintenance.html; location /maintenance.html { if (!-f $request_filename) { rewrite ^(.*)$ /maintenance.html break; } } # Error pages error_page 500 502 504 /500.html; location = /500.html { root /var/www/great_app/public; } error_page 404 /404.html; location = /404.html { root /var/www/great_app/public; } client_max_body_size 4G; keepalive_timeout 10; } |
7. Setting log rotation
Logs of nginx, puma, rails will increase over time, so setting the rotation log is a habit we should do.
1 2 3 | # Nội dung file greatapp.logrotate.conf tham khảo mình để ở dưới $ sudo vi /etc/logrotate.d/greatapp.logrotate.conf |
File greatapp.logrotate.conf for reference
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # Nginx log /var/log/nginx/*.log { missingok weekly # rotate hàng tuần rotate 12 # keep đến 12 bản log gần đây nhất dateext dateformat -%Y%m%d } # Application log /var/www/great_app/log/*.log { missingok weekly rotate 12 dateext dateformat -%Y%m%d } |