Repository navigation
Install the panel
Download or build Mistgate, prepare the panel with mistgate setup, run it under systemd and sign in for the first time.
This page takes a fresh Linux server to a running panel with an owner account. The examples use panel.example.com; check Requirements first. Commands on the panel server run as root. An AI agent with SSH access to the server can do the same steps for you: see the install prompt in the AI agent guide.
Note
this page is for a panel on a server of your own. To run the panel on Cloudflare Workers instead, with no server (a preview), see Install the Cloudflare edition.
For a fresh Linux server on amd64 or arm64 with systemd, run this as root. The domain must point directly at the server and TCP ports 80 and 443 must be free. Signature verification needs either openssh-client with ssh-keygen -Y verify support or OpenSSL 3.2 or newer. The installer downloads the latest release, checks the binary against SHA256SUMS and the signed panel manifest, then runs setup and installs the systemd service. It does not change firewall rules; if UFW or firewalld is active, it prints the rules to add.
curl -fsSL https://mistgate.app/install.sh | sudo bash -s -- --public-url https://panel.example.comThe installer requests a Let's Encrypt certificate for the URL host by default. It asks before making changes; add --yes for a non-interactive run. Use --dry-run to download and verify a release without changing the host, or --version vX.Y.Z to install a pinned release. --admin-host, --admin-listen, --acme-domain and --data-dir select the setup and service options described below.
When it finishes, open the one-time setup link in a browser and create the owner account. The link expires in 30 minutes. Then add a node from Nodes → Add node.
The panel is one static Linux binary for amd64 or arm64, with the admin web app built in. Use the official release unless you have a reason to build your own.
Every release on GitHub Releases carries the panel (mistgate-linux-amd64, mistgate-linux-arm64), the node agent (mistgate-node-linux-amd64, mistgate-node-linux-arm64), SHA256SUMS, BUILDINFO and two signed manifests: manifest.json with manifest.sig for the node agents and panel-manifest.json with panel-manifest.sig and panel-manifest.sshsig for the panel. The official binaries carry the project's release key, so a panel installed from them downloads the signed node agents by itself and can update itself from later releases (see Updates).
On the panel server, as root (uname -m prints x86_64 for amd64 and aarch64 for arm64):
ARCH=amd64 # arm64 on an ARM server
cd /root
for f in "mistgate-linux-$ARCH" SHA256SUMS panel-manifest.json; do
curl -fsSLO "https://github.com/Mistgate/mistgate/releases/latest/download/$f"
done
sha256sum --check --ignore-missing SHA256SUMS
grep -q "$(sha256sum "mistgate-linux-$ARCH" | cut -d' ' -f1)" panel-manifest.json && echo "listed in panel-manifest.json"
install -m 0755 "mistgate-linux-$ARCH" /usr/local/bin/mistgate
mistgate versionWhat these checks prove, and what they do not:
-
sha256sum --checkproves the file arrived intact and matches the checksums published with the release.SHA256SUMSis written by the release workflow and is not signed, so it does not prove who built the binary. - The same SHA-256 is listed in
panel-manifest.json, which the maintainer signs offline with the release key after rebuilding every binary from the tag. The one-line installer preferspanel-manifest.sshsigwithssh-keygen -Y verify, and falls back topanel-manifest.sigwith OpenSSL 3.2 or newer. For this manual path, thegrepis a consistency check only. - From then on the panel checks signatures itself: it installs a panel release, and hands a node bundle to the agents, only when the signature verifies with the release key compiled into it.
mistgate versionprints the version and that key's fingerprint.
On a build machine with the tools listed in Requirements:
git clone https://github.com/Mistgate/mistgate.git
cd mistgate
make build
scp bin/mistgate-linux-amd64 root@panel.example.com:/root/
ssh root@panel.example.com 'install -m 0755 /root/mistgate-linux-amd64 /usr/local/bin/mistgate'bin/ also holds the node agents (mistgate-node-linux-amd64, mistgate-node-linux-arm64); keep them for the manual node install.
Warning
a build without RELEASE_KEY has no release key: its node agents never update themselves, the panel cannot install panel releases, and the SSH installation has no trusted agent bundle to install. A build with your own key trusts only releases you sign. Make the key before the first build: see Releases and signing.
The public address shows a decoy site to everyone. The admin is reached in one of three ways, chosen once, when you run mistgate setup:
| Mode |
setup flags |
Admin address | When to pick it |
|---|---|---|---|
| Secret path prefix (default) | --public-url https://panel.example.com |
https://panel.example.com/<secret>/, where the secret is 24 random characters |
The simplest: one host name, one certificate. |
| Secret host | --public-url https://panel.example.com --admin-host <secret host> |
https://<secret host>/ |
You want the admin on a host name nobody can guess. It needs a DNS record and a certificate that covers it. |
| Separate listener | --public-url https://panel.example.com --admin-listen 127.0.0.1:8081 |
http://localhost:8081/, through an SSH tunnel |
The admin never appears on the public port at all. |
-
Requests that do not match the admin (a wrong prefix, an unknown host, an unknown path) all get the decoy site, so a prober cannot tell a near miss from a random guess.
-
Always pass
--public-url. It is the base of every subscription link and the address that node install commands carry. Without it the panel hands out no subscription links, and adding a node fails unlessservegets--agent-addr. -
--admin-hostand--admin-listencannot be combined. -
The separate admin listener speaks plain HTTP. Bind it to loopback and reach it through SSH:
ssh -N -L 8081:127.0.0.1:8081 root@panel.example.com
Then open
http://localhost:8081/in your browser. Use the same port on your side: passkeys are bound to the addresshttp://localhost:<port>that setup stored. -
--rp-idand--rp-originsoverride the WebAuthn settings that setup derives from the admin address. You rarely need them.
Warning
setup stores these addresses once. Running it again keeps them, and Mistgate has no command to change them later. Choose before you go on; starting over means a new data directory and enrolling every node again.
mistgate setup --public-url https://panel.example.comIt prints:
Data dir: /var/lib/mistgate
Admin URL: https://panel.example.com/<secret>/
Setup link: https://panel.example.com/<secret>/setup#<token>
The link works once and expires in 30 minutes. Open it in a browser and create your admin (a passkey, or a password with an authenticator code).
What setup does:
- Creates the data directory
/var/lib/mistgatewith mode 0700 (--data-dirchanges the path). - Creates
master.key, 32 random bytes with mode 0600. It encrypts every secret the panel stores. - Creates the database
mistgate.dband applies the schema. - Stores the addresses of the chosen mode and generates two more secrets: the TLS name the node agents use to reach the panel, and the secret path prefix of the subscription links.
- Prints a one-time setup link, valid for 30 minutes.
Keep the admin URL to yourself. Setup is safe to run again: it keeps the existing configuration and, as long as no admin exists, prints a fresh setup link.
| Option | Flags of serve
|
What happens |
|---|---|---|
| Let's Encrypt | --acme-domain panel.example.com |
The panel gets and renews the certificate itself (TLS-ALPN-01 on the public listener, so it must be reachable on port 443). A second listener on :80 answers HTTP-01 and redirects plain HTTP to HTTPS (--acme-http; an empty value turns it off). Certificates are cached in <data-dir>/acme. --acme-email adds a contact address. Using it accepts the Let's Encrypt terms of service. |
| Your own certificate | --tls-cert /path/fullchain.pem --tls-key /path/privkey.pem |
The panel serves your PEM files and reads them again when the certificate file changes (checked at most every 30 seconds), so a renewal by another tool needs no restart. |
| Both | both sets of flags | Names listed in --acme-domain get Let's Encrypt certificates; every other name gets your certificate. Useful for a secret admin host covered by a wildcard certificate of your own. |
--acme-domain takes plain host names only, no wildcards. It can be repeated for several names.
Note
a Let's Encrypt certificate for a secret admin host puts that name into public Certificate Transparency logs. To keep it secret, cover it with a wildcard certificate of your own.
Without anything else the panel shows a built-in "Coming soon" page. Every installation ships the same page, so it is recognisable; your own site is better. Put static files in a directory and pass --decoy-dir:
-
/and every directory serve theirindex.html. -
404.htmland429.html, when present, replace the built-in "not found" and "too many requests" pages. Every unknown path, wrong admin prefix and unknown subscription link gets the same 404. -
robots.txt, when absent, is a built-in one that turns away known AI crawlers. - Only GET and HEAD are served. Files and directories whose name starts with a dot are never served, and responses carry no Last-Modified or ETag headers.
The panel only reads this directory. With the systemd unit below, keep it outside /home and /root (for example in /srv/mistgate-decoy). Your own decoy site says what a good one looks like and has a prompt that has an AI agent invent a unique site.
mistgate serve --listen :443 --acme-domain panel.example.com--listen defaults to 127.0.0.1:8080, so pass --listen :443 on a real server. The log goes to stderr; look for listening lines for the public listener (and acme-http for port 80). Stop it with Ctrl+C once it works.
Save this as /etc/systemd/system/mistgate.service and change ExecStart to the flags you chose:
[Unit]
Description=Mistgate panel
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/mistgate serve --listen :443 --acme-domain panel.example.com
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
# The panel writes only its data directory and only needs to bind ports 443 and 80.
NoNewPrivileges=yes
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
ProtectSystem=strict
ReadWritePaths=/var/lib/mistgate
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectHostname=yes
LockPersonality=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK
SystemCallArchitectures=native
SystemCallFilter=@system-service
UMask=0077
[Install]
WantedBy=multi-user.targetsystemctl daemon-reload
systemctl enable --now mistgate
journalctl -u mistgate -fWhy it looks like this:
-
mistgate setupran as root, so the data directory belongs to root, and the service runs as root too. Every capability except binding low ports is dropped, and only/var/lib/mistgateis writable. If you use another--data-dir, changeReadWritePaths. - The panel stops gracefully on SIGTERM. With
Restart=on-failuresystemd restarts it when a listener fails, not when you stop it. - Every flag has a
MISTGATE_*environment variable, so you can move the flags toEnvironment=lines or anEnvironmentFile=. See Configuration. - With
--decoy-dir,--tls-certor--tls-key, the files only need to be readable.
If another web server must own port 443 on this host, Mistgate can run behind it:
- Run the public listener without TLS on loopback (
--listen 127.0.0.1:8080, no--acme-domain, no--tls-cert) and let the proxy terminate TLS forpanel.example.com, passing the Host header and the path through unchanged. - Add
--trusted-proxy 127.0.0.1so that rate limits, sessions and the audit log see the real client address fromX-Forwarded-FororForwarded. - Node agents need TLS from the panel itself. Give them a listener of their own and put its address into the install commands:
--agent-listen :8443 --agent-addr panel.example.com:8443. The proxy must not touch that port.
The agent port is then a port of its own that answers only the secret TLS name; on the shared port 443 it hides behind the decoy site. Prefer the plain setup above when you can.
Open the setup link from step 3 in a browser, the whole link including the part after #.
- Language. Pick English, Russian or Simplified Chinese. You can change it later.
-
Create the admin. The LOGIN field (it starts as
admin) is your login and the name the panel shows. Then:- Create passkey: the browser asks for a fingerprint, a face, a PIN or a security key. The key stays on your device. This is the recommended way.
- password + authenticator code: a password of at least 12 characters, then scan the QR code with an authenticator app (Google Authenticator, 1Password, Aegis and the like), type the 6-digit code and press Create admin.
- Done. Choose Add your first node or Later, let me look around first.
The first admin is the owner. The setup wizard also creates an empty group "Everyone" for your first users.
- A login is 3 to 64 characters: a–z, 0–9 and
. _ @ -. - The link is spent only when the admin is created. If it expired or something went wrong, run
mistgate setupagain for a new link. - A passkey works only on the admin address that setup stored. "The browser refused the passkey for this address" means the page was opened under another address.
Later you sign in at the admin URL with Sign in with passkey, or with another way: login, password and code. Five wrong passwords within an hour lock that login for 15 minutes. Lost your phone or your passkey: Security explains mistgate auth reset-login.
Everything the panel knows lives in the data directory:
| File | What it is |
|---|---|
mistgate.db, mistgate.db-wal, mistgate.db-shm
|
The database: admins, nodes, profiles, users, devices, traffic, events, the audit log. Secrets inside are encrypted with the master key. |
master.key |
The key that encrypts the stored secrets, including the key of the panel CA that every node trusts. |
acme/ |
Let's Encrypt account and certificates (with --acme-domain only). |
Make a copy now, with the panel stopped so the database is consistent:
systemctl stop mistgate
tar czf mistgate-backup-$(date +%F).tgz -C /var/lib mistgate
systemctl start mistgateWarning
the copy holds the master key: whoever has it can read every secret of the panel. Keep it encrypted and off the server. Without the data directory every node has to be enrolled again and every user, link and key is gone.
For regular copies, turn on encrypted backups in Settings → Backups: the panel encrypts a consistent snapshot to your offline recovery key and uploads it to your Cloudflare R2 bucket on a schedule. If you built the panel with your own release key, keep that key file offline and backed up as well.
Add a node: automatically over SSH or with a command you run yourself.
Generated from docs/ in Mistgate/mistgate — edit the docs, not the wiki.
Сгенерировано из docs/ в Mistgate/mistgate — правьте документацию, а не вики.
由 Mistgate/mistgate 中的 docs/ 生成,请编辑文档,不要直接编辑 wiki。
English
Getting started
- Overview
- Requirements
- Install the panel
- Install the Cloudflare edition
- Add a node
- Install a node over SSH
- AI agent guide
- First users
Guide
- Nodes
- Profiles
- Hysteria2
- VLESS REALITY
- VLESS and Hysteria2 on one node
- AmneziaWG
- WARP
- Users and groups
- Subscriptions
- Client apps
- User page
- DNS
- Torrent protection
- Your own decoy site
Operations
- Health
- Reachability
- Telegram alerts
- Panel watcher
- Updates
- Releases and signing
- Encrypted panel backups
- Security
- Troubleshooting
Roadmap
Reference
Русский
Начало работы
- Обзор
- Требования
- Установка панели
- Установка Cloudflare-версии
- Добавление ноды
- Установка ноды по SSH
- Инструкция для AI-агента
- Первые пользователи
Руководство
- Ноды
- Профили
- Hysteria2
- VLESS REALITY
- VLESS и Hysteria2 на одной ноде
- AmneziaWG
- WARP
- Пользователи и группы
- Подписки
- Приложения-клиенты
- Страница пользователя
- DNS
- Защита от торрентов
- Свой сайт-ширма
Эксплуатация
- Здоровье
- Доступность
- Алерты в Telegram
- Наблюдатель панели
- Обновления
- Релизы и подпись
- Зашифрованные резервные копии панели
- Безопасность
- Решение проблем
План развития
Справочник