Add support for advertising Tailscale Services - #715
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a disabled-by-default ChangesTailscale Services
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant share-services
participant Tailscale Serve
participant Tailscale status
share-services->>Tailscale Serve: Read current serve configuration
share-services->>Tailscale Serve: Remove stale service entries
share-services->>Tailscale status: Check HTTPS capability when required
share-services->>Tailscale Serve: Advertise configured target
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tailscale/rootfs/etc/s6-overlay/scripts/stage2_hook.sh (1)
138-140: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse
rm -fto prevent potential startup failures.While the container filesystem is typically recreated on every start, adding the
-fflag ensures the script won't fail and crash the startup process if theshare-servicescontents file is already missing or cannot be removed.🛠️ Proposed fix
if ! bashio::config 'services' | jq -e '. | length > 0' > /dev/null; then - rm /etc/s6-overlay/s6-rc.d/user/contents.d/share-services + rm -f /etc/s6-overlay/s6-rc.d/user/contents.d/share-services fi🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tailscale/rootfs/etc/s6-overlay/scripts/stage2_hook.sh` around lines 138 - 140, Update the cleanup command in the services configuration check of stage2_hook.sh to use rm -f when removing the share-services contents file, so an already-missing file does not fail startup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tailscale/rootfs/etc/s6-overlay/scripts/stage2_hook.sh`:
- Around line 138-140: Update the cleanup command in the services configuration
check of stage2_hook.sh to use rm -f when removing the share-services contents
file, so an already-missing file does not fail startup.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6fec5516-8be6-4b0a-b556-1608b8e2d9ce
📒 Files selected for processing (9)
tailscale/DOCS.mdtailscale/config.yamltailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/dependencies.d/post-tailscaledtailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/runtailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/typetailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/uptailscale/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/share-servicestailscale/rootfs/etc/s6-overlay/scripts/stage2_hook.shtailscale/translations/en.yaml
2ca7ee2 to
1575c1d
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tailscale/DOCS.md`:
- Around line 342-344: Update the https service description in the Tailscale
documentation to state that tailnet HTTPS certificates and MagicDNS must be
enabled beforehand, while retaining the note that Tailscale provisions the TLS
certificate automatically once those prerequisites are met.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9e896e75-70d3-41e7-acf1-5ba217281b30
📒 Files selected for processing (9)
tailscale/DOCS.mdtailscale/config.yamltailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/dependencies.d/post-tailscaledtailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/runtailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/typetailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/uptailscale/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/share-servicestailscale/rootfs/etc/s6-overlay/scripts/stage2_hook.shtailscale/translations/en.yaml
🚧 Files skipped from review as they are similar to previous changes (6)
- tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/type
- tailscale/translations/en.yaml
- tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/up
- tailscale/rootfs/etc/s6-overlay/scripts/stage2_hook.sh
- tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/run
- tailscale/config.yaml
1575c1d to
0b889d6
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tailscale/config.yaml`:
- Line 84: Update the target regex in the configuration’s target validation to
enforce the same valid port range, 1–65535, instead of accepting any digits
after 127.0.0.1. Preserve support for both http(s) and tcp schemes and local
ports within the valid range.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b5944bed-00f9-4282-9fd0-f289f39099c0
📒 Files selected for processing (9)
tailscale/DOCS.mdtailscale/config.yamltailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/dependencies.d/post-tailscaledtailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/runtailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/typetailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/uptailscale/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/share-servicestailscale/rootfs/etc/s6-overlay/scripts/stage2_hook.shtailscale/translations/en.yaml
🚧 Files skipped from review as they are similar to previous changes (5)
- tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/up
- tailscale/rootfs/etc/s6-overlay/scripts/stage2_hook.sh
- tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/type
- tailscale/DOCS.md
- tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/run
This adds a new `services` configuration option that allows users to advertise local services running on the Home Assistant host as Tailscale Services. A new S6 oneshot service `share-services` reads the configured services and calls `tailscale serve --service=svc:<name>` for each entry. The `svc:` prefix is added automatically; users configure the plain service name. Supported protocols are `http`, `https`, `tcp`, and `tls-terminated-tcp`. Services must be defined and approved in the Tailscale admin console before they can accept traffic. Also updates the app documentation and translations for the new option.
0b889d6 to
3379686
Compare
|
And now a general comment. The share_homeassistant option worked similarly a few years ago ("recreating" TS serve/funnel config), and as far as I remember there were complaints, that it comflicted manually configured serve configs, that's why that was changed to a front running serve/funnel with --bg=false. So, when this change is merged, it will delete previously manually configured serve configs for the services. Hmmm, I think we should mark it (potentially) breaking change. The removal is logged, so I think it's fine. |
|
@lmagyar Thanks for all the good feedback. I will work it in over the next week. |
|
I've just marked it draft until you work on it. |
|
@lmagyar I implemented most of it now. But it feels a hard to keep track. Is it okay if I close the worked of conversations? Or do you want to close them during a review later? I still need to test all the variants to expose the services now. |
|
Feel free to do as you wish. :) I will remember what I've commented. Meanwhile I'm thinking to leave share_homeassistant option as-is: that can use funnel also, but funnel is incompatible with services, and the current foreground running service behind share_homeassistant doesn't interfere with services (the port thing). Maybe we can add a comment to the share_homeassistant option to the docs, that if somebody wants to share HA with services, use the services option instead. |
|
Tried my best, to address everything in a meaningful way. I need to still test all protocols though. |
|
Alright, I created a test Home Assistant App providing HTTP and TCP ports and configured the corresponding services in my Tailnet: services:
- name: svc:http
target: http://127.0.0.1:8090
protocol: http
port: 8090
- name: svc:https
target: http://127.0.0.1:8090
protocol: https
port: 443
- protocol: tls-terminated-tcp
name: svc:tls-tcp
target: tcp://127.0.0.1:8092
port: 8093
- name: svc:tcp
target: tcp://127.0.0.1:8092
protocol: tcp
port: 8092And a client: go run . --tailnet=tailaa.ts.net --http-service=http --http-port=8090 --https-service=https --tcp-service=tcp --tcp-port=8092 --tls-tcp-service=tls-tcp --tls-tcp-port=8093
ADDRESS PROTOCOL RESULT DETAIL
http.tailaa.ts.net:8090 HTTP PASS
https.tailaa.ts.net:443 HTTPS PASS
tcp.tailaa.ts.net:8092 TCP PASS
tls-tcp.tailaa.ts.net:8093 TLS-TCP PASS |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/run`:
- Around line 45-53: The stale-service reconciliation must operate once per
Service name rather than once per entry: at lines 45-53, retain the drain
operation without immediately clearing the service, and defer clear until
draining connections have completed; at lines 89-95, remove the unconditional
per-entry clear and group mappings by service name before reconciliation so
endpoints from earlier entries are not deleted prematurely.
In `@tailscale/translations/en.yaml`:
- Around line 82-83: Align the service-name contract across the supplied schema,
runtime normalization, and documentation: choose whether users provide the svc:
prefix or omit it, then update validation and normalization to accept and
produce that same form consistently. Update the service-name documentation near
this text to match the selected contract.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f350ff59-f1d0-4867-b278-c4349d84b34b
📒 Files selected for processing (4)
tailscale/DOCS.mdtailscale/config.yamltailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/runtailscale/translations/en.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
- tailscale/config.yaml
- tailscale/DOCS.md
| for service_name in "${current_names[@]}"; do | ||
| if ! printf '%s\n' "${configured_names[@]}" | grep -qx "${service_name}"; then | ||
| bashio::log.info "Removing stale service host configuration for ${service_name}" | ||
| if ! /opt/tailscale serve drain "${service_name}" >/dev/null 2>&1; then | ||
| bashio::log.warning "Failed to drain stale service host ${service_name}" | ||
| fi | ||
| if ! /opt/tailscale serve clear "${service_name}" >/dev/null 2>&1; then | ||
| bashio::log.warning "Failed to clear stale service host ${service_name}" | ||
| fi |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Do not clear a Service immediately after draining it.
drain preserves existing connections until they close; calling clear immediately afterward terminates that grace period. The per-entry cleanup also deletes endpoints added by an earlier entry with the same Service name. Reconcile once per Service and wait for draining connections before clearing obsolete mappings. (tailscale.com)
tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/run#L45-L53: defer clearing stale services until their drain completes.tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/run#L89-L95: avoid unconditional per-entry clear; group mappings by service name before reconciliation.
📍 Affects 1 file
tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/run#L45-L53(this comment)tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/run#L89-L95
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tailscale/rootfs/etc/s6-overlay/s6-rc.d/share-services/run` around lines 45 -
53, The stale-service reconciliation must operate once per Service name rather
than once per entry: at lines 45-53, retain the drain operation without
immediately clearing the service, and defer clear until draining connections
have completed; at lines 89-95, remove the unconditional per-entry clear and
group mappings by service name before reconciliation so endpoints from earlier
entries are not deleted prematurely.
|
Give me some time... :) |
Proposed Changes
This adds a new
servicesconfiguration option that allows users to advertise local services running on the Home Assistant host as Tailscale Services.A new S6 oneshot service
share-servicesreads the configured services and callstailscale serve --service=svc:<name>for each entry. Thesvc:prefix needs to be added in the config manually, following thetag:.Supported protocols are
http,https,tcp, andtls-terminated-tcp. Services must be defined and approved in the Tailscale admin console before they can accept traffic.Also updates the app documentation and translations for the new option.
Related Issues
None. As far as I have looked into the issues.
Summary by CodeRabbit
New Features
Documentation