Install the Firetower
One line on the server. It asks a handful of questions and brings the stack up.
Firetower is built server-first: the control plane runs on a Linux machine — a VPS, a cloud VM, a box in your office — and you connect to it from wherever you are, with the desktop client on your Mac or Windows machine, or the mobile app. Nothing below runs on your laptop.
#Before you start
- A Linux server you can SSH into, as root or with sudo.
- A domain you can add DNS records to, and an API token for whoever hosts its DNS.
#Install
▶Run this onthe server the Firetower will run on
curl -fsSL https://usefiretower.com/install.sh | shIt gets three things onto the machine, showing each line and asking before it
runs: Docker with the Compose plugin, if there is none, using Docker's own
installer; Node 20 or newer, which the CLI runs on; and the Firetower CLI. Then
it hands over to firetower install, and nothing else is decided for you.
Note
Already have Docker and Node? npm i -g @firetower/cli and firetower install
is the same thing without the first two steps.
The first question decides the rest, and there are two answers:
How will people reach this Firetower? ◆ Select │ ● Tailscale or another mesh VPN recommended — free, and takes 5 min │ ○ Advanced (type my own IP) public, your LAN, or a VPN you run └
#Using Tailscale — recommended
Nothing is published to the internet. Your people reach the Firetower because they are on your tailnet, and nobody else can reach it at all.
Install it on the server first, so the CLI has an address to find:
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale upTurn off key expiry for the machine in the Tailscale admin console while you are there — a server that drops off the tailnet is a Firetower nobody can reach.
Then run firetower install and take the first answer. It finds the address
itself:
✓ Mesh network detected 100.69.206.104 (tailscale0) ◆ Reach Firetower on 100.69.206.104? │ ● Yes └ ◆ Domain │ firetower.example.com └ ◆ Where should the certificate come from? │ ● Let's Encrypt, through Cloudflare └ ◆ API token │ •••••••••••••••••••••••••••••••• └ Create these DNS records in Cloudflare: firetower.example.com A 100.69.206.104 *.firetower.example.com A 100.69.206.104 ◆ Done? │ ● Yes, continue └
Both records. The wildcard is not optional — previews are served on subdomains. They are public records pointing at a private address: they resolve for everybody and answer only for people on your tailnet.
#With a custom IP
For a LAN, a VPN of your own, or a public address. You type it, and Firetower does not check it:
◆ Select │ ○ Tailscale or another mesh VPN │ ● Advanced (type my own IP) └ Firetower will be reached at the address you type, and will not check it. We assume you know what you are doing. ◆ Which address will people reach this on? │ 34.79.12.180 └
From there it is the same questions — domain, certificate, token, records — with your address in the two records instead of a tailnet one.
This loses work
On an address the internet can reach, the login page is the only thing in front of the control plane — and previews have no login at all. It holds your git tokens, your agent credentials and your worker SSH keys. Use a mesh VPN unless you have a reason not to.
If the machine is reached at an address it does not hold — behind NAT, a
floating IP, or a load balancer, which is every VM on Google Cloud, AWS and
Azure — it asks a second time for the address to listen on, prefilled with
0.0.0.0.
#Either way
It checks the machine, writes the deployment, generates the secrets and brings the stack up. The first start builds Caddy with your DNS provider compiled in, which takes a few minutes and is cached afterwards.
Firetower is running. https://firetower.example.com username admin password velvet-timber-harbor-332
That password is printed once. You are asked to replace it when you sign in,
and then to delete ADMIN_INITIAL_PASSWORD from .env.
This loses work
The root key is the only unrecoverable thing here. Every stored credential is sealed with it, and the installer makes you acknowledge it for that reason. Back it up somewhere that is not your database backup.
#Next
- Add a worker — to run agents on other machines.
- Update it when a new release lands.