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

  1. Get the compose file

    git clone https://github.com/ingres-si/ingressi.git
    cd ingressi
    cp .env.example .env
  2. Set the secrets

    Edit .env and fill in these values. Docker Compose stops on an empty one, and the web container refuses to start with an example secret, a SESSION_SECRET shorter 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 32

    Every other setting in .env.example is explained where it is defined.

  3. Start it

    docker compose up -d
  4. Sign in

    Open http://<your-server>:3000/login and sign in with ADMIN_USERNAME and ADMIN_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 -d

Your 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 -d

docker 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 the rename changed
WhatOld nameNew nameAfter the upgrade
Identity headers sent to upstreams by forward authX-CPM-User, -Email, -Groups, -User-IdX-Ingressi-User, …Still sent with the same values, but deprecated: move upstreams to the new names.
Docker imagesghcr.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.ymlcaddy-proxy-manager-*ingressi-*Scripts that address containers by name need the new names once you use the new compose file.
SQLite database filecaddy-proxy-manager.dbingressi.dbRenamed 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_faStill accepted, so nobody is signed out.
Prometheus server labelcpmingressiChanged: update dashboards and alerts that filter on it.
Default ClickHouse usercpmingressiThe 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 hostscpmForwardAuthingressiForwardAuthStill 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.