Skip to content

Installing the server agent

The server agent installs in one command and enrolls itself. This page covers the install paths, the installer’s options, the network requirements, and hosts that reach the internet only through a forward proxy.

  • A Linux host, x86-64 or arm64, running systemd 219 or newer — every current distribution, and Amazon Linux 2 and CentOS 7 (219). On systemd older than 235, and on cgroup v1 hosts without memory accounting, a few system-service details are not reported.
  • Outbound HTTPS from the host to the WatchTower15 API, directly or through a forward proxy. No inbound ports.
  • Your organisation’s install token (in the dashboard, Servers → Add Server).
  • Root for the install step, typically through sudo. The installer refuses to run without it.

The fastest path. Downloads the agent, verifies its checksum, creates the service user, enrolls, and starts monitoring:

Terminal window
curl -fsSL https://api.watchtower15.com/api/agent/install-script | sudo sh -s -- <org_token>

In the dashboard, Add Server on the Servers page opens the Adding a server drawer, which shows this command with your token filled in, and a button that copies it. It leaves out sudo: run it as root, or put sudo before sh. Members who cannot view the organisation’s settings see <org_token> in place of the token. For a host behind a proxy, the drawer adds the proxy for you: see Behind a forward proxy.

A new server joins your organisation’s default profile, unless the command names another profile with --profile=. The drawer adds it for you: pick a profile in its Profile (optional) list and the command gains --profile=<slug>; Organisation default adds nothing. Members who cannot view profiles do not see the list. A profile’s own page shows the command for that profile too (see Assigning a host to a profile). To move a server to another profile later, use (change) on the Profile card of the server’s Info tab (see Changing a server).

Pass options after the token (sh -s -- <org_token> --option). Each option can also be given as the environment variable in the second column.

Option Environment variable Effect
--proxy=<url> WT15_PROXY Send the agent’s API traffic, and the installer’s own download, through a forward proxy. See Behind a forward proxy.
--proxy-port=<port> WT15_PROXY_PORT The proxy’s port, when the URL does not include one.
--no-logging WT15_DISABLE_LOGGING=1 Do not collect or ship logs from this host.
--no-telemetry WT15_DISABLE_TELEMETRY=1 Do not collect or send host telemetry.
--supplier-identifier=<id> WT15_SUPPLIER_IDENTIFIER The provider’s ID for the host (for example an AWS instance ID). Detected when unset on AWS EC2, on DigitalOcean and in a Docker container. Elsewhere, set a stable ID here (the provider’s instance or server ID, not /etc/machine-id, which an OS reinstall regenerates), and give the same value on every install of that host, so that an agent installed again continues its server.
--tag=<group>=<tag> WT15_TAGS A tag the server gets when it enrols, repeatable, at most 20; also --tag=<group-uuid>=<tag> and --tag=<tag-uuid>. A tag that does not exist yet is created. Checked with WatchTower15 before anything is installed: see Tags at install. WT15_TAGS holds the same tags joined by commas; --tag replaces it. It applies only when the host enrols as a new server.
--profile=<uuid|slug> WT15_PROFILE The profile the server joins when it enrols, by the profile’s uuid or slug (both on the profile’s page), never its name. Without it, the server joins your organisation’s default profile. Checked with WatchTower15 before anything is installed: see If the profile is not found. It applies only when the host enrols as a new server; --upgrade and --uninstall ignore it.
--upgrade — Upgrade an installed agent to the latest release in place. See Upgrades.
--uninstall — Remove the agent and everything the installer created, the uninstall unit included. Takes no token; needs root. In a container it removes nothing, and says so. See Uninstall.

The installer writes these settings to /etc/wt15-server-agent/agent.env, which the service reads at start-up, the profile as WT15_PROFILE_UUID or WT15_PROFILE_SLUG, whichever the value is, and the tags it kept as WT15_TAGS. See the configuration reference.

Before it downloads or installs anything, the installer asks WatchTower15 whether your token and profile would enrol, and names the profile the server will join:

==> Profile: web-tier

If your organisation has no profile with that uuid or slug (a typo, a deleted profile, or another organisation’s), it stops there, with exit status 1, and names the value:

ERROR: profile "web-teir" was not found in your organisation. Check the uuid or slug on the profile's page.

A profile’s name is refused before WatchTower15 is asked:

ERROR: --profile takes a profile's uuid or slug, not its name: "Web tier"

