Deploying Observable
Observable consists of two main components:
- a Go-based backend that monitors network endpoints and,
- a Next.js frontend that visualizes the telemetry in a 3D knowledge graph.
Get Podman Images
First, download the pre-built container images from the OpenML artifact repository:
# Download the frontend and backend images
curl -L -O https://observable.openml.io/openml-observable-frontend.tar
curl -L -O https://observable.openml.io/openml-observable-backend.tar
# Load the images into Podman
podman load -i openml-observable-frontend.tar
podman load -i openml-observable-backend.tar
Preparing the Host Storage
Create a directory on the host where the SQLite database will permanently reside. This ensures data persistence across container restarts.
mkdir -p /opt/observable/data
Since we are running Podman in rootless mode, we must ensure the directory is writable by the container process:
# Take ownership of the directory on the host
sudo chown -R $USER:$USER /opt/observable/data
# Ensure the directory is writable
chmod 775 /opt/observable/data
Backing Up SQLite Data
Never perform a standard file copy (like cp observable.db observable_backup.db) while the Go daemon is actively
running. Because our service is actively writing to the database every 30 seconds, copying the raw file mid-transaction
can result in a corrupted, unrecoverable backup.
Instead, we must use SQLite's native, transaction-safe backup prodecure below:
-
Mounting a persistent volume, like we did above
-
Using the native backup command,
sqlite3, which cleanly reads the database state and writes a consistent snapshot to a new file, pausing briefly if a write transaction is occurring to avoid corrupting the active daemon's transactions:sqlite3 /opt/observable/data/observable.db ".backup /opt/observable/data/observable_backup_$(date +%F).db"A backup file will appear under
/opt/observable/data/directory. For example:$ ls /opt/observable/dataobservable.db observable_backup_2026-06-03.dbwhere
observable_backup_2026-06-03.dbis the backup we just created -
Automating backup with a host-level cron job, which ensures our time-series data is protected. Open host's crontab using
crontab -eand add a schedule like this to run it every night at 2:00 AM:
0 2 * * * sqlite3 /opt/observable/data/observable.db ".backup /opt/observable/data/observable_backup_$(date +\%F).db"
Deploying with Podman Compose
The most efficient way to run both services together is using a Compose file. Create a file named compose.yaml in our
deployment directory:
# compose.yaml
services:
backend:
image: openml-observable-backend
container_name: observable-backend
restart: always
ports:
- "8080:8080"
volumes:
- /opt/observable/data:/app/data:Z
frontend:
image: openml-observable-frontend
container_name: observable-frontend
restart: always
ports:
- "3000:3000"
depends_on:
- backend
Launch the stack using:
podman-compose up -d
Verification
Once the stack is running, you can verify the deployment by accessing the following endpoints:
- Frontend HUD:
http://localhost:3000 - Backend Status API:
http://localhost:8080/status
To check the logs of the running services:
podman-compose logs -f