PiVPN Web is configured entirely through environment variables passed to the Docker container at startup. There are no configuration files to edit — set the variables you need in yourDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/AZhur771/pivpn-web/llms.txt
Use this file to discover all available pages before exploring further.
docker run command or docker-compose.yml and the application picks them up automatically. The sections below cover every supported variable, user role semantics, TLS setup, and session secret behaviour.
Environment variables
Server
The TCP port the Express.js web server listens on inside the container. Map
this to a host port with Docker’s
-p flag (e.g. -p 8080:3001 to expose
the dashboard on port 8080 of the host).Set to any non-empty value (e.g.
"true") to mark the session cookie as
secure: true. This is required when PiVPN Web is served over HTTPS — the
browser will refuse to send a secure cookie over plain HTTP. Leave unset
for HTTP-only deployments. See the TLS / HTTPS section for
details.Unlike most other variables, IS_SECURE is read directly from
process.env.IS_SECURE inside Server.ts and is not exported from
config.ts.The secret used to sign the
express-session cookie. If not provided, a
random value is generated at startup. See the Session secret
section for the implications of leaving this unset.SSH connection
IP address or hostname of the PiVPN WireGuard host the container will connect
to over SSH. Every WireGuard operation is executed remotely via this
connection. If PiVPN runs on the same physical machine as Docker, use the
host’s LAN IP or
host.docker.internal (see the Quickstart for details).The SSH port on the target host. Override only if your PiVPN host runs SSH on
a non-standard port.
The Linux username used to authenticate the SSH session. This user must have
permission to run
pivpn commands on the target host (typically the user
who owns the PiVPN installation).The password for the SSH user specified in
SSH_USER. The connection is
established using password authentication via the node-ssh library.Admin account
The login username for the primary admin account created at first startup.
Admin accounts have full access to all dashboard features including creating,
deleting, enabling, and disabling WireGuard clients.
The password for the admin account. Stored as a
bcryptjs hash (10 salt
rounds) in the SQLite database — the plaintext value is never persisted.Viewer account
VIEWER_USER, VIEWER_PASSWORD, TECH_USER, and TECH_PASSWORD are not
listed in the original README environment variable table. They are
defined in config.ts and seeded by separate TypeORM migrations added after
the initial release.The login username for the read-only viewer account seeded alongside the
admin account on first startup. The TypeORM migration that creates this
account runs unconditionally — if
VIEWER_USER is not set, the record is
inserted with a null login. Set this variable to a meaningful username so
the viewer account is usable. See User roles for what a viewer
can and cannot do.The password for the viewer account. Should always be set alongside
VIEWER_USER. Stored as a bcryptjs hash in the same migration that creates
the admin account.Tech account
The login username for a secondary admin-level account seeded by a separate
TypeORM migration at first startup. Like the viewer account, the migration
runs unconditionally — if
TECH_USER is not set, the record is inserted with
a null login. Set this variable to a meaningful username so the tech account
is usable. See User roles for details.The password for the tech account. Should always be set alongside
TECH_USER.
Stored as a bcryptjs hash (10 salt rounds) in the SQLite database.User roles
PiVPN Web has two distinct privilege levels, stored in theadmin boolean column of the user table.
Admin (admin = true)
Full access to all API endpoints. Admin accounts can list clients, create new peers, delete peers, enable/disable peers, retrieve QR codes, and download configuration files. Both ADMIN_USER and TECH_USER are seeded as admin-level accounts.
Viewer (admin = false)
Read-only access. Viewer accounts can list clients, view connection status, retrieve QR codes, and download configuration files. They cannot create, delete, enable, or disable clients — any attempt returns 403 Not enough rights. VIEWER_USER is seeded as a viewer account.
The privilege check is enforced server-side in Server.ts via validateSession(req.session, true), which verifies the isAdmin flag stored in the session before allowing any write operation.
| Account variable | Role | Can write? |
|---|---|---|
ADMIN_USER | Admin | ✅ Yes |
TECH_USER | Admin | ✅ Yes |
VIEWER_USER | Viewer | ❌ No |
TLS / HTTPS
PiVPN Web does not handle TLS termination itself. To serve the dashboard over HTTPS:- Place the container behind a reverse proxy such as nginx or Caddy that handles the TLS certificate and forwards requests to the container on port
3001. - Set
IS_SECUREto any non-empty value when starting the container. This causes the session cookie to be sent withsecure: true, which prevents the browser from transmitting it over unencrypted HTTP connections.
IS_SECURE is set, the session cookie is configured as:
Session secret
TheSECRET environment variable controls the signing key for express-session cookies. When not set, the server generates a random value at startup:
SECRET:
Even with a stable
SECRET, sessions are persisted to the SQLite database via
typeorm-store. If the database file is not mounted as a Docker volume,
session data will still be lost when the container is recreated. Mount the
database directory as a named volume to achieve full persistence.