Setting Up Phoenix/Elixir With Nginx and LetsEncrypt

Andrew Forward
4 min readJan 7, 2016

In this article we are going to setup a Phoenix web application (running Elixir), served using Nginx and configured for encrypted pages using LetsEncrypt (i.e. all traffic running through SSL / HTTPS).

Elixir is a wonderful (new) language that is mostly functional, with a great syntax, a vibrant community and leverages Erlang (a battle-tested language known for low-latency, distributed and fault-tolerant systems).

Phoenix is the dominant web framework for Elixir.

LetsEncrypt is the new Certificate Authority that is touted as being free, automated and open. It’s still in Beta, so the automated part is still a work in progress :-).

Before we get started, you will need a few things installed first, I have provided links to installation scripts for Ubuntu 14.04 if you don’t already have an environment up and running.

Older versions might still work, so don’t go upgrading just yet; try things out and let me know if you run into problems.

Let’s create a new app and start it up

echo "Y" | mix phoenix.new isafe
cd isafe
mix phoenix.server

Your app should look like

And, Nginx should configured on port 80 with the default site.

Now let’s configure Nginx to serve up our Phoenix app. Let’s add an server to your nginx.conf (your nginx.conf might be somewhere different).

vi /usr/local/nginx/conf####
http {
upstream phoenix_upstream {
server 127.0.0.1:4000;
}

server {
listen 80;
location / {
proxy_redirect off;
proxy_pass http://phoenix_upstream;
}
}
}
####

Restart Nginx, and you should now see your app phoenix app.

Now let’s configure Nginx with Let’s Encrypt. At the moment the Nginx plugin isn’t ready. So we will do it manually. Please change the email and domain appropriately.

letsencrypt-auto certonly -a manual --rsa-key-size 4096 --email example@email.com -d yourdomain.com

During the process, you will be asked to verify the domain, similar to…

Make sure your web server displays the following content at
http://yourdomain.com/.well-known/acme-challenge/g6mNtyZq1Ok-dddddd-cccccc before continuing:
g6mNtyZq1Ok-dddddd-ccccccc.9_fMxmKqgJuqNtACmoj76huophfBfP26R4_WvlQcwgYIf you don’t have HTTP server configured, you can run the following
command on the target server (as root):

So, let’s’ stop Nginx, and run the python script to launch the mini webserver. When it’s ready, click enter.

If all goes well you should have your certificates setup at:

ls -la /etc/letsencrypt/live/yourdomain.com/

Now back to your nginx.conf and add in the necessary SSL information

vi /usr/local/nginx/conf####
http {
upstream phoenix_upstream {
server 127.0.0.1:4000;
}

server {
listen 80;
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/cert.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_redirect off;
proxy_pass http://phoenix_upstream;
}
}
}
####

Restart nginx and you are now encrypted.

Next, we should force all traffic to flow through HTTPS.

vi /usr/local/nginx/conf####
http {
upstream phoenix_upstream {
server 127.0.0.1:4000;
}

server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/cert.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_redirect off;
proxy_pass http://phoenix_upstream;
}
}
}
####

You should be automatically redirectled to HTTPS if you try to access the insecure URL from HTTP. Please note that you will need to regenerate your SSL Certificate every 90 days!

Last thing to setup, you will want to remove direct access to your phoenix application. There are many ways to configure your phoenix app for production use, but here just make sure that you bind yourself to 127.0.0.1.

config :isafe, Isafe.Endpoint,
http: [ip: {127, 0, 0, 1}, port: 4000],

Now your site is being served up only through SSL (using Nginx), and Phoenix is no longer directly available on port 4000.

Happy HTTPS.

--

--

Andrew Forward

Back to PHP and #elixir; flirting with #Elm. TDD infected since jUnit 2.1, former cheesemaker, and working at #crossfit