gateway-domain: the backend needs tag:notplants-test-server

The tailnet ACL only permits the gateway to open connections to nodes tagged
tag:notplants-test-server. Map an untagged node and the gateway accepts the
mapping and then never connects — no error anywhere, and it presents as a
broken gateway rather than as a missing tag on your own box.

Nothing said so, and it is not discoverable from the failure. The skill now
leads with the requirement and the one-liner to check it, and names it as the
first thing to look at when traffic does not flow.

The tool also warns when the node it is about to map does not carry the tag.
It cannot check a backend given explicitly on the command line — it only sees
its own tags — so that case stays documented rather than enforced.

Found by mapping this orchestrator box (tag:orchestrator, tag:server) as a
smoke test: the mapping was written and looked entirely healthy.
This commit is contained in:
2026-08-20 18:01:41 +00:00
parent 22bd897a86
commit c7cbac6fb2
2 changed files with 54 additions and 4 deletions
+24 -4
View File
@@ -1,6 +1,6 @@
---
name: gateway-domain
description: Give a tailnet box a real public HTTPS domain (<name>.gtest.commoninternet.net) by mapping it on the shared testing gateway. Use when an agent needs a publicly reachable URL for a box with no public IP — an OAuth callback, a webhook receiver, a demo link, an ACME challenge. Covers the add/remove tool, where the admin password lives, and the traps (your box serves the TLS cert, not the gateway; hostname backends are unremovable).
description: Give a tailnet box a real public HTTPS domain (<name>.gtest.commoninternet.net) by mapping it on the shared testing gateway. Use when an agent needs a publicly reachable URL for a box with no public IP — an OAuth callback, a webhook receiver, a demo link, an ACME challenge. Covers the add/remove tool, where the admin password lives, and the two things that silently break it: your box must carry the tag:notplants-test-server tailnet tag or the ACL blocks the gateway from reaching it, and your box serves the TLS cert rather than the gateway.
---
# Giving your box a public domain
@@ -18,6 +18,25 @@ python3 engine/tools/gateway-domain.py add myapp
That is the whole happy path. The backend defaults to **this box's own tailscale IP**, so run
it on the machine that will serve the domain.
## Your box must carry the `notplants-test-server` tag
The tailnet ACL only permits the gateway to open connections to nodes tagged
**`tag:notplants-test-server`**. Without it the gateway accepts your mapping and then simply
never connects — which looks like a broken gateway and is not one. Check before you start:
```bash
tailscale status --json | jq -r '.Self.Tags[]?'
```
If `tag:notplants-test-server` is not listed, add it to that node in the Tailscale admin (a
node's tags are set when it is authenticated, so this may mean re-authenticating it), or map a
backend that already has the tag. `gateway-domain.py` warns when the node it is about to map
lacks the tag, but it cannot see the tags of a backend you name explicitly — that one is on you.
The gateway itself is tagged `tag:testing-gateway`; that is the other half of the same ACL rule.
## The commands
```bash
python3 engine/tools/gateway-domain.py list
python3 engine/tools/gateway-domain.py add myapp # this box, port 443
@@ -115,9 +134,10 @@ Check in this order — most failures are the last two.
1. `gateway-domain.py list` — is the mapping actually there?
2. `getent hosts myapp.gtest.commoninternet.net` — should be `49.13.156.72`.
3. Is your box reachable from the gateway on the tailnet? The gateway is `gateway-test-1`
(`100.91.44.90`), tagged `tag:testing-gateway`. If tailnet ACLs block it from reaching your
node, the mapping is correct and traffic still will not flow.
3. **Is your node tagged `tag:notplants-test-server`?** (`tailscale status --json | jq -r
'.Self.Tags[]?'`) This is the single most common cause. The gateway is `gateway-test-1`
(`100.91.44.90`), tagged `tag:testing-gateway`; the ACL pairs those two tags, so an
untagged backend is unreachable no matter how correct the mapping looks.
4. **Is your service actually serving TLS for that name on the backend port?** A backend that
speaks plain HTTP on 443, or serves a cert for a different name, fails here and nowhere else.