OWNER: upaas deployment on fsn1app1 - deploy branch decision and the setup only you can do #148

Open
opened 2026-09-21 09:18:32 +02:00 by clawbot · 4 comments
Collaborator

@sneak these are the parts of putting dnswatcher on fsn1app1 that need your access or your call. The repo-side work is tracked separately and does not wait on this.

Decision: which branch does upaas deploy from?

#78 (closed) planned a prod branch fed by periodic main to prod PRs. Since then this repo gained next, so main already only ever receives a reviewed milestone that you merged yourself.

  1. Deploy from main. Your merge of the milestone PR is the deploy. No third branch.
  2. Deploy from prod. One more PR per deploy; lets main run ahead of production.

Recommendation: option 1. main is already gated by you, and a third branch adds a step without adding a check. The README deploy section will say main unless you say otherwise.

Needs your access

  • Create the upaas app on fsn1app1: repo URL, deploy key, webhook, branch as decided above.
  • Volume: a host directory mounted at /var/lib/dnswatcher.
  • Environment: DNSWATCHER_TARGETS (the real list of domains and hostnames you want watched), and the notification endpoints (DNSWATCHER_SLACK_WEBHOOK, DNSWATCHER_MATTERMOST_WEBHOOK, DNSWATCHER_NTFY_TOPIC), plus DNSWATCHER_METRICS_USERNAME / DNSWATCHER_METRICS_PASSWORD if you want /metrics.
  • Whether the dashboard is exposed publicly. It is unauthenticated by design and shows every watched name and recent alert.

What should be on main before the first deploy

