Skip to content
How to install

Configuration (deploy/.env)

deploy/.env holds what the stack needs before the panel can run: the version and channel, domains and certificates, the database, the mail relay and the owner’s first sign-in. Everything else is a panel setting, changed under Settings.

provision/setup.sh writes the file on a fresh server and never overwrites it. Some variables are read only once, on the panel’s first boot, to fill in a setting. Their comments below say so.

This page lists all 40 variables of deploy/.env.example, in its own groups and order. The 9 variables marked optional are commented out in the example. Remove the # to set one.

Variable Example value What it does
WPL7_SOURCE image What is installed, and where it comes from. provision/update.sh maintains all of these; there is normally no reason to edit them by hand.

WPL7_SOURCE=image: pull the released panel image named below (the default)
WPL7_SOURCE=build: compile the panel from this checkout instead (provision/build.sh sets this; provision/deploy.sh is the update path for it)
WPL7_VERSION empty The version this install reports and compares against releases. In image mode it must name a published release - nothing here invents one.
WPL7_IMAGE_TAG empty The tag those images were published under. Same as WPL7_VERSION for a release; edge for the rolling build of main, which calls itself 0.x.y-edge.<commit> but is published under a tag that moves.
WPL7_CHANNEL stable stable = releases | edge = the rolling build of main. Only changes which release the panel offers to update to; it is applying an update that changes what is installed.
WPL7_PANEL_IMAGE
optional
ghcr.io/andyfo/wpl7/panel Override to run a fork’s or a mirror’s images. Repository only, without the tag.
WPL7_WORDPRESS_IMAGE
optional
ghcr.io/andyfo/wpl7/wordpress See WPL7_PANEL_IMAGE above.
WPL7_REPO
optional
andyfo/wpl7 Where releases are looked up (GitHub owner/name). Change it with the images above.
WPL7_GITHUB_TOKEN
optional
empty Fine-grained read-only token, only needed while the repository is private. It also makes the panel’s hourly check free of GitHub’s rate limit, which an anonymous one is not.
WPL7_COMMUNITY_URL
optional
https://wpl7.com/community The project’s community: linked from the panel’s About and Support pages, and where “a question or an idea” in its feedback dialog is posted. Empty it to offer neither.
Variable Example value What it does
SERVER_ROLE main main = panel + sites (the default single-server install) | worker = sites only, driven by the central panel over SSH (compose.sh then skips the panel container).
Variable Example value What it does
PANEL_DOMAIN panel.example.com Hostname of the admin panel (A record → this server).
DEV_DOMAIN dev.example.com Dedicated dev domain. Every new site defaults to <slug>.${DEV_DOMAIN}. Requires a wildcard DNS record: *.dev.example.com → this server.
ACME_EMAIL [email protected] Let’s Encrypt account email.
TLS_MODE letsencrypt letsencrypt = production certs | staging = LE staging (testing) | none = plain HTTP (local dev) NOTE: TLS_MODE only decides http vs https; it does NOT pick the ACME CA. For staging certificates set ACME_RESOLVER=letsencrypt-staging as well.
ACME_RESOLVER letsencrypt Which ACME CA issues certificates: letsencrypt | letsencrypt-staging. Applies to the panel, custom-domain sites AND the dev wildcard certificate.
SERVER_PUBLIC_IP empty Public IPv4 of this server; used for DNS preflight warnings (auto-detected by setup.sh).
Section titled “DNS: wildcard cert for dev sites, panel-managed records (optional, recommended)”
Variable Example value What it does
DNS_PROVIDER empty Cloudflare is set up in the panel, under Settings → DNS: its API token (Zone → Zone → Read and Zone → DNS → Edit), and per server whether dev sites share one *.${DEV_DOMAIN} wildcard certificate over DNS-01 instead of one HTTP-01 certificate each. The same token lets the panel manage per-site records across servers and publish SPF/DKIM/DMARC (docs/dns.md).

CF_DNS_API_TOKEN below is read ONCE, on the panel’s first boot, to fill that in - after that Settings → DNS owns the token, and editing it here changes nothing.

