Skip to main content

Running as a service

For a machine you actually want monitored, the agent should start at boot and restart if it stops.

No installer yet

Watchtower does not ship a service installer. There is no .msi, no systemd unit, and no launchd plist in the box — you write the service definition yourself using the examples below.

A proper installer is planned. Until then, the one thing you must get right is WT_CREDENTIAL_PATH.

Set the credential path explicitly

This is the part that catches people.

The default credential location is derived from the home directory of the user running the agent. A service account has a different home directory, or none — so without an explicit path the credential lands somewhere unexpected, and in the worst case in whatever directory the service happened to start in.

Pick a system path and set it:

PlatformSuggested path
Linux/var/lib/wt-agent/credential.json
WindowsC:\ProgramData\wt-agent\credential.json
macOS/Library/Application Support/wt-agent/credential.json

Create the directory, make the service account its owner, and keep it unreadable by other users. The agent writes the file owner-only, but it cannot fix a directory that is open to everyone.

Linux (systemd)

/etc/systemd/system/wt-agent.service:

[Unit]
Description=Watchtower agent
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=wt-agent
Environment=WT_APP_URL=https://watchtower.page
Environment=WT_BROKER_URL=wss://broker.watchtower.page/ws
Environment=WT_CREDENTIAL_PATH=/var/lib/wt-agent/credential.json
EnvironmentFile=/etc/wt-agent/env
ExecStart=/usr/local/bin/wt-agent
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Put the API key in /etc/wt-agent/env, readable only by root, so it is not visible in the unit file or in systemctl show:

WT_API_KEY=wt_your_key_here

Then:

sudo useradd --system --no-create-home wt-agent
sudo mkdir -p /var/lib/wt-agent && sudo chown wt-agent:wt-agent /var/lib/wt-agent && sudo chmod 700 /var/lib/wt-agent
sudo chmod 600 /etc/wt-agent/env
sudo systemctl daemon-reload
sudo systemctl enable --now wt-agent
sudo journalctl -u wt-agent -f

Windows

The agent is a console program, not a native Windows service, so it needs a wrapper. NSSM is the usual choice:

nssm install WatchtowerAgent "C:\Program Files\Watchtower\wt-agent.exe"
nssm set WatchtowerAgent AppEnvironmentExtra WT_APP_URL=https://watchtower.page WT_BROKER_URL=wss://broker.watchtower.page/ws WT_CREDENTIAL_PATH=C:\ProgramData\wt-agent\credential.json WT_API_KEY=wt_your_key_here
nssm set WatchtowerAgent Start SERVICE_AUTO_START
nssm start WatchtowerAgent

Create C:\ProgramData\wt-agent\ first and restrict it to the account the service runs as. Note that environment variables set this way are readable by anyone who can read the service configuration — on a shared machine, prefer running the agent once interactively to register it, then removing WT_API_KEY from the service definition entirely. The credential is all it needs after that.

macOS (launchd)

/Library/LaunchDaemons/page.watchtower.agent.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>page.watchtower.agent</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/wt-agent</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>WT_APP_URL</key>
<string>https://watchtower.page</string>
<key>WT_BROKER_URL</key>
<string>wss://broker.watchtower.page/ws</string>
<key>WT_CREDENTIAL_PATH</key>
<string>/Library/Application Support/wt-agent/credential.json</string>
</dict>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
sudo launchctl load /Library/LaunchDaemons/page.watchtower.agent.plist

Register the machine once by running the agent manually with WT_API_KEY set before loading the daemon, so the key never has to appear in the plist.

Registering first, then running as a service

The cleanest pattern on any platform:

  1. Run the agent once by hand, with WT_API_KEY and WT_CREDENTIAL_PATH set to the system path, as the account the service will use.
  2. Confirm the machine appears in the console and the credential file exists.
  3. Configure the service without WT_API_KEY, pointing at the same WT_CREDENTIAL_PATH.

The key never lands in a service definition, and the service starts with a credential already in place.