🚀 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
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.
cd /srv/basicrum
git pull origin main
pnpm installTo run the application, first build the api_contract, and the backend app itself.
cd api_contract
pnpm build
cd ../backend
pnpm buildNOTE
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:
pm2 lsIf you see a process named basicrum-backend, stop and delete it with:
pm2 stop basicrum-backend
pm2 delete basicrum-backendIf it's not running, you can start it with:
pm2 start build/index.js --name basicrum-backendNow check if the process is running:
pm2 lsYou can also see its logs by running:
pm2 logs basicrum-backendBeacon service (Rust)
The beacon_service deploys the same way: build the release binary, then run it under pm2 like any other process.
cd /srv/basicrum/beacon_service
./scripts/download-geoip.sh
cargo build --releasepm2 stop basicrum-beacon || true
pm2 delete basicrum-beacon || true
pm2 start ./target/release/beacon_service --name basicrum-beacon3. 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.
nano /srv/assets/basicrum-backend/.envMake sure to copy the .env file to the backend directory before starting it:
cp /srv/assets/basicrum-backend/.env /srv/basicrum/backend/.envThe 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:
sudo nano /etc/nginx/sites-available/basicrum-backendCurrent config:
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:
sudo nginx -tIf the test is successful, reload Nginx to apply the changes:
sudo systemctl reload nginxCheck 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:
curl localhost:3100/healthAlternatively 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.
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:
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:
npm install -g pm2This will make the in-memory daemon out of date. To update the daemon, run:
pm2 updateThis will automatically restart all pm2 processes with the updated pm2 version.