Skip to content

Bare-Metal Deployment Guide (Debian 13)

This guide walks you through deploying openLogForge directly on a Debian 13 (trixie) server without Docker - as a classic web application managed by systemd and served behind Caddy.

The stack is:

  • Backend - FastAPI running under Uvicorn, managed by a systemd service
  • Frontend - static files built with Vite and served by Caddy
  • Reverse proxy - Caddy forwards /api/* to Uvicorn and serves the frontend for all other paths
  • Database - SQLite file on the local filesystem

Estimated time: 25-35 minutes.


System requirements

Resource Minimum Recommended
CPU 2 cores 4 cores
RAM 2 GB 4 GB
Disk 5 GB 10 GB
OS Debian 13 (trixie) x86_64 or arm64 -

Step 1 - Update the system

sudo apt update && sudo apt upgrade -y

Step 2 - Create a dedicated user

Run openLogForge under its own unprivileged user.

sudo useradd --system --shell /usr/sbin/nologin --home-dir /opt/openlogforge --create-home olf

Step 3 - Install Python 3.12

Debian 13 ships Python 3.12. Install it along with the virtual environment tools:

sudo apt install -y python3 python3-venv python3-pip

Verify the version:

python3 --version
# Python 3.12.x

Step 4 - Install Node.js 20

Node.js 20 is required to build the frontend. Install it from the NodeSource repository:

sudo apt install -y curl
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt install -y nodejs

Verify:

node --version   # v20.x.x
npm --version    # 10.x.x

Step 5 - Install Caddy

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddy

Verify:

caddy version

Step 6 - Install Git and clone the repository

sudo apt install -y git
git clone https://github.com/openlogforge/openlogforge.git /opt/openlogforge/app
sudo chown -R olf:olf /opt/openlogforge

Step 7 - Set up the backend

7.1 - Create a Python virtual environment:

sudo -u olf python3 -m venv /opt/openlogforge/venv

7.2 - Install Python dependencies:

sudo -u olf /opt/openlogforge/venv/bin/pip install --no-cache-dir \
  -r /opt/openlogforge/app/backend/requirements.txt

Note

This installs only the runtime dependencies. The dev/test tools listed after the comment in requirements.txt (pytest, ruff, mypy, etc.) are also installed by this command. They do not affect the running application and can be removed manually if disk space is a concern.

7.3 - Create the data directory:

sudo mkdir -p /var/lib/openlogforge
sudo chown olf:olf /var/lib/openlogforge

7.4 - Run database migrations:

sudo -u olf bash -c "
  cd /opt/openlogforge/app/backend &&
  OLF_DB_PATH=/var/lib/openlogforge/openlogforge.db \
  /opt/openlogforge/venv/bin/alembic upgrade head
"

You should see output ending with INFO [alembic.runtime.migration] Running upgrade ....


Step 8 - Build the frontend

8.1 - Install npm dependencies:

sudo -u olf bash -c "cd /opt/openlogforge/app/frontend && npm ci"

8.2 - Build the static files:

sudo -u olf bash -c "cd /opt/openlogforge/app/frontend && npm run build:docker"

Note

build:docker runs vite build only (no TypeScript type check), which is correct for a production build. If you want to run the full type check first, run npm run build instead - this requires the dev dependencies to be installed, which npm ci already handles.

The compiled files land in /opt/openlogforge/app/frontend/dist/.


Step 9 - Create the systemd service

Create the service unit file for the backend:

sudo nano /etc/systemd/system/openlogforge.service

Paste the following content:

[Unit]
Description=openLogForge backend
After=network.target

[Service]
Type=simple
User=olf
Group=olf
WorkingDirectory=/opt/openlogforge/app/backend
Environment="OLF_DB_PATH=/var/lib/openlogforge/openlogforge.db"
ExecStart=/opt/openlogforge/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000
Restart=on-failure
RestartSec=5

# Hardening
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/var/lib/openlogforge

[Install]
WantedBy=multi-user.target

Reload systemd and start the service:

sudo systemctl daemon-reload
sudo systemctl enable --now openlogforge

Verify it is running:

sudo systemctl status openlogforge

You should see Active: active (running).


Step 10 - Configure Caddy

Replace the default Caddy configuration:

sudo nano /etc/caddy/Caddyfile

Paste the following, replacing your-domain-or-ip with your server's IP address or domain name:

your-domain-or-ip {
    handle /api/* {
        reverse_proxy 127.0.0.1:8000
    }

    handle {
        root * /opt/openlogforge/app/frontend/dist
        try_files {path} /index.html
        file_server
    }
}

Using an IP address instead of a domain

If you do not have a domain name, use your server's IP address:

:80 {
    ...
}
Caddy will not attempt automatic TLS when bound to a plain port number.

Restart Caddy to apply the configuration:

sudo systemctl reload caddy

Step 11 - Open the firewall

sudo apt install -y ufw
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Step 12 - Access the web interface

Open a browser and navigate to your server's address:

http://your-domain-or-ip

You should see the openLogForge dashboard.


Managing the application

View backend logs:

sudo journalctl -u openlogforge -f

Restart the backend:

sudo systemctl restart openlogforge

Stop the application:

sudo systemctl stop openlogforge
sudo systemctl stop caddy

Updating to a new version

# Pull the latest code
cd /opt/openlogforge/app
sudo -u olf git pull

# Update Python dependencies
sudo -u olf /opt/openlogforge/venv/bin/pip install --no-cache-dir \
  -r /opt/openlogforge/app/backend/requirements.txt

# Run any new database migrations
sudo -u olf bash -c "
  cd /opt/openlogforge/app/backend &&
  OLF_DB_PATH=/var/lib/openlogforge/openlogforge.db \
  /opt/openlogforge/venv/bin/alembic upgrade head
"

# Rebuild the frontend
sudo -u olf bash -c "cd /opt/openlogforge/app/frontend && npm ci && npm run build:docker"

# Restart the backend
sudo systemctl restart openlogforge

Caddy serves the frontend directly from disk, so it picks up the rebuilt files immediately - no restart needed.


Troubleshooting

Backend fails to start

Check the logs for the error:

sudo journalctl -u openlogforge --no-pager -n 50

502 Bad Gateway in the browser

Caddy is running but cannot reach the backend on port 8000. Check that the backend service is up:

sudo systemctl status openlogforge
curl -s http://127.0.0.1:8000/api/v1/use-cases

Permission denied on the database file

Confirm the data directory is owned by the olf user:

ls -la /var/lib/openlogforge/
sudo chown -R olf:olf /var/lib/openlogforge
sudo systemctl restart openlogforge

npm ci fails during frontend build

Make sure Node.js 20 is installed and the repository was cloned correctly:

node --version
ls /opt/openlogforge/app/frontend/package.json

What is next