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
Step 2 - Create a dedicated user
Run openLogForge under its own unprivileged user.
Step 3 - Install Python 3.12
Debian 13 ships Python 3.12. Install it along with the virtual environment tools:
Verify the version:
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:
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:
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:
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:
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:
8.2 - Build the static files:
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:
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:
Verify it is running:
You should see Active: active (running).
Step 10 - Configure Caddy
Replace the default Caddy configuration:
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:
Caddy will not attempt automatic TLS when bound to a plain port number.Restart Caddy to apply the configuration:
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:
You should see the openLogForge dashboard.
Managing the application
View backend logs:
Restart the backend:
Stop the application:
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:
502 Bad Gateway in the browser
Caddy is running but cannot reach the backend on port 8000. Check that the backend service is up:
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:
What is next
- First Use Case Walkthrough - create your first attack simulation use case
- SIEM Target Configuration - configure your SIEM as a log destination