Install with Docker Compose
Docker Compose starts everything with one command: application, PostgreSQL, Redis and nginx.
Step 1 — Clone the repository
$ git clone https://github.com/openwhistle/OpenWhistle.git
$ cd OpenWhistle
Step 2 — Configure environment
At minimum set SECRET_KEY, DATABASE_URL and
REDIS_URL; every other setting is in the
configuration table.
$ cp .env.example .env
$ nano .env
# The production stack (TLS, nginx); every docker compose command below uses it:
COMPOSE_FILE=docker-compose.prod.yml
# Minimum required values. The production Redis requires REDIS_PASSWORD,
# so it goes into REDIS_URL too, as POSTGRES_PASSWORD goes into DATABASE_URL:
# openssl rand -hex 32 — a new value for each key:
SECRET_KEY=<64 hex characters>
ENCRYPTION_KEY=<64 hex characters>
POSTGRES_PASSWORD=db-password
REDIS_PASSWORD=redis-password
DATABASE_URL=postgresql+asyncpg://openwhistle:db-password@db:5432/openwhistle
REDIS_URL=redis://:redis-password@redis:6379/0
Step 3 — Start services
$ docker compose up -d
► Network openwhistle_default Created
► Container openwhistle-db-1 Started
► Container openwhistle-redis-1 Started
► Container openwhistle-app-1 Started
► Container openwhistle-nginx-1 Started
nginx serves HTTPS on 443 and redirects plain HTTP on 80. Put your
fullchain.pem and privkey.pem (e.g. from certbot) into
nginx/certs/ and restart.
- Copy them, do not symlink: a link into
/etc/letsencrypt/livedangles inside the container. - Keep the key root-owned
0600, or0644. Otherwisetls-initstops and names the path and the reason. - Without them, the one-shot
tls-initservice generates a self-signed certificate before nginx starts. It is forTLS_HOSTNAME(defaultlocalhost), a.envvariable onlydocker-compose.prod.ymlreads. After a change,docker compose up -d tls-init nginxissues and serves a new one. - To renew, drop the new certificate into
nginx/certs/and rundocker compose up -d tls-init nginx. Restartingnginxalone keeps the old one: nginx never re-readsnginx/certs/itself.
It lets the stack come up before you have a real certificate, not to serve users. A
browser that clicks through its warning gets an HSTS pin
(Strict-Transport-Security: max-age=31536000; includeSubDomains; preload) for
that hostname. Install a real certificate before anyone but you visits.
Step 4 — Run the setup wizard
Unless you set SETUP_TOKEN yourself, read the one-time setup token from the
log:
$ docker compose logs app | grep "Setup token"
Then open https://<TLS_HOSTNAME>/setup (https://localhost/setup
by default) and follow the First-Run Wizard. The account
it creates is a superadmin: it manages organisations and grants every role.
Alembic migrations run automatically at startup. The app serves no traffic until every one has been applied.
First-Run Wizard
On first boot, /setup serves the wizard: one page, four parts. Once an admin
account exists it redirects to /admin/login for good.
Wizard steps
- Admin account
A username of 3–64 characters (letters, digits, spaces and. _ @ -). A password of at least 12 characters and at most 72 bytes. - TOTP
Scan the QR code with an authenticator app (Google Authenticator, Authy, Bitwarden, etc.) and enter its 6-digit code. Mandatory; it cannot be skipped. - Installation count
Optional and unchecked: may this installation be counted once a day (what is sent)? Changeable under Admin → System.
Write down the TOTP secret shown during setup and keep it offline. There are no backup codes. A lost authenticator is reset by a superadmin or on the host (Lost password or authenticator).