We use cookies in order to improve your experience

Rails

Develatio’s Ruby on Rails AMI will let you deploy a full Ruby on Rails project in less than a minute and with zero configuration, enabling you to focus on what’s really important: your own code!

Components

This AMI is provisioned with several core components, configured for production usage.

  • Debian Buster (10) - The latest stable version of Debian
  • NGINX - Provided with a simple configuration for reverse proxying uWSGI and the ability to add a custom SSL cert with zero effort
  • Puma - Settings inherited directly from your application
  • Ruby 2.5 and Gem
  • Netdata - Monitor your EC2 instance without further complications, get alerts when something goes wrong. Accessible behind a basic auth login with user/password

Security

Aside from easy deployments, security is another topic that we’re really concerned about. That’s why this AMI is also provisioned with some extra components that will let you secure, prevent and monitor your EC2 instance for attacks, intrusions, FS modification attempts, etc…

  • SSH hardening - SSH login using root has been disabled. Only key-based logins are enabled. Only v2 of SSH protocol is enabled
  • RKHunter - Daily scanning and automatic updates
  • Fail2ban - Block any IP trying to brute-force your EC2 instance
  • Auditd and ACCT - Any suspicious activity will be recorded. This includes tampering Auditd itself, configuration files and logs, kernel modprobing, kexec usage, mount operations, time and date modification attempts, user/group operations, logins, access failure (unauthenticated file access/modification/deletion), power state changes, DAC modifications, any 32 API usage, ptrace-based code injections/debugs, any commands executed by root, etc…

System tweaks

  • SSH tweaks:
    • increased connection timeout
  • sysctl tweaks:
    • Increased file descriptor limit
    • Increased inotify limit
    • Enabled execshield
    • Network stack tuning (increased TCP buffer size, queue for input packets, selective logging, reverse path filtering, no routing modifications, prevent TCP time-wait attacks, prevent SYN attacks, etc…)
    • Discourage swapping idle processes
  • Bash tweaks:
    • readonly HISTFILE
    • readonly HISTIGNORE
    • don’t ignore commands
    • increased HISTSIZE
  • A swap file has been added
  • Improved I/O scheduler and I/O related tweaks

Folders structure

The AMI is designed in such a way that you only need to deal with one folder: /var/www/webapp. In that folder you’ll have all your configurations and your source code.

This is how the AMI will look like when you launch it:

├── conf
│   ├── autorun.sh
│   ├── cron
│   │   ├── d
│   │   ├── daily
│   │   ├── hourly
│   │   ├── monthly
│   │   └── weekly
│   ├── global
│   │   ├── hostname
│   │   └── timezone
│   ├── mail
│   │   ├── msmtprc
│   │   └── notifications
│   ├── netdata
│   │   └── password
│   └── nginx
│       ├── helloworld.crt
│       ├── helloworld.key
│       └── web.conf
└── src
    ├── Gemfile
    ├── Gemfile.lock
    ├── Rakefile
    ├── app
    ├── babel.config.js
    ├── bin
    ├── config
    ├── config.ru
    ├── db
    ├── lib
    ├── log
    ├── node_modules
    ├── package.json
    ├── postcss.config.js
    ├── public
    ├── storage
    ├── test
    ├── tmp
    ├── vendor
    └── yarn.lock

You can check the contents of our demo project here

Let’s start with the more obvious part, the src folder. This is the usual Ruby on Rails folder structure.

That said, let’s move on to the conf folder. That folder contains the configuration files for each service. You’ll be able to edit the behavior of all the services from here, without having to edit anything else. Just apply your changes and restart the services using the usual systemd commands.

Basic settings

