Install with Docker
Run pfSense Actions with the repository's Docker Compose file, which builds the image on your host and publishes the console and API on port 22603.
Why Use This Deployment?
- Publishes port 22603 on every IPv4 and IPv6 address of the Docker host, so devices on your network can open the console. The HTTPS reverse proxy guide covers a loopback binding that limits it to the Docker host.
- Needs no passwords or keys in files, because you create the administrator account in the browser with a one-time setup code from the container log.
- Keeps the controller database and its generated encryption key on a named data volume that survives rebuilds.
- Runs the service as a non-root user under s6-overlay, with a built-in health check.
Requirements
- Docker with Compose — Docker Engine with the Compose plugin and BuildKit, on an amd64 or arm64 host.
- Repository checkout —
compose.ymlbuilds the image from the root of the pfSense Actions repository. - Prepared pfSense — SSH turned on and an account ready, as described in Prepare pfSense.
- HTTPS plan — A reverse proxy for any client that isn't on the Docker host, covered in HTTPS Reverse Proxy.
Change the Host Settings
compose.yml works without an environment file. To change the published port, the user the service runs as, or its time zone, copy the root sample file and edit it.
cp .env.sample .env
PFSENSE_ACTIONS_PORT="22603"
PGID="1000"
PUID="1000"
TZ="UTC"
Every variable and its default is listed in the Configuration Reference.
Build and Start
Build the image and start the service from the repository root.
docker compose up --build --detach
npm run deploy:container runs the same command. On the first start, pfSense Actions creates the controller database and an encryption key, which it saves as keys/installation.key in the data volume.
Find the Setup Code
While no administrator account exists, pfSense Actions prints a setup code in its log.
docker compose logs app
WARN No administrator account exists yet. Open the console at /admin/ to create it.
WARN Setup code: ABCDE-FGHJK-LMNPQ (valid until 2026-01-01T12:30:00.000Z; restart the container for a new one)
- The code works once and lasts 30 minutes, and
docker compose restart appprints a new one. - Anyone who can read the container log can use the code, so it's worth creating the account right after the first start.
Create the Administrator Account
- Open
http://<docker-host>:22603/admin/, where<docker-host>is the name or address of the machine that runs Docker. Use yourPFSENSE_ACTIONS_PORTif you changed it, or your HTTPS address once the proxy is in place. - Enter the One-time code from the log. Letter case, spaces, and dashes don't matter.
- Choose a Username and a Password of at least 12 characters, repeat the password in Confirm password, and select Create account. The bar under the field rates it from Weak to Strong, and any password of 12 or more characters is accepted.
The console signs you in right away, and the setup screen doesn't appear again.
Connect pfSense
- On Overview, select Set up the connection.
- Enter the firewall's IP address, the SSH port, and the SSH username.
- Choose Private key or Password under Sign in with, and paste the credential.
- Select Test and save.
pfSense Actions saves the connection only after it signs in with it, as described in pfSense Connection.
Create a Token
Create a personal access token with the pfsense:read scope as described in Access Tokens, and copy it while the console shows it.
Verify a Request
Send one connectivity check from the Docker host, keeping the token out of the process list.
read -r -s PFSENSE_ACTIONS_TOKEN
printf 'header = "Authorization: Bearer %s"\n' "$PFSENSE_ACTIONS_TOKEN" \
| curl --config - --silent --show-error \
--write-out '\nHTTP %{http_code}\n' \
http://127.0.0.1:22603/api/v1/connectivity
unset PFSENSE_ACTIONS_TOKEN
HTTP 200 with {"connected":true} means pfSense Actions signed in to the firewall and ran uname -mrs. HTTP 502 means the SSH sign-in or the command failed, which Troubleshooting covers.
Get Alerts
To hear when pfSense stops answering or sign-in is locked, add a notification destination on the console's Notifications page, as described in Notifications.
What the Data Volume Holds
The data volume pfsense_actions_data is mounted at /data and holds two things.
pfsense-actions.sqlite3— The controller database, with its-waland-shmfiles. It holds the administrator account with an Argon2id password hash, browser sessions, each token hash and its scopes, the encrypted pfSense connection, the encrypted TOTP secret, recovery code hashes, passkey public keys, notification destinations with their encrypted secret fields, and the activity log.keys/installation.key— The generated encryption key, readable only by the service's user. If it goes missing, pfSense Actions makes a new one and removes the saved pfSense password or private key, the authenticator app, and every destination's secret fields, as described in Backup and Recovery.
Raw tokens, raw recovery codes, and plaintext passwords or private keys aren't stored anywhere.
warning
The volume holds both the database and the key that decrypts it, so anyone with a copy of the volume can read the stored pfSense credential and notification secrets. Keep volume backups as safe as the firewall credential itself, as described in Backup and Recovery.
info
The image is built on node:24.22.0-trixie-slim, pinned by digest, with s6-overlay 3.2.3.2 downloaded from GitHub and checked against its SHA-256 checksums. Builds for any platform other than amd64 or arm64 stop with an error.