Docker & Compose
Run Openbeehive as a single container for a self-host setup, or bring up the full cloud stack (Postgres and MinIO) with Docker Compose.
The image is published to the GitHub Container Registry on every release tag:
ghcr.io/openbeehive-org/openbeehive-app:latest # newest release
ghcr.io/openbeehive-org/openbeehive-app:X.Y.Z # a specific release
ghcr.io/openbeehive-org/openbeehive-app:X.Y # newest patch of a minor release
The same image serves both deployment profiles; the environment you pass in decides which one you get. Since 0.4.0 the container runs as the unprivileged user 65532 with /data as its working directory.
Verifying a release image
Every release image is signed with cosign (keyless, bound to the release workflow's identity), carries a GitHub build-provenance attestation and ships an SBOM on the GitHub release. To check that the image you pull is the one the release workflow built:
cosign verify ghcr.io/openbeehive-org/openbeehive-app:X.Y.Z \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github.com/openbeehive-org/openbeehive-app/\.github/workflows/release\.yml@.*'
gh attestation verify oci://ghcr.io/openbeehive-org/openbeehive-app:X.Y.Z --owner openbeehive-org
Both commands print the signing identity and the commit the image was built from. Images published before 0.4.0 are not signed.
For a single-user instance on one machine the single binary is even simpler than Docker. Reach for Compose when you want Postgres and S3-style storage.
Run the single container
One container with the selfhost profile keeps a SQLite database and the uploaded blobs on one mounted volume. Nothing else is required.
docker run -d \
--name openbeehive \
-p 8080:8080 \
-v openbeehive-data:/data \
-e BEEHIVE_DEPLOYMENT_PROFILE=selfhost \
-e BEEHIVE_PUBLIC_BASE_URL=https://bees.example.com \
-e 'BEEHIVE_DATABASE_DSN=file:/data/openbeehive.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)' \
-e BEEHIVE_BLOB_DIR=/data/blobs \
ghcr.io/openbeehive-org/openbeehive-app:latest
-p 8080:8080maps the container's listen port (BEEHIVE_ADDR=:8080) to the host.-v openbeehive-data:/datakeeps your data on a named volume. Docker creates the volume with the ownership of/datain the image, so the unprivileged server user can write to it. If you bind-mount a host directory instead (-v /srv/openbeehive:/data), it must be owned by uid65532:sudo chown -R 65532:65532 /srv/openbeehive.- The
BEEHIVE_DATABASE_DSNandBEEHIVE_BLOB_DIRlines point the database and the uploaded photos at the volume explicitly. The defaults (openbeehive.db,./data/blobs) are relative to the working directory, which is/datasince 0.4.0, but spelling the paths out keeps the command unambiguous and matches the backup instructions. BEEHIVE_PUBLIC_BASE_URLmust be the address users reach, including scheme. The server uses it for OIDC redirect URLs and for invite and verification links.
With no login method enabled (the selfhost default) the instance runs in single-user mode. To add authentication, set BEEHIVE_SESSION_SECRET (generate it once with openssl rand -base64 32 and keep it stable; changing it signs everyone out) plus the variables for the method you want. Email/password login also needs BEEHIVE_ADMIN_EMAIL and BEEHIVE_ADMIN_PASSWORD, or the server refuses to start. See Authentication.
Using an env file
docker run -d \
--name openbeehive \
-p 8080:8080 \
-v openbeehive-data:/data \
--env-file openbeehive.env \
ghcr.io/openbeehive-org/openbeehive-app:latest
The cloud profile with Compose
The cloud profile pairs the server with PostgreSQL and MinIO. The repository's docker-compose.yml is a development stack: it builds the server from source and publishes the database and MinIO ports on the host.
git clone https://github.com/openbeehive-org/openbeehive-app.git
cd openbeehive-app
cp .env.example .env # then edit .env (see below)
docker compose up -d --build
The services
| Service | Image | Role |
|---|---|---|
server | built from the repository Dockerfile | Backend and web app on :8080 |
postgres | postgres:18-alpine | Database; 5432 published on the host |
minio | minio/minio:latest | S3-compatible blob storage; 9000 (API) and 9001 (console) published on the host |
server depends on postgres and minio, so Compose starts them first.
What the compose file sets
These values are hard-coded in docker-compose.yml and are not read from .env; change them by editing the file (and change the Postgres and MinIO credentials in the same place):
| Setting | Value in the compose file |
|---|---|
BEEHIVE_DEPLOYMENT_PROFILE | cloud |
BEEHIVE_DATABASE_DSN | postgres://openbeehive:openbeehive@postgres:5432/openbeehive?sslmode=disable |
BEEHIVE_MINIO_ENDPOINT | minio:9000 |
BEEHIVE_MINIO_ACCESS_KEY / BEEHIVE_MINIO_SECRET_KEY | minioadmin / minioadmin |
BEEHIVE_OIDC_PROVIDERS | google |
These come from your shell or .env:
# Required: the cloud profile enables password auth, which needs the instance admin.
# docker compose up fails immediately if either is missing.
BEEHIVE_ADMIN_EMAIL=you@example.com
BEEHIVE_ADMIN_PASSWORD=at-least-eight-characters
# Sessions; generate with: openssl rand -base64 32
BEEHIVE_SESSION_SECRET=
# Defaults to http://localhost:8080
BEEHIVE_PUBLIC_BASE_URL=https://bees.example.com
# Google is enabled as an OIDC provider in the compose file, so these are
# required too; without a client ID the server exits with
# "OIDC provider google: issuer/client id missing". Remove the BEEHIVE_OIDC_*
# lines from docker-compose.yml if you do not want Google sign-in.
BEEHIVE_OIDC_GOOGLE_CLIENT_ID=...
BEEHIVE_OIDC_GOOGLE_CLIENT_SECRET=...
:::note Service names are hostnames
Inside the Compose network, containers reach each other by service name, which is why the DSN points at postgres and the MinIO endpoint at minio.
:::
A production-shaped file
docker-compose.demo.yml in the repository is the file behind the hosted instance: it uses the published image instead of building, publishes no database or MinIO ports, adds restart policies and healthchecks, takes every secret from .env, closes registration (invite-only) and enables the demo tenant. Its header comment lists the variables it needs. Use it as the starting point for your own production stack:
docker compose -f docker-compose.demo.yml up -d
For the full list of variables see Configuration.
Persisting your data
- Single container (
selfhost): everything is under/dataon theopenbeehive-datavolume, as long as the DSN and blob directory point there. - Cloud profile: records live in the
pgvolume (Postgres) and uploaded files in theminiovolume. The server container is stateless and can be replaced freely.
:::danger Back up before you upgrade
Named volumes survive docker compose up and image upgrades, but not docker compose down -v or a removed volume. Take a backup before any upgrade or destructive command. See Backups.
:::
Common operations
# Follow the server logs
docker compose logs -f server
# Rebuild from updated source and recreate (docker-compose.yml builds the image)
git pull && docker compose up -d --build
# Pull a newer published image and recreate (docker-compose.demo.yml or your own file)
docker compose -f docker-compose.demo.yml pull
docker compose -f docker-compose.demo.yml up -d
# Stop everything (volumes are kept)
docker compose down