Setting Up Staging for Personal Purposes

Like many developers, I often face the task of quickly deploying a test/showcase environment for a project.
A couple of years ago, I came up with a simple solution that saves time and money based on Ubuntu, Nginx, and Docker Compose.


Choosing a platform for staging

For a while now, I have been using VPS for such tasks. Just a month ago, I reevaluated the price-quality ratio and settled on the option of https://www.hetzner.com/cloud CX21.
For 5.88 euros, you get a 2-core CPU, 4GB of RAM, and a 40GB SSD. Compared to, for example, DigitalOcean, it’s affordable. And for an additional 1.18 euros, you can ensure regular backups.


What will be on staging

We will deploy a VPS, set up a firewall, install Nginx, Certbot for certificates, and Docker Compose.

Basic server setup

Reference

Firewall configuration

$ ssh root@your_server
$ ufw app list
$ ufw allow OpenSSH
$ ufw status

Key-based access only

Reference

Edit the file:
$ vim /etc/ssh/sshd_config

and set the value no for PasswordAuthentication no

Then restart SSH:
$ systemctl restart ssh

Installing Docker and Docker-Compose

Installing Docker

Reference

$ apt update
$ apt install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
$ apt-cache policy docker-ce
$ apt install docker-ce
$ systemctl status docker

Installing docker-compose

Reference

Choose the desired version from the page https://github.com/docker/compose/releases.

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version

Installing and configuring Nginx

Reference

$ apt update
$ apt install nginx
$ ufw app list
$ ufw allow "Nginx Full"
$ ufw status

Instructions for installing Certbot from Let’s Encrypt: https://certbot.eff.org/instructions

Preparing basic authentication for future projects (optional)

$ apt install apache2-utils
$ htpasswd -c /etc/nginx/htpasswd YOUR_LOGIN

To update the password:
$ htpasswd /etc/nginx/htpasswd YOUR_LOGIN

To create a separate user for managing Docker Compose

$ adduser deployer --disabled-password
$ sudo usermod -aG docker deployer
$ sudo usermod -aG docker deployer
$ su - deployer
$ groups

If desired, you can set up key-based authentication for the deployer user to enable deployment from CI.

How to deploy an application (using Strapi as an example)

$ vim /etc/nginx/sites-enabled/strapi

Insert the following content:

server {
    server_name strapi.YOUR_DOMAIN;

    # Uncomment the lines below if you want to restrict access using the previously set up basic authentication
    # auth_basic "Restricted";
    # auth_basic_user_file /etc/nginx/htpasswd;
    access_log syslog:server=[2001:db8::1]:1234,facility=local7,tag=nginx,severity=info;

    location / {
        proxy_pass      http://127.0.0.1:1337;
    }
}

Then restart Nginx: $ service nginx restart

To issue a certificate, run certbot and follow the instructions.

Next, switch to su - deployer and create a docker-compose.yml file.

version: '3'
services:
  strapi:
    image: strapi/strapi
    environment:
      DATABASE_CLIENT: postgres
      DATABASE_NAME: strapi
      DATABASE_HOST: postgres
      DATABASE_PORT: 5432
      DATABASE_USERNAME: strapi
      DATABASE_PASSWORD: strapi
    volumes:
      - ./app:/srv/app
    ports:
      - '1337:1337'
    depends_on:
      - postgres

  postgres:
    image: postgres:13-alpine
    environment:
      POSTGRES_DB: strapi
      POSTGRES_USER: strapi
      POSTGRES_PASSWORD: strapi
    volumes:
      - ./data:/var/lib/postgresql/data

Then run docker-compose up -d

Update from 2022-07-14

I have created an Ansible playbook for setting up staging: https://github.com/dmkuznetsov/ansible-staging-example