A Website and a Blog for $5/mo - Part 2

Mon, Nov 09 2020

This is the second part of a series focussing on setting up more than one Phoenix Application on a single Digital Ocean Droplet (Part 1 can be found here).

Simple Phoenix Application

As I mentioned in Part 1, I was keen to not use a database for my website and blog, not only to keep the cost lower, but also I am not planning on doing anything that needs a database yet (In a future post I will detail how I made a LiveView contact form without a database).

To test my server I started with a Phoenix Application:

$ mix phx.new blog --live --no-ecto

Following the instructions and ensure that it runs with the default settings (Creating a new Phoenix App is well documented so I won’t spend anytime on it here). However, using the –live and –no-ecto switches will ensure most of the biolerplate we need is setup for us.

Git

Make sure you follow best practice and keep your project in a code repo. If you have not done so already, head over to github and create and account. With an account create a new repo called blog or whatever you called your Phoenix Application above. Once you have a github repo create your local git repo and add the github remote.

$ git init
$ git remote add origin git@github.com:your_user_name/your_project_name.git
$ git add .
$ git commit -m "initial commit"
$ git push --set-upstream origin master

Simplify Your Phoenix App

Go to the page_live.html.leex and modify the page to identify it as your Blog or whatever you have called your project. Delete all of the html and replace it with something unique. Open the page_live.html.leex in your editor of choice.

$ vim /lib/blog_web/live/page_live.html.leex

Replace all of the markup with something like

<div>
    <h1>MY BLOG</h1>
<div>

You can then open page_live.ex and remove all of the functions except mount, change mount to

@impl true
def mount(_params, _session, socket) do
{:ok, socket}
end

You can now delete all of the handle_event functions. Run mix phx.server and ensure that your site is running on localhost:4000 and shows your modified page. We cam now deploy the application to our Digital Ocean Droplet. Don’t forget to commit your changes to github.

$ git add .
$ git commit -m "Modified home page"
$ git push

Deployment

Our first deployment will be manual (In a future post I will show you how I automated it). Start by connecting to your Droplet using ssh.

$ ssh your-user-name@your-Droplet-ip

Then we need to install git.

$ sudo apt-get install git

After installing git we need to add an ssh-key to github so we can pull the repo to our server. Just like before run ssh-keygen (ensuring the new key is created in the .ssh/ directory). I used all of the default settings, and then used the more cmd to copy the public key (Make sure it is the .pub file).

Once you have the public key go to your github account and navigate to the deploy keys sections Settings -> Deploy Keys. Create a new deploy key (naming it something meaningful) and paste in the public key from the server.

Now that you have the deploy key setup, grab the clone url from the Clone or Download menu. Go back to your ssh session with the Droplet and clone your repo on the server.

$ git clone git@github.com:your-account/your-project.git

Once the project has been cloned run through the local setup.

$ cd project_name
$ mix deps.get
$ cd assets
$ npm install

NOTE: I had some issues with webpack when I started to create a release and found a tip from Michael at Omgneering that webpack needed to be installed globally.

$ sudo npm install -g webpack
$ sudo npm install -g webpack-cli

Because we are going to be creating a PROD release we need to change our configuration. Go back to your github account and navigate to Settings -> Secrets. Create a new secret called KEY_BASE and past in a key generated at in your terminal using mix phx.gen.secret 64.

Then create a new secret called SIGNING_SALT and paste in the key generated using mix phx.gen.secret 32. Go back to your local editor and open /config/prod.exs and make the following changes.

use Mix.Config

config :your_app, YourAppWeb.Endpoint,
  server: true,
  http: [
    port: String.to_integer(System.get_env("PORT") || "4000"),
    transport_options: [socket_opts: [:inet6]]
  ],
  url: [host: "your-domain.com", port: 80],
  check_origin: [
    "https://your-domain.com",
    "https://www.your-domain.com"
  ],
  secret_key_base: System.get_env("KEY_BASE"),
  live_view: [signing_salt: System.get_env("SIGNING_SALT")]

# Do not print debug messages in production
config :logger, level: :info

Commit your changes from your local machine to github.

$ git add .
$ git commit -m "Modified PROD config"
$ git push

Now go back to your ssh session on the Droplet and run git pull from the project directory. Your project will now be up to date on the server. Before we build our release we are going to setup Nginx. Open the settings file for your project (See Part 1) using $ sudo vim /etc/nginx/sites-available/your-website-name, add the following section directly above the sever config:

upstream your-website-name{
    server 127.0.0.1:4000;
}

server {
    ...
}

Then go down to the location section and change it to

location / {
    allow all;

    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Cluster-Client-Ip $remote_addr;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_pass http://your-website-name; # Defined above
}

Save and test the config using sudo nginx -t and if OK restart with sudo systemctl restart nginx. Now we can build and start our Phoenix application and test our server. Go to the project directory and run

$ npm run deploy --prefix ./assets
$ mix phx.digest
$ MIX_ENV=prod mix compile
$ MIX_ENV=prod mix release 
$ _build/prod/rel/your_project/bin/your_project start

You should now be able to go to your domain and see your Phoeinx application. You can stop your application by using

$ _build/prod/rel/your_project/bin/your_project stop

If you want to run your application and exit the Droplet you can use

$ _build/prod/rel/your_project/bin/your_project daemon

You can see all the commands available using

$ _build/prod/rel/your_project/bin/your_project

In Part 3 I am going to deploy another Phoeinx Application and configure Nginx to serve both sites.