Quickstart
Run the released control plane with Docker Compose or the release binaries, then enroll an agent on a Linux host.
Run the control plane
Important
Before you start: decide where the agents will run. If any agent will run on a machine other than the one running the control plane (always the case when Docker runs on macOS or Windows), first read Name the control plane before the first start. The gateway’s certificate is generated once, at the first start, and names only that machine’s local names.
The supported deployment is one control-plane binary and one Postgres (ADR-0017). Run the released image with Docker Compose, or install the released binaries. The commands below install v0.4.1, the release these docs describe.
With Docker Compose
git clone https://github.com/innerwall-dev/innerwall.git
cd innerwall
git checkout v0.4.1 # the release these docs describe; a fresh clone is main
echo 'INNERWALL_IMAGE=ghcr.io/innerwall-dev/innerwall:0.4.1' > .env
docker compose up -d # pulls the released control-plane image and starts it with Postgres.env (git ignores it) names the image for every later docker compose command. Compose keys the stack’s volumes by the directory’s name, so a clone into a directory named innerwall picks up whatever state an earlier innerwall stack left behind. To start clean beside it, add COMPOSE_PROJECT_NAME=<a new name> to .env before the first start (troubleshooting).
Set the operator password. The command line on the host is the only place it can be set:
docker compose exec innerwall /innerwall operator set-passwordIt prompts twice, without echo. Open https://localhost:8080/ and log in. The certificate is self-signed: before you accept it, compare the SHA-256 fingerprint the browser shows with the sha256_fingerprint in docker compose logs innerwall | grep "operator listener certificate".
docker compose up -d never builds: it runs the image .env names, pulled if it is not already present. Without INNERWALL_IMAGE in .env, every docker compose command stops with an error that names the line to add.
make dev is the fallback: it builds the image from the checkout, console embedded. It ignores INNERWALL_IMAGE and names its build innerwall:dev, never a release’s image name.
With the release binaries
Download innerwall_0.4.1_<os>_<arch>.tar.gz (Linux or macOS), verify it and install it as Versioning and install shows. Then, with a reachable Postgres:
export INNERWALL_DATABASE_URL='postgres://innerwall:innerwall@127.0.0.1:5432/innerwall?sslmode=disable'
innerwall migrate
innerwall operator set-password
innerwall serve --init-ca --ca-dir ./state/ca --site lab --gateway-advertise-address localhost:8443On first start, --init-ca creates the signing authority in ./state/ca, with the listeners’ certificates beside it. Then open https://localhost:8080/ and compare the fingerprint in the operator listener certificate log line as above.
To build from source instead, you need Go (the version go.mod names) and Node 22 for the console:
make console # builds the console into ui/dist/
make build # bin/innerwall and bin/innerwall-agent, the console embeddedUse bin/innerwall and bin/innerwall-agent where this page says innerwall and innerwall-agent. make build-noconsole builds without Node; that binary serves the API and no console.
Enroll an agent
The agent runs on Linux as root, with nftables. It needs a provisioning token and the signing authority’s certificate, delivered together out of band. Mint a token in the console (Workloads → Provisioning tokens → Mint token; the dialog shows the enroll command with your gateway address filled in) or on the command line, and fetch the certificate:
# Docker Compose
docker compose exec innerwall /innerwall token mint --name lab --label app=demo
docker compose cp innerwall:/var/lib/innerwall/ca/ca.crt ./ca.crt
# release binaries
innerwall token mint --name lab --label app=demo
cp ./state/ca/ca.crt ./ca.crtOn the host to protect, download the agent, verify it against the release’s signed checksums, and install it (ARCH is amd64 or arm64):
VERSION=0.4.1 ARCH=amd64
ASSET=innerwall-agent_${VERSION}_linux_${ARCH}.tar.gz
base=https://github.com/innerwall-dev/innerwall/releases/download/v$VERSION
for f in "$ASSET" checksums.txt checksums.txt.sig checksums.txt.pem; do curl -fsSLO "$base/$f"; done
cosign verify-blob checksums.txt --signature checksums.txt.sig --certificate checksums.txt.pem \
--certificate-identity "https://github.com/innerwall-dev/innerwall/.github/workflows/release.yml@refs/tags/v$VERSION" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
awk -v f="$ASSET" '$2 == f' checksums.txt | sha256sum -c
tar -xzf "$ASSET" innerwall-agent
sudo install -m 0755 innerwall-agent /usr/local/bin/innerwall-agentcosign verify-blob (cosign 2.x) prints Verified OK only if checksums.txt was signed by the release workflow at that tag, and sha256sum -c prints OK only if the archive is the one it lists. Neither binary checks for updates or sends telemetry. Then enroll and run the agent:
sudo innerwall-agent enroll --server localhost:8443 --token <provisioning-token> --bootstrap-ca ca.crt
sudo innerwall-agent daemon --server localhost:8443On another host, use the control plane’s address instead of localhost; the gateway’s certificate must name it (--tls-hosts, set before the control plane first starts). Flow byte counts read zero until the kernel’s per-connection byte accounting is on: sudo sysctl -w net.netfilter.nf_conntrack_acct=1 (troubleshooting).
Next
The workload appears in the console’s fleet, synced, in visibility mode: its connections are observed and nothing is blocked. From there, write a ruleset, move workloads to simulation, read the simulation review, and promote. Visibility, simulation, enforcement explains each step.
sudo innerwall-agent down removes the agent’s firewall table at any time, without the control plane. Running Innerwall in production, with more than one replica and behind load balancers, is in Deploy & operate.