Deploy Early and Often: Deploying Phoenix with Edeliver and Distillery (Part One)
We will be setting up a Phoenix production environment on Ubuntu 16.04 LTS and deploy a simple Phoenix application using Edeliver and Distillery. We’ll be setting up a Droplet on DigitalOcean.
We will be compiling and deploying on the same server.
What you’ll need:
- An Elixir environment set up on your computer
- Any domain or subdomain
When it comes to learning Phoenix, deploying your application to a VPS is probably the most challenging part. I had developed an application with Programming Phoenix as a guide, and I wanted to deploy the finished application to a server. To my chagrin, it was almost impossible to debug the various cryptic error messages that came up. I realised that leaving deployment till last was a bad idea — the application had accumulated enough complexity that I was at a loss as to how to fix it. With so much technical debt, it was impossible to gauge which part of the process had gone wrong. It would have been easy to pinpoint errors had I deployed the application regularly from the beginning.
Whenever you develop a Phoenix application for any real-world use, remember to deploy early and often. This will save you hours of head scratching and hair pulling.
While there are a number of popular articles about deploying Elixir releases with Edeliver and Distillery, I had to piece together several different guides along with the Edelivery documentation in order to deploy successfully. Hopefully, this will serve as a “golden path” guide that would serve the needs of most small Phoenix applications.
Our Phoenix Application
Let’s start by creating a new Phoenix project. (You can skip ahead if you’re familiar with the basics)
mix phoenix.new deploy_phoenix
We’ll set up git:
git add .
git commit -m "initial commit"
Set up your database. Open config/dev.exs and config/test.exs and edit the database configuration, then run:
localhost:4000 in your browser. You should see the default Phoenix homepage.
Now, add the dependencies
mix deps.get to fetch the dependencies.
Our DigitalOcean VPS
Let’s set up our DigitalOcean VPS. (If you aren’t already using DO, you’ll get $10 in credit via this referral link.)
Click Create Droplet on your DigitalOcean dashboard, and select:
- Ubuntu 16.04.2 x64
- 1GB/1CPU ($10/mo)
- Any datacenter region
- Under “Select additional options”: none are necessary
- Your SSH key
Enter any hostname (for this guide, we’ll use deployphoenix), then click Create. Copy the ipv4 address, e.g. 22.214.171.124 (replace with your own).
SSH into the server:
Let’s create a deploy user that we will subsequently log in with. You’ll be prompted for a password and other details for the user.
Next, we’ll add the deploy user to the
usermod -aG sudo deploy
Now, we’ll copy the SSH keys over to the
deployuser’s home directory.
su - deploy
sudo cp /root/.ssh/authorized_keys ~/.ssh/authorized_keys
sudo chown `whoami` ~/.ssh/authorized_keys
Let’s try SSH’ing in using a new shell window.
Locking down the root account
Let’s perform some basic server hardening, starting with preventing SSH access to the root account.
Edit the sshd_config file with
sudo vim /etc/ssh/sshd_config (or use
sudo nano). Change the line
and save the file. Then, run:
sudo service sshd restart
We’ll now update system packages before we proceed.
sudo apt-get update
sudo apt-get upgrade
Setting up a firewall
Next, we’ll set up UFW.
sudo ufw app list # You should see OpenSSH listed
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status # Status: active
Let’s install PostgreSQL.
sudo apt-get install postgresql-9.6
You may see an error like the following:
E: Unable to locate package postgresql-9.6
E: Couldn’t find any package by glob ‘postgresql-9.6’
E: Couldn’t find any package by regex ‘postgresql-9.6
Let’s add the Postgres Apt repository. (I found this solution on the AskUbuntu site)
sudo add-apt-repository "deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main"sudo apt-get install postgresql-9.6
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
Now that we’ve installed PostgreSQL, let’s create a database.
sudo -i -u postgres
This opens a psql console.
postgres=# CREATE DATABASE deployphoenix_prod;
postgres=# CREATE USER deployphoenix WITH PASSWORD 'mypassword';
postgres=# GRANT ALL PRIVILEGES ON DATABASE deployphoenix_prod TO deployphoenix;
We’ve just created a database that we’ll later configure Phoenix to use. Type in
\q to quit the psql console, then
exit to return to the deploy user shell.
Since we’re using vanilla Phoenix for this guide, that means we’re using Brunch for asset compilation. Brunch requires
Node.js. Let’s install that now.
First, to add the
Node.js PPA maintained by NodeSource, we use
curl to retrieve the installation script.
curl -sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh
Then, we run the script:
sudo bash nodesource_setup.sh
The PPA will have been added, and the local package cache will be updated as well. Now, we can install Node.js.
sudo apt-get install nodejs
npm as well. We will also need the
sudo apt-get install build-essential
Let’s step back for a moment and review what we’ve got so far:
- A bare-bones Phoenix application
- An Ubuntu server ready for compiling and deploying
Give yourself a pat on the back if you’ve followed along so far. In Part 2, we will continue our deployment process. We will build and deploy a release, then get it to play nice with