A Linux server
x86_64 or arm64, at least 1 vCPU, 1 GB RAM and 10 GB disk. Docker Engine 24+ with the Compose v2 plugin, and git.
ZenoCookieConsent ships as containers: the web app (dashboard, public API and zeno.js), PostgreSQL, MinIO for S3 storage and Caddy for automatic HTTPS. One installer sets it all up on any Linux server with Docker, behind your own domain.
Install
The installer checks Docker, writes deploy/.env with freshly generated secrets, builds the image, starts the stack and waits until the app is healthy. Re-running it is safe: an existing .env is kept.
Create a DNS record for your consent hostname, e.g. consent.example.com, pointing at the server.
From a clone of the repository, or with the one-liner, which fetches the source into ./zenocookieconsent first. Read the script before you pipe it into a shell.
Open the setup URL the installer prints (https://consent.example.com/setup), create the administrator and add a domain.
$ git clone <repository> && cd zenocookieconsent && ./install.sh --domain consent.example.com
$ curl -fsSL https://zenocookieconsent.citiumsoftware.com/install.sh | bash
# asks for the hostname; or pass options after "bash -s --":
$ curl -fsSL https://zenocookieconsent.citiumsoftware.com/install.sh \
| bash -s -- --domain consent.example.com --yes
$ git clone <repository> && cd zenocookieconsent/deploy
$ cp .env.example .env && chmod 600 .env
# edit .env: DOMAIN, APP_URL and every "change-me" value
# (generate secrets with: openssl rand -hex 32)
$ docker compose up -d --build
Trying it locally? ./install.sh --domain localhost --port 3000 --yes runs everything on http://localhost:3000 without TLS. Then add the script tag to your site: <script src="https://consent.example.com/zeno.js"></script>
Run ./install.sh --help for the same list. Without options the installer asks for the hostname, whether to run Caddy and whether to run MinIO; with curl … | bash it asks on your terminal.
| Option | Effect |
|---|---|
--domain HOST | Public hostname of the consent service, e.g. consent.example.com. With localhost, Caddy is skipped and the app runs on plain HTTP. |
--no-caddy | Don't run the built-in HTTPS proxy. Put your own reverse proxy in front of the app port. |
--external-s3 | Don't run the built-in MinIO. Edit the S3_* values in deploy/.env afterwards and re-run. |
--port N | Host port for the app when not using Caddy (default 3000). |
--yes | Accept the defaults and ask no questions (unattended installs). |
--force | Overwrite an existing deploy/.env with newly generated secrets. |
Before you start
x86_64 or arm64, at least 1 vCPU, 1 GB RAM and 10 GB disk. Docker Engine 24+ with the Compose v2 plugin, and git.
For example consent.example.com, with a DNS record pointing at the server.
The built-in Caddy gets certificates automatically: keep ports 80 and 443 open. Or use your own proxy with --no-caddy.
PostgreSQL and MinIO are included. Prefer your own S3-compatible bucket? Use --external-s3. SMTP for invitation e-mails is optional.
What runs where
One web app, one database, one bucket, one proxy. Every request from a visitor's browser goes to your hostname and nowhere else.
/app, public API at /api/v1, and zeno.js.Day two
Pull the new source and rebuild. Database migrations run automatically on start. Check the release notes first.
git pull
cd deploy
docker compose up -d --buildNightly pg_dump backups go to object storage by default. Consent receipts are legal evidence: test your restores.
Reverse proxy examples, environment variables, monitoring and upgrades, step by step.
You become the operator. Self-hosting means the consent data never leaves your infrastructure, and also that availability, security updates and backups are in your hands. Plan for them like any other production service.
Read the operations manual, or look at the source before you install anything.