DNS_PROVIDER is the provider Traefik’s DNS-01 resolver uses; empty means cloudflare. Another provider (https://doc.traefik.io/traefik/https/acme/#providers, e.g. hetzner) works for the wildcard certificate with its credentials here, but the panel writes records through Cloudflare only.
CF_DNS_API_TOKEN
optional
empty See DNS_PROVIDER above.
HETZNER_API_KEY
optional
empty See DNS_PROVIDER above.
DO_AUTH_TOKEN
optional
empty See DNS_PROVIDER above.
Variable Example value What it does
SRV_ROOT /srv All persistent state lives under this root (sites, backups, mysql, traefik, panel, plugins).
BACKUP_ROOT
optional
/mnt/backups Optional: keep THIS server’s backups somewhere other than ${SRV_ROOT}/backups - a second disk, a large volume. Setting it makes compose.sh mount that path into the panel container at the identical path (docker-compose.backup-root.yml), which is the only way the panel can write there; recreate the panel afterwards (./provision/compose.sh up -d panel).

Needed only on the machine running the panel. Worker servers take any path straight from Panel → Backups → Storage. And if the disk is not in use yet, the simplest option is to mount it AT ${SRV_ROOT}/backups and leave this unset.
Variable Example value What it does
MARIADB_ROOT_PASSWORD empty
MARIADB_BUFFER_POOL 256M
MARIADB_MAX_CONNECTIONS 300
Variable Example value What it does
MAIL_HOSTNAME mail.example.com PHP mail() works on every site out of the box: the site image relays through the per-server postfix container, which signs with DKIM and delivers. Panel → Mail shows health, full traffic and the DNS records each customer domain needs (docs/mail.md).

Hostname postfix announces (set an A record + reverse DNS to this server for direct mode). Any name you control - it need not sit under the panel’s domain. This is the default: a name set in Panel → Mail → Setup guide overrides it (via /srv/mail/relay.env) until you reset it there. See “Changing the mail hostname” in docs/mail.md.
SMTP_RELAYHOST empty Smarthost mode (recommended): relay through one SMTP account, e.g. [smtp.eu.mailgun.org]:587 Leave empty for direct MX delivery (your VPS provider must allow outbound port 25; set rDNS + SPF or expect spam folders — see docs/mail.md).
SMTP_USERNAME empty See SMTP_RELAYHOST above.
SMTP_PASSWORD empty See SMTP_RELAYHOST above.
Variable Example value What it does
PANEL_SESSION_SECRET empty Cookie/session signing secret (openssl rand -hex 24).
PANEL_ADMIN_USER admin The owner account, which the FIRST boot creates from these (the name is seeded, the password seeds the hash). Afterwards change either in the panel UI - Users → your account, where everyone else gets an account too - and editing these lines has no effect. The one exception: an owner password hash blanked by hand is re-seeded from PANEL_ADMIN_PASSWORD (docs/troubleshooting.md).
PANEL_ADMIN_PASSWORD empty See PANEL_ADMIN_USER above.

Defaults seeded into panel settings on first boot (editable in the UI afterwards)

Section titled “Defaults seeded into panel settings on first boot (editable in the UI afterwards)”
Variable Example value What it does
BACKUP_CRON 0 3 * * *
BACKUP_RETENTION 10
WP_DEFAULT_PHP 8.3
WP_PHP_VERSIONS 8.2,8.3,8.4,8.5
WP_DEFAULT_LOCALE en_US Any wp.org locale code (cs_CZ, de_DE_formal, pt_PT_ao90 …); the panel’s language picker offers WordPress’s full list. Editable later under Settings → Sites.
WP_DEFAULT_PLUGINS empty Comma-separated wp.org plugin slugs preselected for new sites (optional). WordPress’s own bundled plugins (Akismet, Hello Dolly) are removed from every new site regardless.
Variable Example value What it does
WPL7_CATALOG_URL empty Plugin recipes (how the panel activates ACF PRO, Breakdance, … licenses) ship with the panel and are also published as a signed public catalog the panel fetches hourly, so a new or corrected recipe reaches this install without a software update. Empty = the official catalog. off = never fetch; use only the recipes bundled with this version. A fork that publishes its own catalog puts its index URL here and its public key below.
WPL7_CATALOG_PUBLIC_KEY empty Ed25519 public key (SPKI) the index must be signed with; empty = the official key. Put just the base64 body of the PEM on this one line - a multi-line PEM does not survive an env file - or the PEM with its line breaks written as literal \n.