Install
Install Ingressi
Ingressi runs as a Docker Compose stack: the dashboard, Caddy, ClickHouse for analytics and a few small helpers. Images are published for amd64 and arm64.
Requirements
- A Linux server with Docker Engine and the Docker Compose plugin.
- Ports 80 and 443 reachable from the Internet, and DNS records for your domains pointing at the server, so Caddy can obtain certificates. With a DNS provider configured, DNS-01 also works for servers that are not reachable from the Internet.
- The dashboard listens on port 3000, published on every interface by default. Keep it off untrusted networks (publish it as
127.0.0.1:3000:3000, or block it in a firewall that applies to Docker's published ports), and reach the dashboard through a proxy host. - Optional: a free MaxMind account, for countries and networks in analytics, access lists and geo blocking.
Quick start
Get the compose file
git clone https://github.com/ingres-si/ingressi.git cd ingressi cp .env.example .envSet the secrets
Edit
.envand fill in these values. Docker Compose stops on an empty one, and the web container refuses to start with an example secret, aSESSION_SECRETshorter than 32 characters or a weak admin password.# .env: the three values to fill in (ADMIN_USERNAME is already set) SESSION_SECRET= # openssl rand -base64 32 ADMIN_USERNAME=admin ADMIN_PASSWORD= # 12+ characters: upper and lower case, a digit, a symbol CLICKHOUSE_PASSWORD= # openssl rand -base64 32Every other setting in
.env.exampleis explained where it is defined.Start it
docker compose up -dSign in
Open
http://<your-server>:3000/loginand sign in withADMIN_USERNAMEandADMIN_PASSWORD. On a fresh install, the overview page shows a checklist of first steps: a domain pointing at the server, the first proxy host, analytics, a teammate and single sign-on. Setup checklist
Configuration, environment variables and every feature are described in the README and the documentation.
Countries and networks (optional)
Country, continent and AS number rules, and the countries and networks in analytics, use MaxMind's free GeoLite2 databases. Create a MaxMind account and a license key, add the geoipupdate profile in .env, then run docker compose up -d again. The databases are refreshed every 72 hours.
COMPOSE_PROFILES=clickhouse,geoipupdate
GEOIPUPDATE_ACCOUNT_ID= # from your MaxMind account
GEOIPUPDATE_LICENSE_KEY=PostgreSQL (optional)
The dashboard keeps its data in SQLite by default, one file in the data volume. It can use PostgreSQL 16 or later instead, free in every edition. To run the bundled PostgreSQL next to the stack (Docker Compose 2.24 or later), add a password of letters and digits to .env and start with the override file:
echo "POSTGRES_PASSWORD=$(openssl rand -hex 32)" >> .env
docker compose -f docker-compose.yml -f docker-compose.postgres.yml up -dYour own PostgreSQL server works too, and the copy tool moves an existing install from SQLite. Several dashboard replicas on one PostgreSQL database are part of high availability (Enterprise). PostgreSQL
Verify the images
Every release image is signed with Sigstore cosign by the release workflow. To check one before running it:
cosign verify ghcr.io/ingres-si/ingressi-web:latest \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github\.com/ingres-si/ingressi/\.github/workflows/docker-build-trusted\.yml@refs/(heads|tags)/'More on signatures and SBOMs: Security.
Upgrade
docker compose pull && docker compose up -ddocker compose restart does not re-read .env; use up -d. With several dashboard replicas on PostgreSQL, stop every replica before you start the new version, and do not let an image updater replace them one at a time. Before upgrading across releases, read the upgrade notes in the README.
Upgrading from Caddy Proxy Manager
Caddy Proxy Manager is now called Ingressi, and the rename reaches the names the product uses on the wire and on disk. Every old name keeps working for existing installs, so most upgrades need no action: pull and recreate as above. The main renames:
| What | Old name | New name | After the upgrade |
|---|---|---|---|
| Identity headers sent to upstreams by forward auth | X-CPM-User, -Email, -Groups, -User-Id | X-Ingressi-User, … | Still sent with the same values, but deprecated: move upstreams to the new names. |
| Docker images | ghcr.io/fuomag9/caddy-proxy-manager-{web,caddy,l4-port-manager} | ghcr.io/ingres-si/ingressi-{web,caddy,l4-port-manager} | Every release is pushed under both names, so watchtower and old compose files keep updating. |
Container names in docker-compose.yml | caddy-proxy-manager-* | ingressi-* | Scripts that address containers by name need the new names once you use the new compose file. |
| SQLite database file | caddy-proxy-manager.db | ingressi.db | Renamed on start when the new file does not exist yet; a compose file naming the old file keeps using it. |
| Forward-auth session cookie | _cpm_fa | _ingressi_fa | Still accepted, so nobody is signed out. |
Prometheus server label | cpm | ingressi | Changed: update dashboards and alerts that filter on it. |
| Default ClickHouse user | cpm | ingressi | The bundled ClickHouse needs nothing. If you run your own and never set CLICKHOUSE_USER, set CLICKHOUSE_USER=cpm. |
| REST field for forward auth on proxy hosts | cpmForwardAuth | ingressiForwardAuth | Still accepted and returned, but deprecated. Sending both with different values is refused. |
Docker volume names and environment variables stay as they were. Upgrade in the directory you installed from: Docker Compose names the volumes after it, so a fresh clone into a new directory (such as ingressi) would start with empty volumes, unless COMPOSE_PROJECT_NAME is set to the old directory's name. The repository is now ingres-si/ingressi; GitHub redirects its old address. Every rename
Installing a license key
Paid features need a license key. Open License in the dashboard (at the bottom of the sidebar, next to Settings), paste the key or choose the key file, and select Verify key: the dashboard shows the edition, nodes, expiry and features it grants before anything changes. Install key applies it. With the REST API: PUT /api/v1/license with {"key": "…"} (permission license:write).
The key is verified on your server and never calls home. Renewed keys can install themselves if you turn on automatic updates on the License page (off by default; how it works). For hosts without Internet access, the Enterprise edition includes an offline install bundle: Air-gapped installs.