Configuration
Environment variables and panel settings.
Environment variables
Set in /opt/zefira/.env (installer-managed, mode 600) or exported before start:
| Variable | Default | Purpose |
|---|---|---|
ZEFIRA_ADMIN_USERNAME | admin | First-run admin (lowercased, validated) |
ZEFIRA_ADMIN_PASSWORD | random | First-run password, one-time: auto-scrubbed from .env on first boot (random if empty) |
ZEFIRA_DOMAIN | — | Public domain baked into configs & links |
ZEFIRA_PORT | 8000 | Panel listen port (systemd unit) |
ZEFIRA_SUB_PORT | 443 | Port in VLESS/VMess/Trojan/SS links |
ZEFIRA_HY2_PORT | 8443 | Port in Hysteria2 links |
ZEFIRA_WG_PORT | 51820 | WireGuard endpoint port |
ZEFIRA_DNS | 1.1.1.1 | DNS in WireGuard configs |
ZEFIRA_OVPN_PORT / ZEFIRA_OVPN_PROTO | 1194 / udp | OpenVPN endpoint |
DATABASE_URL | SQLite | mysql+pymysql://… or postgresql+psycopg2://… (MySQL: use utf8mb4 charset, or emoji notes break inserts) |
SUBSCRIPTION_PATH | /sub | Subscription URL prefix |
ZEFIRA_SESSION_TTL | 28800 | Login session lifetime, seconds (clamped to 5 min – 7 days, default 8h) |
ZEFIRA_TRUSTED_PROXIES | empty | CIDRs allowed to send X-Forwarded-For. 0.0.0.0/0, multicast and overly-broad ranges (< /8 v4, < /32 v6) are refused/ignored. Example: 127.0.0.1 |
ZEFIRA_ALLOW_UPDATE | 1 | 0 disables the in-panel updater entirely |
ZEFIRA_ALLOW_CUSTOM_REPO | 0 | 1 allows ZEFIRA_UPDATE_REPO/BRANCH overrides (default: pinned to mrlurix/zefira-panel@main) |
TG_BOT_TOKEN / TG_CHAT_ID | empty | Telegram notifications |
Panel settings
Settings → Server / Hosts edits domain, ports, DNS, WireGuard public key, REALITY SNI list, obfuscation and CDN options live (no restart). L2TP/IPsec, Cisco AnyConnect and SOCKS5 each have their own port field; their credentials are generated per user (L2TP also gets a per-user IPsec PSK) and delivered as config text files plus dashboard cards — SOCKS5 additionally ships as socks5:// links and a Clash proxy. Settings → Tunnel sets the public URL and trusted proxies — the latter decides whose X-Forwarded-For is believed for rate limiting and audit logs.
Every server setting, by its stored name
The same values are readable and writable through GET/PUT /api/settings, and they are what a backup or a hand-edited row contains. Use these names, not the labels on the page.
| Key | Default | What it changes |
|---|---|---|
domain | empty | Public host baked into every link and config |
sub_port | 443 | Port written into VLESS / VMess / Trojan / Shadowsocks links |
hy2_port | 8443 | Port written into Hysteria2 links |
wg_port | 51820 | WireGuard endpoint port |
wg_pub | empty | Your WireGuard public key; without it the panel keeps the one it generated |
dns | 1.1.1.1 | Resolver pushed into WireGuard configs |
ovpn_port / ovpn_proto | 1194 / udp | OpenVPN endpoint, and whether it is UDP or TCP |
l2tp_port | 1701 | L2TP/IPsec port (credentials are generated per user) |
cisco_port | 443 | Cisco AnyConnect port |
socks5_port | 1080 | SOCKS5 port, also emitted as socks5:// links and a Clash proxy |
reality_port | 443 | REALITY listener port |
reality_sni | www.yahoo.com,www.samsung.com,www.microsoft.com | Comma-separated SNI list, rotated across the generated links |
reality_pub | empty | REALITY public key; the matching private key is stored encrypted and reveal is audit-logged |
obfuscated_host | empty | Decoy host that replaces your domain inside the configs (leave empty to use the real domain) |
per_user_subdomain | 0 | Prefixes a per-user hash so two customers' configs are not correlatable. Needs a wildcard DNS record, and it is skipped on IP literals — a prefixed IP resolves nowhere |
cdn_enabled | 0 | Turns on CDN SNI spoofing |
cdn_sni | empty | The CDN domain shown as TLS SNI while traffic still goes to your obfuscated host |
block_direct_ip | 0 | Answers 403 to panel and API requests that arrive on a raw IP. Turn it on only once the domain works — while testing it locks you out of your own panel |
stream or TCP/UDP pass in your vhost — the nginx site the installer writes proxies the panel port only.HTTPS / SSL
- During install (step 7): Nginx reverse proxy + Let's Encrypt with auto-renew cron.
- From the panel (Settings → SSL): request or renew a certificate for
domainorsub.domain— standalone HTTP-01 on port 80, expiry shown in the panel.
sudo on PATH). The certificate is stored, not deployed: your nginx vhost keeps the paths from install time, so point ssl_certificate at the new files and reload nginx yourself. Easier: let step 7 of the installer issue and wire everything.X-Forwarded-Proto from localhost/trusted proxies, so cookies get the Secure flag and HSTS is emitted.Data locations
| Path | Content |
|---|---|
/opt/zefira/.env | Secrets (600) |
/opt/zefira/instance/zefira.db | SQLite database (600) |
/opt/zefira/instance/secret.key | JWT + encryption master key (600) — lose it and encrypted secrets become unreadable |
/opt/zefira/instance/ca.key / ca.crt | OpenVPN certificate authority |
ZEF