Nothing is installed and no server is created: correct the value and run the command again. The same check stops an install whose token WatchTower15 does not accept, with ERROR: the install token was not accepted. Copy the command again from Servers → Add Server. If the installer cannot reach WatchTower15, it tries again after 5, 10, 20 and 30 seconds, then stops with ERROR: cannot reach <API URL> (HTTP <code>).

On a host that is already enrolled, the agent does not enrol again, so the installer skips the check. If you gave a profile, it says so and carries on: ==> Credentials found: this host is already enrolled, so --profile applies only if it enrols again as a new server. To move an enrolled server, use (change) on the Profile card of the server’s Info tab.

--tag= gives the server tags when it enrols, as many as you need up to 20: repeat the option, one tag each.

Terminal window
curl -fsSL https://api.watchtower15.com/api/agent/install-script | sudo sh -s -- <org_token> \
--tag=Environment=production --tag=Team=billing-api

Each tag is one of:

  • <group>=<tag>: a tag group and a tag by name, as on the Tags page. A group or tag that does not exist yet is created when the server enrols.
  • <group-uuid>=<tag>: a group by its uuid, then a tag by name, for a group whose name predates the naming rule (such as My App).
  • <tag-uuid>: an existing tag by its uuid.

Names follow the naming rule: letters, digits, - and _ only, a group starting with a letter and a tag with a letter or a digit, up to 100 characters each. In a container, or from an image’s first boot, set WT15_TAGS to the same tags joined by commas (WT15_TAGS=Environment=production,Team=billing-api); --tag replaces it when both are given. The Add Server drawer writes these options for you.

Before it installs anything, the installer checks every tag with WatchTower15 and says what will happen to each:

==> Profile: web-servers
==> Tag Environment=production (exists)
==> Tag Team=billing-api (will be created)

It stops, with exit status 1 and nothing installed, on a tag it cannot use, naming it:

ERROR: tag a b=c: Use only letters, digits, - and _, starting with a letter (up to 100 characters).
ERROR: tag not-a-uuid: give <group>=<tag>, or a tag's uuid.
ERROR: at most 20 tags per install.
ERROR: tag 3f2c6a1e-5b7d-4e9f-8a0b-1c2d3e4f5a6b: no such tag (or group) in this organisation.
ERROR: tag Team=old-team: a tag group or tag with this name was deleted in WatchTower15, and its name cannot be reused. Choose another name.
ERROR: tag Domain=x: its group holds tags for domains, not servers.

The first three are checked before WatchTower15 is asked; the others name every refused tag at once. The tags apply only when the host enrols as a new server. On a host that is already enrolled no request is made: a tag that breaks the naming rule is only warned about and left out (WARNING: --tag ignored: "<tag>": …), the others are saved, and the installer carries on. Removing a tag from the server later keeps it removed, until the agent is installed again with the same command: a host that continues its server adds its install tags back, and takes none away.

Terminal window
systemctl status wt15-server-agent
● wt15-server-agent.service
Loaded: loaded (/etc/systemd/system/wt15-server-agent.service; enabled)
Active: active (running)

The host appears in your dashboard within ~60 seconds. The agent writes its own diagnostics to /var/log/wt15-server-agent.log, and its start-up line there shows the version it runs. Your system’s logrotate rotates and prunes that file on the same schedule as your other logs.

The systemd journal receives the agent’s errors, warnings and notices, nothing else. An outage is one error line when it starts, a warning every hour while it lasts and a notice when it ends (see When WatchTower15 cannot be reached), so journalctl -u wt15-server-agent -p err still lists errors only: one per outage, not one per failed attempt.

To see what the agent is doing, run it with --status, as root:

$ sudo /var/lib/wt15-server-agent/wt15-server-agent --status
WatchTower15 agent …, state as of 2026-10-06 11:25:04 UTC (written on change)
Connection : cannot reach WatchTower15 since 09:12:30 UTC (2 h 12 min): dns_failure
last error: lookup api.watchtower15.com: no such host
Spool : on disk, /var/lib/wt15-server-agent/spool, 1.9 MB
Backlog : telemetry 528 records (09:12:30 → 11:24:45), system info 1, database snapshots 0, disk usage 0
Dropped : none
Clock : 1 s behind WatchTower15 (no correction)
Profile : etag 3f9a2b7c…, fetched 2026-10-06 08:01 UTC, from the cache
Limits : telemetry 64 MB + 24 MB × 1 database, horizon 72 h, floor 10 % / 512 MB free

