Installing the controller
One command installs everything: Node.js, Caddy for HTTPS, the panel as a service, and your Owner account. It takes about two minutes.
Before you start
- A fresh server running Debian 12 or Ubuntu 22.04 / 24.04, with 2 vCPUs and 2 GB of memory, and root access.
- A domain name for the panel, such as
panel.example.com, with a DNS A record pointing at the server’s IP address. The installer gets a free HTTPS certificate for it. Without a domain you can still try the panel onhttp://<server IP>, unencrypted. - Ports 80 and 443 open in your provider’s firewall.
1. Get the installer
It’s one file: vorticpanel-0.1.0.tar.gz.
-
Download it from the repository’s Releases page on GitHub, or
-
Build it on any computer with Node.js 24 and a copy of the code:
npm ci npm run packageIt’s saved as
release/vorticpanel-0.1.0.tar.gz.
2. Copy it to the server
From your computer (Windows PowerShell, macOS or Linux), replacing SERVER_IP:
scp vorticpanel-0.1.0.tar.gz root@SERVER_IP:/root/
3. Run it
On the server, as root:
cd /root && tar -xzf vorticpanel-0.1.0.tar.gz && bash vorticpanel-0.1.0/install.sh --domain panel.example.comcd /root && tar -xzf vorticpanel-0.1.0.tar.gz && bash vorticpanel-0.1.0/install.sh --no-domainPartway through it asks for your account, the first Owner:
- your name, email and company name (shown in the panel)
- a password of 12 characters or more
- a QR code: scan it with an authenticator app (Google Authenticator, Authy, 1Password…) and type the 6-digit code it shows
When it finishes, it prints the panel’s address. Open it and sign in. Then go to First steps.
What the installer does
| Step | Where |
|---|---|
| Installs Node.js 24, SQLite and Caddy | From Debian/Ubuntu, NodeSource and Caddy’s own packages |
Creates the panel user and copies the panel |
/opt/panel |
| Writes the settings | /etc/panel/controller.env (see Controller settings) |
Sets up the service, started at boot. It runs as the panel user with no privileges, can only write in /var/lib/panel, keeps its files to itself, and can’t reach the cloud metadata address (169.254.169.254) |
/etc/systemd/system/panel.service |
| Asks for the first Owner | Only on a fresh install |
| Sets up HTTPS with a free certificate, renewed automatically | /etc/caddy/Caddyfile |
Copies the database and secret.key every hour (see Backing up) |
/var/backups/panel, by panel-backup.timer |
Opens ports 80 and 443, if the ufw firewall is on |
|
| Checks the panel answers on its address |
The panel’s data lives in /var/lib/panel. Logs: journalctl -u panel -f.
The server’s IP address comes from api.ipify.org, or else from the server itself (hostname -I), and is only used if it’s a plain IPv4 address. The installer stops if /var/lib/panel, /var/lib/panel/images or /var/backups/panel is a symbolic link, rather than change whatever the link points at.
Options
| Option | What it does |
|---|---|
--domain NAME |
Serve the panel on https://NAME. Without it, the installer asks. |
--no-domain |
Serve plain http://<server IP> on port 80. Not encrypted: for testing only. Nodes then enroll with PANEL_AGENT_INSECURE=1 (see Adding a node). |
--no-proxy |
Don’t install Caddy, for a server that already runs nginx or another web server. You point it at 127.0.0.1:8080 yourself: see Using your own web server. |
--forget-old-addresses |
After moving the panel: stop answering nodes at its earlier addresses. Only once every node uses the new one. |
To switch from testing to a domain later, see the next section.
Moving to a domain and HTTPS
A panel installed with --no-domain runs on plain http://<server IP>. To move it to a domain with HTTPS, keeping every account, server and setting:
1. Point the domain at the controller. Add a DNS A record for it, such as panel.example.com, with the controller’s IP address. Check it from the controller (it should print that IP):
getent ahostsv4 panel.example.com
2. Run the installer again with --domain, on the controller, as root, from the release folder you installed from (or a newer one):
bash vorticpanel-0.1.0/install.sh --domain panel.example.com
It refuses to go ahead while the domain points somewhere else, so nothing changes until DNS is right. Then it sets PANEL_PUBLIC_URL=https://panel.example.com in /etc/panel/controller.env, has Caddy get a certificate for the domain, and checks that https://panel.example.com answers. Plain http:// to the domain is redirected to HTTPS. Sign in again at the new address.
3. The nodes follow by themselves. There’s nothing to run on them:
- The old address keeps answering nodes, so they stay online. People who go to it are sent to the new one.
- Each node’s agent updates itself (unless you turned off Update agents automatically on a node’s Settings tab; then press Update on each node).
- Once up to date, the agent checks the new address answers from the node, saves it in
/etc/panel-agent/agent.jsonand restarts. Servers on the node keep running. - If it can’t connect at the new address within 5 minutes, it goes back to the old one and tries again later. A node that can’t reach the new address at all (a firewall in the way, say) stays on the old one.
Each node’s page shows the Panel address it uses, marked old address until it has switched. This usually takes a few minutes. Nodes you enroll after the move use the domain, and don’t need PANEL_AGENT_INSECURE=1.
4. Optional: stop answering at the old address. Once every node’s page shows the new address, run the installer once more with --forget-old-addresses. The old addresses the panel keeps answering at are in PANEL_FORMER_URLS in /etc/panel/controller.env.
Moving from a domain back to plain http:// is the one move nodes don’t make by themselves, so their traffic is never unencrypted without you saying so. The installer prints the command to run on each node for that.
Already set up by hand?
Run the installer anyway. It keeps your Owner, settings and data, and replaces the service and the Caddy configuration. An existing Caddyfile is kept as /etc/caddy/Caddyfile.before-panel.
If something goes wrong
| The installer says | What to do |
|---|---|
| Another program is using port 80 or 443 | Usually nginx or Apache. Stop it (systemctl disable --now nginx) and run the installer again, or use --no-proxy and your own web server. |
https://… doesn’t answer yet |
The panel is running, but the address isn’t reachable. Check the domain’s DNS points at the server (dig +short panel.example.com), and that ports 80 and 443 are open in your provider’s firewall. Caddy’s log: journalctl -u caddy -n 50. |
| The panel didn’t start | journalctl -u panel -n 50 says why. |
| … isn’t a domain name | Give a name like panel.example.com, not an IP address. To use the IP, run with --no-domain. |
More in Troubleshooting.