Install on your server, through SSH
The same install as on your own computer, run on a machine that stays awake.
Firetower still publishes on 127.0.0.1 and nothing else, so you reach it by
forwarding that port to your laptop with firetower tunnel. No domain, no
certificate, no VPN.
Not sure this is the right one? See the Overview — and note that you can add a domain later without reinstalling.
Both pieces go on the server: the control plane and the worker that runs the agents. That is the point of this setup — the work is not on your laptop, so closing the lid does not stop it.
#Before you start
- On the server
Docker, the Compose plugin, and Node 20 or newer.
- From your laptop
SSH access to that server, with the key you already use. The tunnel needs nothing else — no port opened, no Firetower CLI on the server's side of it.
#Install on the server
▶Run this onthe server
npm i -g @firetower/cli
firetower install#1. Answer Only from this machine
The same answer as installing on your own computer. "This machine" is the server: Firetower binds loopback there, and the tunnel is what brings it to you.
Firetower ◆ How will people reach this Firetower? │ ● Only from this machine (simplest to start — directly, or with `firetower tunnel` from your laptop) │ ○ Your own domain, over Tailscale or another mesh VPN │ ○ Behind a reverse proxy I already run └
#2. Choose the port with the tunnel in mind
It checks which ports are free and recommends 8080. This is the one answer worth thinking about here, because the tunnel forwards this port: stay above 1024. Forwarding onto a low port requires root on your laptop.
◆ Which port should Firetower publish? │ ● 8080 — free (recommended) │ ○ Let me choose └
#3. Everything else is the ordinary install
In order: it fetches the deployment files from the latest release, checks the
machine (Docker, the Compose plugin, the port, architecture, disk, and whether
ghcr.io is reachable), then asks where Firetower should live, an
administrator username and a password. It shows the whole plan before writing
anything, and answering No writes nothing.
No Caddy container is created with this option — there is no certificate to terminate, and the control plane serves its own interface, API and preview routing.
#4. Save the root key
────────────────────────────────────────────────────────────── Save this. It is not stored anywhere you can read it back. FIRETOWER_ROOT_KEY q1Zk8mWv2r7XcN0pT4sYbA6dJhLgE3uF9nRxKtVwQmc= Every credential Firetower holds is sealed with it. Back it up somewhere that is not your database backup — a stolen database opens nothing on its own, and losing this key means adding every credential again. ────────────────────────────────────────────────────────────── ◆ I have saved the root key │ ○ Yes / ● No └
This loses work
The root key is the only unrecoverable thing here. Every stored credential is sealed with it, which is why the installer requires you to acknowledge it. Back it up somewhere separate from your database backup — see Secrets.
#5. Done — and it tells you how to get to it
Firetower is running. http://localhost:8080 That works on this machine. From your laptop, bring up a tunnel first: firetower tunnel you@this-machine --remote-port 8080 username admin password velvet-timber-harbor-332 You will be asked to replace that password when you sign in, and then to delete ADMIN_INITIAL_PASSWORD from .env.
The admin password is printed once. Note it down — you sign in with it through the tunnel in a moment.
It writes the same files as any loopback install: firetower.yml, an .env
that is chmod 600, and a Caddyfile that goes unused until you add a domain.
#Bring up the tunnel
This is the one command that does not run on the server.
▶Run this onyour own laptop
npm i -g @firetower/cli
firetower tunnel you@your-serverIt reads the port from the remote .env over the same SSH connection it
forwards, brings up http://localhost:8080, and holds until Ctrl-C. The server
needs only ssh — no Firetower CLI there.
Open http://localhost:8080 and sign in with the password the installer
printed. You are asked to replace it, and then to delete
ADMIN_INITIAL_PASSWORD from .env on the server.
#When the default ports do not work
firetower tunnel you@your-server --remote-port 8080 --local-port 9090- --remote-port
The port Firetower publishes on the server. Given, it skips the lookup — use it when your account cannot read the remote
.env, or when the CLI warns that it found noHTTP_PORTthere and is assuming 8080.- --local-port
The port to listen on here. Defaults to the remote port. Use it when something on your laptop already answers on that number: the tunnel exits with
something may already answer on 8080 hererather than connecting and forwarding nothing. A port under 1024 needs root on your laptop, so the error suggests--local-port 8080in that case.
Note
Keep both ports the same where you can. FIRETOWER_PUBLIC_URL is
http://localhost:8080, and preview and notification links are built from it —
with a different --local-port, the address in your browser no longer matches
the links Firetower generates.
#The tunnel is only your view
Ctrl-C closes the window you are looking through, not the deployment. The control plane and the worker are both on the server, so agents carry on, the event log keeps filling, and everything is where you left it the next time you bring the tunnel up.
What the tunnel does cost you is everyone else: it forwards to your laptop only. No phone, and nothing for your team. That is the reason to move to a domain.
#Next
- Want it reachable from your phone and your team, with no tunnel? → Custom
domain + Tailscale.
firetower domainadds one to the install you just made, without reinstalling. - Want agents running on other machines too? → Add a machine
- Upgrade the app when a new release lands.