Skip to content

🚀 Basicrum Linux VM Deployment ​

You can deploy the full stack Basicrum app on any Linux VM using PM2 and Nginx, no Docker required for the app itself (we still use Docker for the databases, but you can also run those bare metal). We tested this setup ourselves on a Hetzner server, but any provider works the same way.

While this guide uses staging as an example, the steps are also applicable to other environments as well. If you'd rather deploy with Docker, see the Dokploy guide instead.

1. Overview ​

Our BasicRum Staging Backend runs on a Linux VM using:

  • Node.js (installed via nvm) for the backend and frontend
  • Rust binary for the beacon_service
  • PM2 for process management
  • PNPM for dependency installation
  • Docker (installed via apt)
  • PostgreSQL running on the server via docker
  • ClickHouse for now running on another server. The location is in the env file
  • Nginx for reverse proxy

We keep environment variables (.env) outside the Git repo in another directory to avoid overwriting them during git pull. In the future, we may consider using a secrets management tool like sops.

The server is authorized to pull (read only) from our GitHub repository. We use a deploy key for this purpose. The key pair is generated on the server and the public key is added to the GitHub repository settings. Learn more about deploy keys.


2. How to deploy ​

Before deploying, make sure the postgres db is running via docker on the server, the necessary environment variables are set (see below), and the remote clickhouse instance is accessible.

You can deploy the changes using SSH.

SSH from local machine ​

bash
ssh root@<SERVER_IP>

You need to be authorized to ssh into the server. Please ask us for the necessary credentials and provide us your public SSH key. We will add it to the allowed keys on the server. The keys are stored in ~/.ssh/authorized_keys on the server.

Pull changes from Git ​

Go to the project directory, pull the latest changes and install any new dependencies.

bash
cd /srv/basicrum
git pull origin main
pnpm install

To run the application, first build the api_contract, and the backend app itself.

bash
cd api_contract
pnpm build
cd ../backend
pnpm build

NOTE

We have to make sure the environment variables are set correctly before starting the application. If not, please follow the Environment Variables section below.

We use pm2 to manage the application processes. First check if any existing basicrum-backend pm2 processes are running:

bash
pm2 ls

If you see a process named basicrum-backend, stop and delete it with:

bash
pm2 stop basicrum-backend
pm2 delete basicrum-backend

If it's not running, you can start it with:

bash
pm2 start build/index.js --name basicrum-backend

Now check if the process is running:

bash
pm2 ls

You can also see its logs by running:

bash
pm2 logs basicrum-backend

Beacon service (Rust) ​

The beacon_service deploys the same way: build the release binary, then run it under pm2 like any other process.

bash
cd /srv/basicrum/beacon_service
./scripts/download-geoip.sh
cargo build --release
bash
pm2 stop basicrum-beacon || true
pm2 delete basicrum-beacon || true
pm2 start ./target/release/beacon_service --name basicrum-beacon

3. Environment Variables ​

We store the environment variables needed to start the application in /srv/assets/basicrum-backend/.env file or in any location of your choice. If you need to change any environment variables, please do so in this file.

You can use nano to edit the file.

bash
nano /srv/assets/basicrum-backend/.env

Make sure to copy the .env file to the backend directory before starting it:

bash
cp /srv/assets/basicrum-backend/.env /srv/basicrum/backend/.env

The beacon_service reads its configuration from environment variables too (BEACON_SERVICE_PORT, CLICKHOUSE_URL, etc., see the Local Development guide). Keep its .env at /srv/assets/basicrum-beacon/.env and export it before starting pm2, e.g. via an EnvironmentFile or by sourcing it in the pm2 start command.

4. Nginx setup ​

We use Nginx as a reverse proxy to forward requests to the backend application. The Nginx configuration file is located at /etc/nginx/sites-available/basicrum-backend. This config was enabled in Nginx by creating a symlink using sudo ln -s /etc/nginx/sites-available/basicrum-backend /etc/nginx/sites-enabled/

You can edit it:

bash
sudo nano /etc/nginx/sites-available/basicrum-backend

Current config:

nginx
server {
    listen 80;
    server_name <SERVER_IP>;

    #frontend
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    #backend: notice the /backend route prefix
    location /backend {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    #beacon_service: routes already include the /beacon prefix, so no rewrite needed
    location /beacon {
        proxy_pass http://127.0.0.1:3100;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

After making changes to the Nginx configuration, test the configuration for syntax errors:

bash
sudo nginx -t

If the test is successful, reload Nginx to apply the changes:

bash
sudo systemctl reload nginx

Check the app ​

You can check if the app is running by visiting http://<SERVER_IP>/backend/v1/health in your web browser. You should see a JSON response message "YOU SHALL NOT PASS" indicating you are unauthorized and the app is working correctly.

The beacon service's /health route isn't proxied publicly (its routes aren't namespaced under /beacon), so check it from the server instead:

bash
curl localhost:3100/health

Alternatively you can also point your local frontend to the server's IP address to test the integration. Just update you local frontend/.env file accordingly.

bash
BACKEND_URL=<SERVER_IP>
BACKEND_URL_FOR_AUTH=http://<SERVER_IP>/backend/v1
NEXT_PUBLIC_API_URL=http://<SERVER_IP>

Basicrum Frontend (staging) - Deployment. ​

The frontend deployment follows exactly the same pattern. The name of the pm2 instance is basicrum-frontend.

Similarly to the backend, the .env file for the frontend is located at /srv/assets/basicrum-frontend/.env in the remote server.

Miscellaneous ​

How to update node version ​

We use nvm to manage node versions on the server. To update node version, first ssh into the server and run:

bash
nvm install <new_version>

This will automatically set the new version as the default version.

How to update pm2 globally ​

To update pm2 globally on the server, run:

bash
npm install -g pm2

This will make the in-memory daemon out of date. To update the daemon, run:

bash
pm2 update

This will automatically restart all pm2 processes with the updated pm2 version.