Download the slides from the talk I gave at NWRUG in April 2017.
Below are some more detailed notes to accompany the talk too. If you give any of this a try and need more details at all please drop me a line.
The instructions assume a user will be added to the server that will be used for running the hosted applications. In these notes that user is called deploy
.
The application installation instructions use an app name of demoapp
which can be replaced as appropriate.
Commands that can be run as the deploy
user are prefixed with a $
whereas commands that need to be run as root
are prefixed with a #
.
Instructions are based on using Ubuntu 16.04 LTS
Add a separate user that will be used for running the hosted applications:
# useradd deploy
sudo
, this sets things up so the deploy
user can run commands via sudo
without needing to enter a password, this is required for deployments to run without user intervention:
# gpasswd -a deploy sudo
# sudo sh -c 'echo "deploy ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/90-deploy'
$ sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev nodejs
/etc/ssh/sshd_config
:
PermitRootLogin no
PasswordAuthentication no
rbenv
and ruby-build
for the deploy
user:
cd
rbenv
git repo: $ git clone git://github.com/sstephenson/rbenv.git .rbenv
rbenv/bin
folder to the path: $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
rbenv
when logging in: $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
ruby-build
plugin which can be used to build the desired version of Ruby from source: $ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
ruby-build/bin
to the path: $ echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bash_profile
.bash_profile
to avoid needing to log out and log back in again to pick up changes above: $ source ~/.bash_profile
rbenv-vars
plugin to allow a .rbenv-vars
file in each application folder to be used to set environment variables for that app: $ git clone https://github.com/rbenv/rbenv-vars.git $(rbenv root)/plugins/rbenv-vars
$ rbenv install -v 2.4.1
$ rbenv global 2.4.1
$ echo "gem: --no-document" > ~/.gemrc
$ gem install bundler
nginx is used as the public facing web server:
$ sudo apt-get install nginx
Notes are based on using PostgreSQL but could use MySQL instead:
$ sudo apt-get install postgresql postgresql-contrib libpq-dev
One-time changes that should be made to a Rails app before deploying using these notes:
config/puma.rb
file to include separate settings for development and production:
One-time steps needed on the server to set up a new app:
$ sudo -u postgres createuser -s demoapp
Set password for postgres app user:
$ sudo -u postgres psql
psql (9.5.6, server 9.3.15)
Type “help” for help.
postgres=# \password demoapp
Enter new password:
Enter it again:
postgres=# \q
$ git clone --bare https://github.com/mikej/demoapp.git ~/demoapp_repo
$ mkdir ~/demoapp
.rbenv-vars
file in ~/demoapp
. This file is used by the rbenv-vars
plugin to set any necessary environment variables for the app:
RAILS_ENV=production
SECRET_KEY_BASE=post-receive
is readable and executable by deploy
user)/lib/systemd/system
and symlink it into /etc/systemd/system/multi-user.target.wants
: $ sudo ln -s /lib/systemd/system/demoapp.service /etc/systemd/system/multi-user.target.wants/demoapp.service
/etc/nginx/sites-available
and symlink into /etc/nginx/sites-enabled
: $ ln -s /etc/nginx/sites-available/demoapp /etc/nginx/sites-enabled/demoapp
$ sudo systemctl start demoapp
$ sudo systemctl restart nginx
This section covers generating and installing a Let’s Encrypt certificate once a basic app is up and running. See also: https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04
$ sudo apt-get install letsencrypt
Generate a certificate: $ sudo letsencrypt certonly -a webroot --webroot-path=/home/mike/demoapp/public -d demoapp.josephson.org
-a webroot
indicates to use webroot authentication: a file is placed in the a folder called .well-known
under the web-root path. On running the letsencrypt
command, a copy of this file will be requested by Let’s Encrypt to verify ownership of the domain specified.
$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
Create an nginx config snippet file in /etc/nginx/snippets
that is specific to this certificate e.g. /etc/nginx/snippets/ssl-demoapp.josephson.org.conf
:
Create a Configuration Snippet with Strong Encryption Settings. This is a file e.g. /etc/nginx/snippets/ssl-params.conf
that can be shared across all your apps, containing a good set of SSL defaults to use for nginx. This is using the recommendations by Remy van Elst on the Cipherli.stsite. You can read more about his decisions regarding the Nginx choices here.
/etc/nginx/sites-available
to support SSL and to redirect non-https requests to the corresponding https URL e.g. using config like this.$ sudo systemctl restart nginx
$ sudo letsencrypt renew
. This can be automated by setting up a daily cron
task - if there are no certificates due for renewal at the time of running then letsencrypt
will indicate this and exit without making any changes.