Welcome to the bouts.app operations manual. This page contains information for bouts.app developers and administrators.

#Provision a new host

The subsections within this section are meant to be followed in order and describe provisioning a new host using a VPS from DigitalOcean and getting the example.bouts.app instance set up on it.

#Create a droplet
  • Create a new droplet on DigitalOcean under the relevant project with the following settings:
    • Name it with its future domain name (example.bouts.app). Use this name for the hostname too.
    • Use the latest Ubuntu LTS as distribution (20.04 as of writing).
    • The smallest instance is probably ok.
    • Include the weekly backup service.
    • Use SSH keys to log in, not a password.
#DNS configuration
  1. Find and copy the IP address of the new server.
  2. Go to DNS settings and create an A record pointing from the subdomain example to the IP address.
#Update and install packages
  1. Update packages: # apt update; apt upgrade.
  2. Install postgres: # apt install postgres postgres-contrib postgresql-12 postgres-client-12.
  3. Install the Go >version 1.14: # apt install golang-go or # snap install go --classic.
#Postgres configuration

Adapted from crunchydata, Digital Ocean's community tutorial and Web Dev with Go.

  1. Upgrade authentication settings to scram-sha-256:
    1. Edit the postgresql.conf file: # vim /etc/postgresql/12/main/postgresql.conf
      • Set password_encryption = scram-sha-256 (default is md5 as of time of writing).
    2. Restart postgresql: # systemctl restart postgresql.
    3. Run psql as the postgres user: # sudo -i -u postgres psql:
      • Set a password on the postgres user: \password. (Using a long, random password. 64 characters is a good length. Save the password somewhere safe.)
    4. Edit the pg_hba.conf file: # vim /etc/postgresql/12/main/pg_hba.conf:
      • In the table at the bottom, replace peer and md5 (in the METHOD column) with scram-sha-256.
  2. Restart postgres: # systemctl restart postgresql.
  3. Create the database: # psql -U postgres, then CREATE DATABASE boutsapp_example.
  1. Install caddy:
    1. # echo "deb [trusted=yes] https://apt.fury.io/caddy/ /" | sudo tee -a /etc/apt/sources.list.d/caddy-fury.list
    2. # apt update
    3. # apt install caddy
#App service

Create a service for the app: # vim /etc/systemd/system/example.bouts.app, and use the following template:

Description=bouts.app example service

ExecStart=/root/bouts.app/example/server -prod