It prints the state the agent last wrote to /var/lib/wt15-server-agent/status.json, and the first line says when that was: the agent writes the file when its state changes, and at most once a minute during an outage.

  • Connection reads connected to WatchTower15, or since when and why it is not: cannot reach WatchTower15 (the network, DNS, TLS or a proxy), WatchTower15 not accepting data (an HTTP error) or no answer from WatchTower15 (a request that got no answer in time), with the error class and the last error.
  • Spool is where the data waiting to be sent is kept, and how much there is: on disk, or in memory only with the reason (for example below the free-disk floor).
  • Backlog is what is still to be sent. While WatchTower15 asks agents to wait before sending more kept data, the line ends with replay paused until … UTC (WatchTower15 asked to wait).
  • Dropped counts the records the agent had to drop (at a limit, or refused by WatchTower15 as invalid), with those of the current outage by reason.
  • Refused, shown only when there are any, counts the database data the agent kept that WatchTower15 refused, by reason: for example database blocks refused: 40, collected after another collector took over; 2, collected while the database was paused. The agent leaves those out and delivers the rest (see Collector pools).
  • Clock compares the server’s clock with WatchTower15’s, and says when the agent is correcting for it.
  • Profile and Limits are the configuration the agent runs: its etag, when it was fetched and whether it came from the profile kept on the host, and how much and how long it keeps. A database this server collected in the last 72 hours still counts in the telemetry limit, and Limits counts those apart, as in telemetry 64 MB + 24 MB × 3 databases (1 kept after a lost lease).

--status sends nothing and changes nothing. It exits with status 1 when there is no state file yet, for example before the agent has enrolled. In a container, run docker exec <container> /var/lib/wt15-server-agent/wt15-server-agent --status.

Direction Destination Purpose
Outbound HTTPS (443) WatchTower15 API, api.watchtower15.com enrollment, telemetry, logs, config
Inbound — none required

Behind a firewall that allows outbound traffic by IP address, allow the three addresses api.watchtower15.com answers from: see the Restricted egress tab under Install.

If your host reaches the internet only through an HTTP(S) forward proxy, give the proxy to the installer with --proxy=. The installer uses it to download the agent, and stores it in the agent’s configuration so the agent uses it too. It applies to WatchTower15 API traffic only, and cloud metadata is never sent through it.

The install script is downloaded before the installer runs, so that download needs the proxy separately, with curl -x:

Terminal window
curl -fsSL -x http://proxy.corp.example:3128 https://api.watchtower15.com/api/agent/install-script \
| sudo sh -s -- <org_token> --proxy=http://proxy.corp.example:3128

You can put the port in the URL, as above, or give it separately:

Terminal window
... | sudo sh -s -- <org_token> --proxy=http://proxy.corp.example --proxy-port=3128