The two notification types that cannot fire today (#104, #105) and the security headers (#98). It runs fine without them; it just watches less than the README says.

Model: fable-5-1

@sneak these are the parts of putting dnswatcher on `fsn1app1` that need your access or your call. The repo-side work is tracked separately and does not wait on this. ## Decision: which branch does upaas deploy from? https://git.eeqj.de/sneak/dnswatcher/issues/78 (closed) planned a `prod` branch fed by periodic `main` to `prod` PRs. Since then this repo gained `next`, so `main` already only ever receives a reviewed milestone that you merged yourself. 1. **Deploy from `main`.** Your merge of the milestone PR is the deploy. No third branch. 2. **Deploy from `prod`.** One more PR per deploy; lets `main` run ahead of production. Recommendation: option 1. `main` is already gated by you, and a third branch adds a step without adding a check. The README deploy section will say `main` unless you say otherwise. ## Needs your access - Create the upaas app on `fsn1app1`: repo URL, deploy key, webhook, branch as decided above. - Volume: a host directory mounted at `/var/lib/dnswatcher`. - Environment: `DNSWATCHER_TARGETS` (the real list of domains and hostnames you want watched), and the notification endpoints (`DNSWATCHER_SLACK_WEBHOOK`, `DNSWATCHER_MATTERMOST_WEBHOOK`, `DNSWATCHER_NTFY_TOPIC`), plus `DNSWATCHER_METRICS_USERNAME` / `DNSWATCHER_METRICS_PASSWORD` if you want `/metrics`. - Whether the dashboard is exposed publicly. It is unauthenticated by design and shows every watched name and recent alert. ## What should be on `main` before the first deploy The two notification types that cannot fire today (https://git.eeqj.de/sneak/dnswatcher/issues/104, https://git.eeqj.de/sneak/dnswatcher/issues/105) and the security headers (https://git.eeqj.de/sneak/dnswatcher/issues/98). It runs fine without them; it just watches less than the README says. Model: fable-5-1
clawbot added this to the 1.0 milestone 2026-09-21 09:18:32 +02:00
sneak was assigned by clawbot 2026-09-21 09:18:32 +02:00
Author
Collaborator

The deploy-branch question here is settled by sneak's standing ruling of 2026-08-30: upaas deploys each app from a prod branch cut from main, so releases stay independent of what the instances run, and a merged main to prod PR is a deploy. Creating prod and the repo-side readiness are ours, queued for when dnswatcher resumes (paused under the current priority rule). What stays with sneak here is only the setup on fsn1app1 once upaas runs there (sneak/upaas#181).

Model: opus-5-5

The deploy-branch question here is settled by sneak's standing ruling of 2026-08-30: upaas deploys each app from a `prod` branch cut from `main`, so releases stay independent of what the instances run, and a merged `main` to `prod` PR is a deploy. Creating `prod` and the repo-side readiness are ours, queued for when dnswatcher resumes (paused under the current priority rule). What stays with sneak here is only the setup on fsn1app1 once upaas runs there (https://git.eeqj.de/sneak/upaas/issues/181). Model: opus-5-5
Owner

yes, option 2. upaas is up now and i'm ready to set up the autodeployment. what settings do i need to set in env?

yes, option 2. upaas is up now and i'm ready to set up the autodeployment. what settings do i need to set in env?
Author
Collaborator

@sneak here is what the upaas app needs, read from the config code on next, which is what you will be deploying.

Environment variables

Only DNSWATCHER_TARGETS is required. A value dnswatcher cannot read (for example DNSWATCHER_DNS_INTERVAL=1d or DNSWATCHER_DEBUG=yes) stops it at startup with an error naming the variable. An empty value is the same as not setting it.

Variable Required Default What it does Example
DNSWATCHER_TARGETS yes; it will not start without it none Comma-separated list of the names to watch. Put both domains (example.com) and hostnames (www.example.com) here; it works out which is which by itself. sneak.berlin,www.sneak.berlin,git.eeqj.de
DNSWATCHER_NTFY_TOPIC no none Sends alerts to this ntfy topic. Give the full URL. https://ntfy.sh/my-dns-alerts
DNSWATCHER_SLACK_WEBHOOK no none Sends alerts to this Slack incoming webhook URL. https://hooks.slack.com/services/T000/B000/XXXX
DNSWATCHER_MATTERMOST_WEBHOOK no none Sends alerts to this Mattermost incoming webhook URL. https://mattermost.example.com/hooks/xxxx
DNSWATCHER_SEND_TEST_NOTIFICATION no false When true, sends one "startup complete" message to every alert destination above after the first round of checks, on every start. This is a quick way to see that alerts arrive. true
DNSWATCHER_SKIP_RECORD_NOTIFICATIONS no none Names from DNSWATCHER_TARGETS that should get no alert when their DNS records change or their nameservers disagree. They are still checked and still shown on the dashboard. A name that is not in DNSWATCHER_TARGETS stops startup. www.sneak.berlin
DNSWATCHER_DNS_INTERVAL no 1h How often DNS records and ports 80 and 443 are checked. Write a number and a unit s, m or h. There is no unit for days, so write 24h. 30m
DNSWATCHER_TLS_INTERVAL no 12h How often TLS certificates are checked, in the same format. 6h
DNSWATCHER_TLS_EXPIRY_WARNING no 7 How many days before a certificate expires to start warning about it. 14
DNSWATCHER_METRICS_USERNAME no none Turns on /metrics (Prometheus) behind a username and password. If this is not set, /metrics does not exist. prometheus
DNSWATCHER_METRICS_PASSWORD yes, if the username is set none The password for /metrics. Setting the username without a password stops startup. a long random string
DNSWATCHER_SENTRY_DSN no none Reports crashes in web requests to Sentry. A value Sentry cannot read stops startup. https://key@o0.ingest.sentry.io/0
DNSWATCHER_DEBUG no false Turns on debug logging. true
DNSWATCHER_MAINTENANCE_MODE no false Only changes one field in the health check reply and does nothing else. Leave it unset.
DNSWATCHER_DATA_DIR no, leave unset /var/lib/dnswatcher The directory for the state file. The image already sets it.
PORT no, leave unset 8080 The port the web server listens on inside the container.

With none of the three alert destinations set, dnswatcher still runs, but changes only show up on the dashboard.

Container

  • Volume: mount a host directory at /var/lib/dnswatcher. It holds one file, state.json. The container starts as root only to hand that directory to its own user (uid 10001), then runs as that user.
  • Port: the container listens on 8080.
  • Health check: the path is /.well-known/healthcheck. The image already checks it every 10 seconds, so there is nothing to set up for it in upaas.
  • No login: the dashboard (/) and /api/v1/status have no login, and they show every watched name and the recent alerts. upaas publishes a mapped port on every network interface of the host (sneak/upaas#113), so only map port 8080 if you want the dashboard public. Otherwise map no port and put the app on your reverse proxy's Docker network. The proxy then reaches it at upaas- followed by the app name, port 8080. Every reply carries Strict-Transport-Security, so serve it only under an HTTPS hostname.
  • Network: dnswatcher sends its DNS queries (port 53) straight to the root servers and to each domain's own nameservers. It never uses a local resolver. It also connects out on ports 80 and 443 to check ports and certificates. The image build runs the tests, and they query the real DNS too. Your check on fsn1app1 (#301 (comment)) shows its network passes DNS through untouched. A network that answers DNS queries itself makes the build and dnswatcher stop with "this network intercepts DNS queries" (#300).
  • Build time: the first build takes a few minutes, because it runs the linter and the tests before building.

What prod holds, and how to deploy

prod and main are both at e77e206, from 9 September. That is 92 commits behind next, where the release candidate (v1.0.0-rc3) is. Do not deploy prod as it stands: the image built from that commit exits at startup. next fixes this.

  1. Merge #152 (next into main).
  2. Once main has moved, I will open a pull request from main into prod, titled "main into prod", assigned to you, to be merged as a squash. Merging that pull request is the deploy, because upaas builds from prod.

Model: opus-5-5

@sneak here is what the upaas app needs, read from the config code on `next`, which is what you will be deploying. ## Environment variables Only `DNSWATCHER_TARGETS` is required. A value dnswatcher cannot read (for example `DNSWATCHER_DNS_INTERVAL=1d` or `DNSWATCHER_DEBUG=yes`) stops it at startup with an error naming the variable. An empty value is the same as not setting it. | Variable | Required | Default | What it does | Example | | --- | --- | --- | --- | --- | | `DNSWATCHER_TARGETS` | **yes**; it will not start without it | none | Comma-separated list of the names to watch. Put both domains (`example.com`) and hostnames (`www.example.com`) here; it works out which is which by itself. | `sneak.berlin,www.sneak.berlin,git.eeqj.de` | | `DNSWATCHER_NTFY_TOPIC` | no | none | Sends alerts to this ntfy topic. Give the full URL. | `https://ntfy.sh/my-dns-alerts` | | `DNSWATCHER_SLACK_WEBHOOK` | no | none | Sends alerts to this Slack incoming webhook URL. | `https://hooks.slack.com/services/T000/B000/XXXX` | | `DNSWATCHER_MATTERMOST_WEBHOOK` | no | none | Sends alerts to this Mattermost incoming webhook URL. | `https://mattermost.example.com/hooks/xxxx` | | `DNSWATCHER_SEND_TEST_NOTIFICATION` | no | `false` | When `true`, sends one "startup complete" message to every alert destination above after the first round of checks, on every start. This is a quick way to see that alerts arrive. | `true` | | `DNSWATCHER_SKIP_RECORD_NOTIFICATIONS` | no | none | Names from `DNSWATCHER_TARGETS` that should get no alert when their DNS records change or their nameservers disagree. They are still checked and still shown on the dashboard. A name that is not in `DNSWATCHER_TARGETS` stops startup. | `www.sneak.berlin` | | `DNSWATCHER_DNS_INTERVAL` | no | `1h` | How often DNS records and ports 80 and 443 are checked. Write a number and a unit `s`, `m` or `h`. There is no unit for days, so write `24h`. | `30m` | | `DNSWATCHER_TLS_INTERVAL` | no | `12h` | How often TLS certificates are checked, in the same format. | `6h` | | `DNSWATCHER_TLS_EXPIRY_WARNING` | no | `7` | How many days before a certificate expires to start warning about it. | `14` | | `DNSWATCHER_METRICS_USERNAME` | no | none | Turns on `/metrics` (Prometheus) behind a username and password. If this is not set, `/metrics` does not exist. | `prometheus` | | `DNSWATCHER_METRICS_PASSWORD` | yes, if the username is set | none | The password for `/metrics`. Setting the username without a password stops startup. | a long random string | | `DNSWATCHER_SENTRY_DSN` | no | none | Reports crashes in web requests to Sentry. A value Sentry cannot read stops startup. | `https://key@o0.ingest.sentry.io/0` | | `DNSWATCHER_DEBUG` | no | `false` | Turns on debug logging. | `true` | | `DNSWATCHER_MAINTENANCE_MODE` | no | `false` | Only changes one field in the health check reply and does nothing else. Leave it unset. | | | `DNSWATCHER_DATA_DIR` | no, leave unset | `/var/lib/dnswatcher` | The directory for the state file. The image already sets it. | | | `PORT` | no, leave unset | `8080` | The port the web server listens on inside the container. | | With none of the three alert destinations set, dnswatcher still runs, but changes only show up on the dashboard. ## Container - **Volume:** mount a host directory at `/var/lib/dnswatcher`. It holds one file, `state.json`. The container starts as root only to hand that directory to its own user (uid 10001), then runs as that user. - **Port:** the container listens on `8080`. - **Health check:** the path is `/.well-known/healthcheck`. The image already checks it every 10 seconds, so there is nothing to set up for it in upaas. - **No login:** the dashboard (`/`) and `/api/v1/status` have no login, and they show every watched name and the recent alerts. upaas publishes a mapped port on every network interface of the host (https://git.eeqj.de/sneak/upaas/issues/113), so only map port `8080` if you want the dashboard public. Otherwise map no port and put the app on your reverse proxy's Docker network. The proxy then reaches it at `upaas-` followed by the app name, port `8080`. Every reply carries `Strict-Transport-Security`, so serve it only under an HTTPS hostname. - **Network:** dnswatcher sends its DNS queries (port 53) straight to the root servers and to each domain's own nameservers. It never uses a local resolver. It also connects out on ports 80 and 443 to check ports and certificates. The image build runs the tests, and they query the real DNS too. Your check on fsn1app1 (https://git.eeqj.de/sneak/dnswatcher/pulls/301#issuecomment-144958) shows its network passes DNS through untouched. A network that answers DNS queries itself makes the build and dnswatcher stop with "this network intercepts DNS queries" (https://git.eeqj.de/sneak/dnswatcher/issues/300). - **Build time:** the first build takes a few minutes, because it runs the linter and the tests before building. ## What `prod` holds, and how to deploy `prod` and `main` are both at `e77e206`, from 9 September. That is 92 commits behind `next`, where the release candidate (`v1.0.0-rc3`) is. Do not deploy `prod` as it stands: the image built from that commit exits at startup. `next` fixes this. 1. Merge https://git.eeqj.de/sneak/dnswatcher/pulls/152 (`next` into `main`). 2. Once `main` has moved, I will open a pull request from `main` into `prod`, titled "main into prod", assigned to you, to be merged as a squash. Merging that pull request is the deploy, because upaas builds from `prod`. Model: opus-5-5
Author
Collaborator

@sneak merging #303 (main into prod, assigned to you) is the deploy. Merge it as a squash. Set up the upaas app with the settings above before you merge, so the first build deploys a working container.

Model: opus-5-5

@sneak merging https://git.eeqj.de/sneak/dnswatcher/pulls/303 (`main` into `prod`, assigned to you) is the deploy. Merge it as a squash. Set up the upaas app with the settings above before you merge, so the first build deploys a working container. Model: opus-5-5
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/dnswatcher#148