Running the monitor as a service#

Running monitor in a foreground terminal is fine for trying it out, but for anything ongoing you want it to survive reboots, restart itself if it crashes, and log somewhere you can check later. Two straightforward ways to get that: a systemd unit, or a Docker container. Pick whichever fits how you already manage the machine it’ll run on.

Either way you’ll need: the monitor binary (or a way to build/pull it), your server’s URL, and an enrollment token from Monitors → Add a monitor (see Adding your first monitor if you haven’t done this yet).

Option A: systemd#

Create a dedicated user and directories for its local state (its SQLite database of mirrored checks and unsent results):

sudo useradd --system --home /var/lib/monitoring --shell /usr/sbin/nologin monitoring
sudo mkdir -p /var/lib/monitoring /etc/monitoring /opt/monitoring
sudo chown monitoring:monitoring /var/lib/monitoring
sudo chmod 750 /var/lib/monitoring
sudo cp monitor /opt/monitoring/monitor && sudo chmod 755 /opt/monitoring/monitor

Configuration file, filled in with your own values:

sudo tee /etc/monitoring/monitor.env <<'EOF'
SERVER_URL=https://your-tenpm-server
ENROLLMENT_TOKEN=<paste from the UI>
MONITOR_NAME=My first monitor
REGION=us
COUNTRY=US
CITY=New York
DB_PATH=/var/lib/monitoring/monitor.db
EOF
sudo chown root:monitoring /etc/monitoring/monitor.env
sudo chmod 640 /etc/monitoring/monitor.env

The token is only needed for the first successful enrollment — after that the agent holds its own API key in its database, and you can drop ENROLLMENT_TOKEN from the file if you like.

Service unit, /etc/systemd/system/monitoring-agent.service:

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

[Service]
Type=simple
User=monitoring
Group=monitoring
EnvironmentFile=/etc/monitoring/monitor.env
ExecStart=/opt/monitoring/monitor
WorkingDirectory=/var/lib/monitoring
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Then:

sudo systemctl daemon-reload
sudo systemctl enable --now monitoring-agent.service
sudo journalctl -u monitoring-agent -f

Running more than one monitor on the same host? Give each its own monitor.env/unit pair (a -shared/-private suffix, say) — it’s the same setup twice, not a different one.

Option B: Docker#

Build an image from an already-built binary (produced by your own build, or downloaded):

FROM alpine:3.20
RUN adduser -D -h /data monitor
USER monitor
COPY monitor /usr/local/bin/monitor
VOLUME /data
ENV DB_PATH=/data/monitor.db
ENTRYPOINT ["/usr/local/bin/monitor"]
docker build -t tenpmuptime-monitor .
docker run -d --name tenpmuptime-monitor \
  --restart unless-stopped \
  -v tenpmuptime-monitor-data:/data \
  -e SERVER_URL=https://your-tenpm-server \
  -e ENROLLMENT_TOKEN=<paste from the UI> \
  -e MONITOR_NAME="My first monitor" \
  -e REGION=us -e COUNTRY=US -e CITY="New York" \
  tenpmuptime-monitor

A few things worth knowing:

  • Use a named volume for /data, not a bind mount — it comes up with the right ownership automatically, where a fresh bind-mounted host directory often doesn’t.

  • The monitor’s identity (its server-assigned id and API key) lives in that volume, not in the container or image. Stopping and recreating the container — to deploy a new version, for instance — keeps the same monitor as long as the volume survives:

    docker stop tenpmuptime-monitor && docker rm tenpmuptime-monitor
    # docker build a new image, then re-run the same `docker run` command
  • Logs go to stdout/stderr, so docker logs -f tenpmuptime-monitor is your journalctl equivalent.

  • Run a one-off CLI flag (like -list-checks) against the running container with docker exec:

    docker exec tenpmuptime-monitor monitor -list-checks

Either way#

SERVER_URL, MONITOR_NAME, REGION, COUNTRY and CITY are required on every start, not just the first — don’t drop them from your config once enrollment succeeds, only ENROLLMENT_TOKEN becomes optional. If you ever need to move a monitor to new hardware, or its local database is lost, Reset enrollment on the Monitors page and re-run with a fresh token and -id <the existing monitor's id> (or MONITOR_ID as an env var) to reclaim its history rather than enrolling a new one — see Managing monitors.