Operation and Updates
Audience: Technical administration
Overview
For day-to-day operation you need two scripts in the project directory: start.sh and stop.sh. This chapter also describes where to find logs and service status, how to update oPBWeb and what to keep in mind on the opsi side. Run all commands in the project directory.
Starting and stopping the stack
start.sh
./start.sh [--build] [--logs] [--dev | --test] [--lang de|en]
| Option | Effect |
|---|---|
| (none) | starts the production stack (docker-compose.yml) with the existing images |
--build | rebuilds your own images before starting |
--logs | follows the logs of all containers after starting (logs -f --tail=50); Ctrl+C only ends the output |
--dev | adds docker-compose.dev.yml (development stack, see below); only in a clone with the sources |
--test | adds docker-compose.test.yml: two opsi mocks as config servers Test and Production, see Test Environment |
--lang de or --lang en | language of the messages for this run (otherwise OPBWEB_LANG from .env) |
-h, --help | shows the help |
Sequence: the script aborts if .env is missing („.env fehlt – bitte ./setup-opbweb.sh ausführen (im Entwickler-Checkout: ./setup-opbweb.sh –dev).“ – .env is missing, please run ./setup-opbweb.sh, in a developer checkout ./setup-opbweb.sh –dev), calls scripts/init-secrets.sh, runs docker compose up -d and shows the status with docker compose ps. Running containers whose configuration has not changed are left untouched. start.sh does not pull new third-party images; for that, see Updating
.
stop.sh
./stop.sh
The script has no options. It runs docker compose down with docker-compose.yml and the overlays present (docker-compose.dev.yml, docker-compose.test.yml) and thus stops production, dev and test services alike. Containers and networks are removed; the volumes with database and object storage are kept.
Restarting individual services
docker restart opbweb-worker
docker restart opbweb-frontend # e.g. after a certificate change
Restarting the worker interrupts running jobs. Check under Jobs beforehand whether installations are currently running.
Containers
| Container | Service | Note |
|---|---|---|
opbweb-frontend | nginx | web interface, manual, proxy |
opbweb-api | API | runs the migrations at startup |
opbweb-worker | worker | jobs, cron, opsi connection |
opbweb-db | MariaDB | |
opbweb-redis | Redis | |
opbweb-garage | Garage | object storage |
opbweb-garage-init | Garage setup | runs briefly on every start and exits with exit code 0 |
opbweb-opsi-mock | dev only | simulated opsiconfd (first opsi system) |
opbweb-opsi-mock2 | dev only | simulated opsiconfd (second opsi system) |
opbweb-frontend-dev | dev only | Vite dev server |
opbweb-manual-dev | dev only | Hugo preview of the manual |
opbweb-launcher-build | dev only | builds the launcher zips at startup and exits with exit code 0 |
opbweb-launcher-dev | dev only | serves the launcher zips |
docker compose ps shows the status (production stack); docker compose ps -a also includes exited containers such as garage-init.
Logs
docker logs -f --tail=100 opbweb-api
docker logs -f --tail=100 opbweb-worker
docker compose logs -f --tail=50 # all services
| Container | What you find there |
|---|---|
opbweb-api | migrations and uvicorn start, creation of the first admin, HTTP requests (one line per request), problems with LDAP sign-in |
opbweb-worker | job execution, opsi check (every 5 minutes by default), errors in connections to opsiconfd |
opbweb-frontend | choice of HTTP or HTTPS, requests and nginx errors |
opbweb-garage-init | setup of layout, key and bucket |
LOG_LEVEL in .env controls the verbosity of api and worker (DEBUG, INFO, WARNING, ERROR; default INFO). A change takes effect with the next ./start.sh.
For LDAP sign-in, the API logs why a sign-in fails: user not found (zero hits for the search filter) and wrong password at level INFO, no group mapped to a role at level WARNING. With LOG_LEVEL=WARNING or ERROR you therefore do not see the first two cases. For example:
docker logs opbweb-api 2>&1 | grep "LDAP login"
python-opsi and the HTTP client httpx only output warnings and errors. Their debug output is enabled only by DEBUG=true; this also starts the API with hot reload and is meant for development only, see Configuration
.
The complete log of every job is also available in the user interface under Jobs, see Jobs .
Checking the status
| Endpoint | Sign-in | Response |
|---|---|---|
/health | no | static healthy from nginx; only checks whether nginx responds |
/api/health | no | {"status":"ok","version":"…"}; the API is reachable through nginx |
/api/health/details | yes (bearer token) | checks database, redis, storage, worker, opsi with ok, details and duration |
/api/system/database | yes, admin | rows and size per database table |
/api/system/storage | yes, admin | object storage usage per area, deduplication, unused and missing blobs |
/api/system/storage/objects | yes, admin | objects of an area with the package versions using them (basis of the bucket browser) |
| System status page | yes, all roles | the same checks as a table, refreshed every 10 seconds |
/api/health is suitable for simple monitoring:
curl -fsS https://opbweb.example.local/api/health
The detailed check evaluates as follows (the details follow the interface language):
| Check | Error if … |
|---|---|
| Database | no connection; otherwise the details show the MariaDB version and schema revision |
| Redis | no connection |
| Object storage | no connection or bucket missing (“Bucket ‘…’ is missing”) |
| Worker | no heartbeat (“no sign of life”) or last heartbeat older than 90 seconds |
| opsi server | not checked yet, no config server configured, or for at least one config server: connection failed, no admin rights, new CA certificate not yet accepted, or expiry warning |
Administrators also see the database table sizes, the object storage usage and the bucket browser on the system status page, see System status .
Scheduled tasks
The worker runs these tasks itself; you do not need a cron entry on the host.
| Task | Schedule | Effect |
|---|---|---|
| Heartbeat | every 30 seconds | sign of life for the system status |
| opsi check | every 5 minutes (default) | connection, depot sync, CA comparison, expiry warning 60 days in advance |
| Cleanup of temporary files | daily at 03:17 (default) | deletes uploads/ and downloads/ older than 24 hours |
The times of the opsi check and the cleanup are set under Settings → Worker ; they apply without a restart.
The automatic task does not remove unused package files (blobs) or build results. An administrator does that when needed with Clean up … on the System status page: first a dry run, then the confirmed deletion.
Updating
Back up the database and object storage, see Backup and Restore . Database migrations cannot easily be undone.
Check under Jobs that no installations are running.
Get the new version, for example with
git pullor with a new stack ZIP unpacked over the installation. The ZIP contains no.env,secrets/orcerts/, they are kept.Bring
.envup to date:./setup-opbweb.sh --updateonlyThe script keeps all existing values, adds new variables with their default and creates new secrets; existing secrets stay unchanged. If you want to change values at the same time, run
./setup-opbweb.shwithout an option.Update the images and start the stack:
Locally built images:
./start.sh --build--builduses the Docker build cache. Security updates of the base images and the system packages do not necessarily arrive that way. For a security update, build without cache and with fresh base images, then run./start.sh:docker compose build --pull --no-cacheImages from a registry: Enter the new image versions, either interactively with
./setup-opbweb.sh(questions about the image versions; the default is the previous version) or directly inBACKEND_IMAGE,FRONTEND_IMAGEandGARAGE_INIT_IMAGEin.env.--updateonlykeeps the previous versions. With aversions.envnext to it (stack ZIP), its versions are the defaults, for--updateonlytoo; unpacking a new ZIP and running--updateonlythus switches the images to its versions. Then:docker compose pull ./start.shIf you use the
latesttags,docker compose pulland./start.share enough.
The API runs
alembic upgrade headautomatically at startup. Check the log afterwards:docker logs opbweb-api 2>&1 | head -50In the user interface, check the versions in the status bar (“Frontend …”, “Backend …”) and the System status page.
start.sh does not automatically pull new versions of the third-party images (MariaDB 11.4, Redis 7, Garage v2.2.0) within their tags. Example, run when needed:
docker compose pull db redis garage
./start.sh
To also update the base images of your own images (node, nginx, python), build with docker compose build --pull and then start with ./start.sh. This only applies to locally built images.
Versioning
Backend and frontend have separate version numbers following the scheme MAJOR.MINOR.PATCH (milestone, phase, bug fix). The user interface shows both in the status bar; /api/health returns the backend version.
Versions are set with set-version.sh; the affected files are listed in version.yaml (backend: backend/src/core/version.py and backend/pyproject.toml, frontend: frontend/package.json via npm version).
| Call | Effect |
|---|---|
./set-version.sh | shows the current versions |
./set-version.sh 0.14.0 | sets all components (with confirmation; --force without) |
./set-version.sh --backend 0.13.1 | sets the backend only |
./set-version.sh --frontend 0.13.1 | sets the frontend only |
./set-version.sh --component <name> <version> | sets one component from version.yaml |
./set-version.sh --config <file> | uses a different configuration file |
A changed version file on the default branch triggers the build of the matching image in GitLab CI, see Build and Delivery .
opsiconfd: admin-networks
The worker calls opsiconfd with admin rights. If the option admin-networks is set in the opsiconfd configuration, the worker’s source address must be within it; otherwise opsiconfd responds with HTTP 403.
Which address opsiconfd sees depends on where oPBWeb runs (derived from Docker’s network behavior; please verify in the opsiconfd log):
oPBWeb on the configserver itself: the worker’s address in the Docker network
opbweb_opsi-net. To show the subnet:docker network inspect opbweb_opsi-net --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'oPBWeb on a different host: usually the address of the Docker host, because Docker masquerades outgoing traffic.
./stop.sh removes the Docker networks; on the next start, opbweb_opsi-net may get a different subnet. Therefore either enter the entire address range from which Docker allocates its networks, or check the subnet after every restart. The opsi manual describes the syntax of the option; opsiconfd must be restarted after the change.
Development stack
The development stack is meant for further development, not for production. In a fresh developer checkout, first create .env (from .env.example, without questions) and then start with locally built images:
./setup-opbweb.sh --dev
./start.sh --dev --build
It adds hot reload (sources as bind mounts, DEBUG=true), two simulated opsiconfd instances, a preview of the manual and the launcher zips to the production stack. API and worker run with the image opbweb-backend:dev.
| What | Address |
|---|---|
| Vite dev server (user interface with hot reload) | http://localhost:3100 |
Manual preview (manual-dev, via the Vite proxy) | http://localhost:3100/manual/ |
Launcher zips (launcher-dev, via the Vite proxy) | http://localhost:3100/downloads/ |
| API with OpenAPI interface | http://localhost:8100/api/docs |
| nginx frontend | port from FRONTEND_HTTP_PORT or FRONTEND_HTTPS_PORT |
| MariaDB | port 3307 |
| Redis | port 6380 |
| Garage S3 | port 3910 |
opsiconfd mock (opsi-mock) | opsi-config.mock and depot1.mock, only in the Docker network |
second opsiconfd mock (opsi-mock2) | opsi-config2.mock and depot2.mock, only in the Docker network |
Each mock simulates a configserver and a depot, including install, uninstall and WebDAV. opbweb-opsi-mock is the first opsi system: as long as no config server is configured, the API registers it at startup as “opsiconfd-Mock” with the stage Test (URL http://opsi-config.mock:4447, user opsiadm, password mock, without TLS verification). opbweb-opsi-mock2 is a second, independent opsi system for tests with several config servers; it is not registered automatically. To use it in the user interface, add it under Depots with + (URL http://opsi-config2.mock:4447, user opsiadm, password mock, TLS verification off).
The end-to-end tests register both mocks as config servers themselves (as “t-Mock 1” and “t-Mock 2”, if not present yet), remove them again afterwards and work only on their depots. They do not assume that the mock is the only or the default config server, and they also run when a real opsi server is configured in addition. The manual preview does not refresh by itself; reload the page after a change.
The dev and production stacks use the same container names and the same volumes. They cannot run at the same time and share database and object storage. Therefore never start the development stack on a production host. To switch, stop with ./stop.sh and start again with or without --dev.