Deploy HushJournal Binary On A Linux VPS

HushJournal provides multiple binaries for different OS and architectures, this makes it easy for you to deploy. In this blog post we will see how to deploy HushJournal for self-hosting on a Linux machine.

In this guide we will deploy our web app on t3.micro instance from AWS. Since our app is built with Rust, 1 GB RAM and 2 vCPU (shared) is more than enough to run it.

Start Postgres Server

HushJournal uses Postgres as its database. We will run our database server using docker compose. Create docker-compose.yml file with following content on it.

services:
  db:
    image: postgres:18
    environment:
      TZ: UTC
      PGTZ: UTC
      POSTGRES_USER: hushjournal
      POSTGRES_PASSWORD: hushjournal
      POSTGRES_DB: hushjournal
    command: ["postgres", "-c", "timezone=UTC"]
    volumes:
      - hushjournal_postgres:/var/lib/postgresql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U hushjournal -d hushjournal"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  hushjournal_postgres:

Now start the db container using below command:

docker compose up -d

Create systemd Service

Now we will create the systemd service for our binary so that it keeps running on background and survives system restart. First download the binary based on your OS and architecture from our release page.

Create the hushjournal user and setup directories for the binary.

sudo useradd --system -s /bin/false hushjournal
sudo mkdir -p /opt/hushjournal

Copy the binary file to /opt/hushjournal/, you might need to use sudo. Then run the following command.

sudo chown -R hushjournal: /opt/hushjournal/

Our application will need APP_ORIGIN and DATABASE_URL environment variable to run. We can pass this using .env file, place the file in /opt/hushjournal/.

APP_ORIGIN must be the origin where application is deployed i.e., for production it could be https://hushjournal.example.com, on local machine it could be http://localhost:8000.

APP_ORIGIN=http://127.0.0.1:8000
DATABASE_URL=postgres://hushjournal:hushjournal@hushjournal:5432/hushjournal

Creating systemd service:

sudo tee /etc/systemd/system/hushjournal.service << 'EOF'
[Unit]
Description=HushJournal
After=network.target

[Service]
ExecStart=/opt/hushjournal/hushjournal
WorkingDirectory=/opt/hushjournal/
Restart=on-failure
RestartSec=5
User=hushjournal
Group=hushjournal

[Install]
WantedBy=multi-user.target
EOF

Enable and start the HushJournal as systemd daemon:

sudo systemctl daemon-reload
sudo systemctl enable hushjournal
sudo systemctl start hushjournal

Setting Up Nginx

We will create the Server Block file for nginx to do the reverse proxy of our site.

Update the DNS of your domain to point to the IP address of your server.

sudo tee /etc/nginx/sites-available/hushjournal << 'EOF'
map $http_upgrade $connection_upgrade {
  "" close;
  default upgrade;
}

server {
        listen 80;
        listen [::]:80;
        server_name hushjournal.example.com;

        # Hide server information headers
        server_tokens off;

        # Enable gzip compression
        gzip on;
        gzip_disable "msie6";
        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_buffers 16 8k;
        gzip_min_length 1024; # Only gzip if size is at least 1KB
        gzip_types
          application/atom+xml
          application/geo+json
          application/javascript
          application/x-javascript
          application/json
          application/ld+json
          application/manifest+json
          application/rdf+xml
          application/rss+xml
          application/xhtml+xml
          application/xml
          font/eot
          font/otf
          font/ttf
          image/svg+xml
          text/css
          text/javascript
          text/plain
          text/xml;

        location / {
            include proxy_params;
            proxy_pass http://localhost:8000;
        }

        # Security headers
        add_header X-Content-Type-Options "nosniff" always;
        add_header Strict-Transport-Security "max-age=31536000; preload" always;
}
EOF

Now create the symlink to enable the site and test the nginx configuration.

sudo ln -s /etc/nginx/sites-available/hushjournal /etc/nginx/sites-enabled/hushjournal
sudo nginx -t

If there are no warning or error then we can restart the nginx to take effect.

sudo systemctl restart nginx

TLS Installation

Install certbot

sudo snap install core; sudo snap refresh core
sudo apt remove certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Obtain TLS certificate for your domain.

sudo certbot --nginx -d hushjournal.example.com
HushJournal
End-to-End Encrypted Journal