#App configuration
  1. Go to the app directory: # cd /root/bouts.app/example.
  2. Write a config.json file, using the database password and name set in previous steps. Replace pepper and hmac_key with long, random strings.
  "domain": "localhost",
  "port": 3000,
  "env": "prod",
  "pepper": "secret-random-string",
  "hmac_key": "secret-hmac-key",
  "database": {
    "host": "localhost",
    "port": 5432,
    "user": "postgres",
    "password": "postgres-password",
    "name": "boutsapp_example"
  "mailgun": {
    "from" : "support@bouts.app",
    "api_key": "secret-api-key",
    "domain": "mg.bouts.app"
  1. From your local machine, run scripts/deploy.sh and pass the instance name: $ ./scripts/deploy.sh example.
    • This will fetch the latest stable tag (or commit on master, if no tags), build it, copy the assets and views, and restart the systemd services for Caddy and the new bouts.app instance.
  2. Verify the service is available at https://example.bouts.app.
  3. Repeat these two steps when publishing updates.

#Add instances to an existing host

Adding instances to an existing host is simpler than setting one up for the first time. All of the steps will be repeats of steps used to provision and set up a new host. This section will describe setting up an instance called test.

  1. Set up DNS for the subdomain. Point test.bouts.app to the server's IP address using an A record.
  2. On the host server:
    1. Create a new database: $ psql -U postgres, then CREATE DATABASE boutsapp_test;.
    2. On the host, create a directory for the app: $ mkdir ~/bouts.app/test.
    3. Add a systemd service for the app: # vim /etc/systemd/system/test.bouts.app.service (using the template from before).
    4. Add a config.json to the app directory using the database name (using the template from before), and a new pepper and hmac key. Use a unique port.
  3. On your local machine:
    1. Update the Caddyfile.
      • Copy and paste the previous entry.
      • On the copy, change the site to test.bouts.app and the reverse_proxy port to the port you specified in the config.json.
    2. Deploy the instance by running scripts/deploy.sh with the instance name as an argument: $ ./scripts/deploy.sh test.

#Promote a user to admin

In order for a user to edit most resources, they need admin permissions. There can be multiple admins per instance. Admins can edit any exposed element on the instance, so only give permissions to trusted users.

We use permission_lvl = 1 to denote admin permissions, and permission_lvl = 0 for default user permissions.

  1. Find the user's email address (e.g., 'newadmin@example.com')
  2. On the host server:
    1. Connect to the database: $ psql -U postgres -d boutsapp_test.
    2. Give the user admin permissions using their email address: UPDATE users SET permission_lvl = 1 where email = 'newadmin@example.com';
    3. Deploy from your local machine: $ ./scripts/deploy.sh test

#Database backup and restore

Methods described in this document can be used to backup and later restore a database, to provide customers a copy of their data, or to transfer the database from one host to another.

This document uses test.bouts.app as the example instance.

See PostgresSQL Documentation on this topic for more information.

#Backup (SQL Dump)
  1. On the server test.bouts.app, create a db_backup directory: mkdir /home/postgres/db_backup.
  2. Run sudo -iu postgres pg_dump boutsapp_test > "/home/postgres/db_backup/boutsapp_test_$(date +%s).sql".
    • This dumps the database called boutsapp_test to the file /home/postgres/db_backup/boutsapp_test_$(date +%s).sql as user postres, where $(date +%s) is the current Unix epoch time.
  1. To see the list of backups for the boutsapp_test database, run ls /home/postgres/db_backup/boustapp_test_*.sql.
  2. Pick a file from the above list. I will refer to it as /home/postgres/db_backup_boutsapp_test_$date.sql.
  3. Before restoring, consider if the current form of the database should be saved via dump and then deleted. (You should probably do this.)
    • See above for instructions on making a dump of the database.
    • To delete the database, exercise extreme caution! First, stop the server to terminate the database connection. Then, drop the database using the dropdb -i command. Verify you have dumped this database before confirming.
    • Create the database again: sudo -iu postgres createdb boutsapp_test.
  4. Restore the database by running sudo -iu postgres psql --set ON_ERROR_STOP=on --single-transaction boutsapp_test < "/home/postgres/db_backup_boutsapp_test_$date.sql", substituting in the correct file name.
  5. Restart the server.
  1. Transfer the file however is convenient, for example by using rsync: rsync demo.bouts.app:/home/postgres/db_backup/boutsapp_test_$date.sql path/to/save/location/.
    • This command will transfer from the demo server to the local machine.


#Unable to Connect (Nothing Served)

If you are unable to connect to the server, try pinging it: $ ping demo.bouts.app. If you receive a response, then the instance is online and something is mis-configured. If you do not receive a response, then the server is offline and needs to be restored.

If the instance is online, connect to it so we can learn more information.

  1. On the host server:
    1. Check if Caddy is running: $ systemctl staus caddy.service.
    2. Check if the bouts.app service is running $ systemctl status test.bouts.app.

If either service is inactive, not loaded, or in a failed state, then resolve accordingly. Try restarting the service or turning it on first, and then checking the status to see if the issue is resolved.

#Investigating Caddy

If everything is running without error but the app isn't loading, then there may be an issue with the Caddyfile. Check to see which Caddyfile is being used (reported in systemctl status output in the caddy run command), then view that Caddyfile and ensure it is correctly configured.

If that Caddyfile is incorrect, either make the corrections or link the correct Caddyfile to that location (e.g., ln Caddyfile /etc/caddy/Caddyfile).

About this wiki

commit 99ef0fa3fb96827b961a29bceb60e13f15f86f03
Author: Ethan Madison <ethan@ethanmad.com>
Date:   2021-09-19T11:35:18-07:00

Add titles to manual pages

Signed-off-by: Ethan Madison <ethan@ethanmad.com>
Clone this wiki
https://git.sr.ht/~ethanmad/bouts.app (read-only)
git@git.sr.ht:~ethanmad/bouts.app (read/write)