Compare commits

..
2 Commits
Author SHA1 Message Date
tgrosinger be0016c461 Skills: Add traefik-expose skill 2026-09-23 21:45:40 -07:00
tgrosinger cd5884598c tmux: Fix session close hook to exclude RAC sessions 2026-09-23 21:40:02 -07:00
2 changed files with 71 additions and 1 deletions
@@ -0,0 +1,66 @@
---
name: traefik-expose
description: Make a service on the tachi host reachable at https://NAME.i.grosinger.net through Traefik, or remove it. Use when asked to expose, register, route, or publish a dev server, host process, or docker container on an internal hostname, or to unexpose/deregister one.
---
> [!info] This skill only applies to the host `voyager`
> This skill may be synced to other hosts, but it only applies to `voyager`. If you are running on a different host and need to expose a service to an internal or external hostname, stop and ask for guidance from the user.
# traefik-expose — put a service on NAME.i.grosinger.net
Traefik on this host (`/tachi/docker`) serves `*.i.grosinger.net` on its `internal` entrypoint. That entrypoint is the default and already carries the wildcard TLS certificate and the home-only IP allowlist, and Blocky resolves every `*.i.grosinger.net` name to this host. So registering a service is only a routing rule and a target; there is no DNS, certificate, or middleware step.
Pick the branch by where the service runs.
## Host process (not in a container)
Register with the script in the docker repo:
```sh
/tachi/docker/traefik/expose NAME PORT # https://NAME.i.grosinger.net -> host:PORT
/tachi/docker/traefik/expose -l # list
/tachi/docker/traefik/expose -d NAME # remove
```
It writes one file to `traefik/dynamic.d/`, which Traefik watches, so the route is live within seconds and needs no restart. The file is gitignored.
The process must listen on `0.0.0.0` or on `172.19.0.1`. Traefik connects from inside its container network and cannot reach a listener bound to `127.0.0.1`, which most dev servers default to; pass the tool's host flag (`--host 0.0.0.0` or equivalent).
## Docker container
Join the container to the `docker_traefik` network and add labels. From a compose file outside `/tachi/docker`, declare the network as external:
```yaml
services:
myapp:
networks: [traefik]
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`myapp.i.grosinger.net`)"
- "traefik.http.services.myapp.loadbalancer.server.port=3000"
networks:
traefik:
external: true
name: docker_traefik
```
Inside `/tachi/docker/docker-compose.yaml` the network is simply `traefik`. Traefik ignores containers without `traefik.enable=true`. Always set the port label: it is the port the app listens on inside the container, not a published one, and no `ports:` mapping is needed. Removing the labels or the container removes the route.
## Verify
```sh
curl -sk -o /dev/null -w '%{http_code}\n' https://NAME.i.grosinger.net/
```
- **200-ish**: done.
- **502**: Traefik has the route but cannot reach the target. Host process: check the bind address with `ss -ltnp | grep PORT`. Container: check the port label matches what the app listens on and the container is on `docker_traefik`.
- **404**: Traefik has no router for that host. Ask the dashboard API, which needs no docker socket:
```sh
curl -sk https://traefik.i.grosinger.net/api/http/routers/NAME@file # host process
curl -sk https://traefik.i.grosinger.net/api/http/routers/NAME@docker # container
```
## Public exposure is a different task
Everything above is reachable only from the LAN and Tailscale. Making a service internet-facing means a real `grosinger.net` name, an explicit `traefik.http.routers.NAME.entrypoints=websecure` label, and a deliberate decision by the user. Do not add `websecure` when asked for an internal hostname.
+5 -1
View File
@@ -5,7 +5,11 @@ set-option -g renumber-windows on
set-option -g history-limit 10000
set -s escape-time 0
set-option -g detach-on-destroy off
set-hook -g session-closed 'choose-tree -Zs'
# This is a variant on the choose-tree hook that filters out Remote Access Console throw-away sessions
# to prevent dropping me into the session picker for automated actions.
#set-hook -g session-closed 'choose-tree -Zs'
set-hook -g session-closed "if -F '#{m:rac-*,#{hook_session_name}}' '' 'choose-tree -Zs'"
### Fix supporting italics
set -g default-terminal "tmux-256color"