The dashboard builds this command for you. The Adding a server drawer (Servers → Add Server) has two optional fields under the command, Proxy URL and Port. Fill them in and the command it shows and copies gains -x for the script’s download, with the port always written out, and --proxy= (and --proxy-port=) for the installer, in the form above. Leave Port empty when the URL carries one. The drawer checks both fields as you type, against the port and format rules below, and leaves a value that fails them out of the command, with the reason under its field.

  • Port. A port in the URL and a --proxy-port= must match. If they differ, the installer stops and names both, rather than picking one. --proxy-port= without --proxy= is also refused. With no port at all, the scheme’s default applies: 80 for http:// and 443 for https://. Most proxies listen on neither, so name the port.
  • Format. The URL is http:// or https://, then the host, then an optional port, and nothing after that (no path).
  • Credentials. user:password@ is supported, but percent-encode any special character in the user name or password. For example, @ becomes %40, so the password p@ss is written as http://user:p%40ss@proxy.corp.example:3128. Apart from the : between user name and password, only letters, digits and - . _ ~ may appear unencoded. The installer refuses anything else before it changes the host. The credentials are stored only in the agent’s configuration file, which only the agent’s service user and root can read. They are hidden in the agent’s log and never sent to WatchTower15.
  • sudo and environment variables. sudo normally drops variables such as HTTPS_PROXY and WT15_PROXY from your shell. Pass the proxy as a flag, as above, or name the variable explicitly (sudo WT15_PROXY=http://proxy.corp.example:3128 sh -s -- …).
  • The proxy must allow the API. It must allow CONNECT to the WatchTower15 API, api.watchtower15.com, on port 443; a proxy that allows by address allows the three addresses in the Restricted egress tab under Install. The agent’s traffic stays TLS-encrypted end to end, and the proxy sees only the hostname.
  • The server’s IP address. WatchTower15 records the address your server’s requests arrive from. Behind a proxy, that is the proxy’s outbound address, so every server behind the same proxy is shown with the same IP address.

A proxy set in the standard HTTPS_PROXY variable is still honoured, but only as a fallback when --proxy is not given. See the configuration reference.

In a container there is no service: the install script runs the agent in the foreground, and the container runtime owns its lifecycle. Mount a volume at /var/lib/wt15-server-agent. It holds the agent’s credentials, its last profile and the data it keeps while it cannot reach WatchTower15; without it, a re-created container enrols again as a new server, starts with no profile until it reaches WatchTower15, and loses the data it kept during an outage. A re-created container that keeps an explicit WT15_SUPPLIER_IDENTIFIER and the same host name continues its server instead.

In a container other than Docker (Podman, LXC, containerd), give each container its own WT15_SUPPLIER_IDENTIFIER. Without one, every such container on a cloud instance can report the instance’s ID and Name tag, so the containers share one identity, and one container’s install would take over another’s server.

To choose the profile the container’s server joins, set WT15_PROFILE in its environment, to the profile’s uuid or slug. The install script checks it as on any host (If the profile is not found) and gives it to the agent. The agent’s own WT15_PROFILE_UUID and WT15_PROFILE_SLUG still work. Once the container has enrolled, its volume holds the server’s credentials, so a restart keeps its server and its profile, and the check is skipped. A container that starts the agent without the install script is refused by the agent itself: it logs profile "<value>" not found in this organisation; not enrolling and exits at once, with no retries.

Run the installer in uninstall mode, as root:

Terminal window
curl -fsSL https://api.watchtower15.com/api/agent/install-script | sudo sh -s -- --uninstall

It needs no token. It stops the agent, then removes its systemd unit, the uninstall unit and its script, the wt15-server-agent command, the logrotate drop-in, /var/lib/wt15-server-agent, /etc/wt15-server-agent, the agent’s log and the wt15-server-agent service user, and prints WatchTower15 agent removed. Anything it could not remove is named: WatchTower15 agent removed, except: …. A state directory that is a mount point is emptied and stays. On a host behind a proxy, add -x <proxy> to that curl, as for the install.

In a container it removes nothing, and prints No systemd here. In a container, remove the container and its volume. Do that instead.

On a host that cannot fetch the script, the same by hand:

Terminal window
sudo systemctl disable --now wt15-server-agent
sudo systemctl disable --now wt15-server-agent-uninstall.path # where the uninstall unit is installed
sudo rm -f /etc/systemd/system/wt15-server-agent.service \
/etc/systemd/system/wt15-server-agent-uninstall.path \
/etc/systemd/system/wt15-server-agent-uninstall.service \
/usr/local/bin/wt15-server-agent /etc/logrotate.d/wt15-server-agent
sudo systemctl daemon-reload
sudo rm -rf /var/lib/wt15-server-agent /etc/wt15-server-agent /usr/local/lib/wt15-server-agent \
/var/log/wt15-server-agent.log*
sudo userdel wt15-server-agent

/var/lib/wt15-server-agent holds the agent binary, its credentials, its last profile, the data it keeps while it cannot reach WatchTower15, its log positions (spool/logs/) and the schema state of the databases it collects (see What the agent keeps on the host); /etc/wt15-server-agent holds its configuration, your organisation’s install token included, and /usr/local/lib/wt15-server-agent the uninstall unit’s script. Removing the agent stops reporting; the server remains in your dashboard until you delete it there.

Installing the agent again on the same host continues that server, monitored or archived, when the host has an instance ID (see Lifecycle at a glance); delete the server first to start a new one. Uninstalling removes /etc/wt15-server-agent, so a host whose ID you set by hand needs the same --supplier-identifier on the next install, or it enrols a new server. The server keeps its own profile: a --profile on the new install is not applied, and you change the profile from (change) on the Profile card of the server’s Info tab. The agent reports the host’s self-reported tags by the profile its install names (your default profile when it names none), and WatchTower15 filters them by the server’s, so name the server’s own profile with --profile to keep them arriving as before. Deleting the server first removes the agent by itself, where its uninstall unit is installed: see Deleting a server.