Here’s a quick run-trough the basic conf files:

  • cron/* - This folder contains the usual /etc/cron.* folders structure you’d expect to have. Scripts inside these folders (d, daily, hourly, monthly, weekly) will be copied to the corresponding folder in /etc/cron.*.
  • global/hostname - Sets the hostname. Use any of the available variables:

    • KERNEL_NAME
    • NODENAME
    • KERNEL_RELEASE
    • KERNEL_VERSION
    • MACHINE
    • PROCESSOR
    • HARDWARE_PLATFORM
    • OS
    • IP_ADDR

    Keep in mind that the value of the resulting string will be slugified according to RFC 1123, which means that only letters, digits and hyphens are allowed

  • global/timezone - Sets the timezone. Use whatever you’d normally put in your /etc/timezone file. Check /usr/share/zoneinfo/.

  • mail/msmtprc - You can configure an SMTP server which will be used to send alerts from Auditd, RKHunter, Fail2ban, etc…

  • mail/notifications - Write a single line containing a valid email address to which the alerts should be sent

  • netdata/password - This is the file you’ll want to edit in order to change Netdata’s basic auth user/password. Use the usual command to generate a valid NGINX username and hash: openssl passwd -apr1 netdata. The user/password in the demo AMI is netdata/netdata

  • nginx/web.conf - This is the NGINX’s website configuration. The default file is configured to reverse proxy everything to the uWSGI server. It will listen by default on port 80, but there is a commented section in the configuration that will enable HTTPS using your certificates (nginx/helloworld.crt and nginx/helloworld.key)

Advanced settings

There are some extra stuff you must know. First of all, let’s start with the one file that hasn’t been covered yet: the autorun.sh. This script will be executed at every boot, using the admin user. Keep in mind that the AMI will make read-only the file on every boot, and it will chown it to admin.

Why is this script useful? You might want to execute some extra tasks after booting. Maybe collect static files or maybe run migrations.

Secondly, there are some commands that you can run at any time in order to apply the changes you’ve made in the configuration files:

  • configure_cron - Removes all user-provided scripts from all /etc/cron.* folders and then moves a fresh copy of the user-provided scripts, as described in the description of the cron/ folder
  • configure_hostname - Applies the configuration from global/hostname (in /var/www/webapp/conf/)
  • configure_notifications - Applies the configuration from conf/mail/notifications (in /var/www/webapp/conf/)
  • configure_timezone - Applies the configuration from global/timezone (in /var/www/webapp/conf/)

Tips & tricks

Unattended updates

This AMI has two systemd services that will run unattended updates: apt-daily.service and apt-daily.timer. If you don’t want to automatically keep your system updated, feel free to disable those services using the usual systemd commands (systemctl stop | disable).

Permissions

We strongly recommend to set proper permission to your conf and your src folders. We set the following permissions in our base AMI.

chown root:root /var/www/webapp

setfacl -R -d -m u:admin:rwx /var/www/webapp
setfacl -R -d -m g:www-data:rx /var/www/webapp
setfacl -R -d -m o::--- /var/www/webapp

setfacl -R -m u:admin:rwx /var/www/webapp
setfacl -R -m g:www-data:rx /var/www/webapp
setfacl -R -m o::--- /var/www/webapp

This will make the files

  • to be owned by root
  • to be read-only by the group www-data
  • to be writeable by the user admin

You’ll probably want to set write permissions to some folders (files uploaded by users?). We recommend using the autorun.sh. Keep in mind that the autorun.sh will be ran with the admin user, so you’ll need to use sudo.

sudo setfacl -R -d -m u:admin:rwx /var/www/webapp/src/user_uploads/
sudo setfacl -R -d -m g:www-data:rwx /var/www/webapp/src/user_uploads/
sudo setfacl -R -d -m o::--- /var/www/webapp/src/user_uploads/

sudo setfacl -R -m u:admin:rwx /var/www/webapp/src/user_uploads/
sudo setfacl -R -m g:www-data:rwx /var/www/webapp/src/user_uploads/
sudo setfacl -R -m o::--- /var/www/webapp/src/user_uploads/

Service management

The AMI provides the following systemd services, which you can use using the usual commands (systemctl status | start | stop) in order to manage your application:

  • puma - Control the Puma server (NGINX will reverse proxy to this server)
  • nginx - Control the NGINX web server

In case of failure or unexpected errors, use journalctl -f -u <service> to monitor the services.

Deployment

We recommend to use Packer and this AMI as a base image to build your own AMIs right from your CI/CD pipeline. Use the provisioners section in your Packer script in order to copy your configuration files to the conf folder and your source code to the src folder. You might also want to run any additional scripts or commands that don’t require the project to be running, for example, package managers install process (npm, composer, pip, etc…).

Ruby on Rails and Puma settings

Modify the files in the src/config/environments/ folder in order to setup your application and the src/config/puma.rb file in order to modify Puma’s configuration.

Changelog

v0.1.0 - 17/09/2019

  • This AMI and it’s components where created