Skip to content

Commit 48bef1c

Browse files
MattDHillclaude
andauthored
feat(start-tunnel): help sidebar, i18n, table sorting; rename Port Forwards to Published Ports (#3448)
- contextual help sidebar (per-screen + in-dialog) with links to the docs - i18n infrastructure + language switcher; English and Spanish dictionaries - sortable columns on the subnets, devices, published-ports, and DNS tables - rename Port Forwards -> Published Ports across UI + docs (CLI/RPC unchanged); device 'Auto Port Forward' capability -> 'Auto-publish' - DNS 'Name' column -> 'Hostname'; expand subnets/DNS docs Rolled into the unreleased 1.1.0 changelog; no version bump. Co-authored-by: Matt Hill <9935159+MattDHill@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5c29db4 commit 48bef1c

53 files changed

Lines changed: 2320 additions & 402 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"license": "MIT",
77
"scripts": {
88
"ng": "ng",
9-
"check": "npm run check:i18n && npm run check:i18n:wrt && npm run check:shared && npm run check:marketplace && npm run check:ui && npm run check:setup && npm run check:brochure && npm run check:wrt",
9+
"check": "npm run check:i18n && npm run check:i18n:tunnel && npm run check:i18n:wrt && npm run check:shared && npm run check:marketplace && npm run check:ui && npm run check:setup && npm run check:brochure && npm run check:wrt",
1010
"check:shared": "tsc --project shared-libs/ts-modules/shared/tsconfig.json --noEmit --skipLibCheck",
1111
"check:marketplace": "tsc --project shared-libs/ts-modules/marketplace/tsconfig.json --noEmit --skipLibCheck",
1212
"check:setup": "tsc --project projects/start-os/web/setup-wizard/tsconfig.json --noEmit --skipLibCheck",
@@ -15,6 +15,7 @@
1515
"check:brochure": "tsc --project projects/brochure-marketplace/tsconfig.json --noEmit --skipLibCheck",
1616
"check:wrt": "tsc --project projects/start-wrt/web/tsconfig.json --noEmit --skipLibCheck",
1717
"check:i18n": "node shared-libs/ts-modules/scripts/check-i18n.mjs",
18+
"check:i18n:tunnel": "node projects/start-tunnel/web/scripts/check-i18n.mjs",
1819
"check:i18n:wrt": "node projects/start-wrt/web/scripts/check-i18n.mjs",
1920
"build:patch-db": "cd shared-libs/crates/patch-db/client && npm ci && npm run build",
2021
"build:core": "cd shared-libs/ts-modules/start-core && make dist",

projects/start-tunnel/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,4 @@ rest of the Angular workspace via `make web-format`.
102102
User-facing changes (UI, CLI flags/output, install flow, subnet/device/forward
103103
behavior) must update `docs/src/` in the same change. The mdbook is published at
104104
`start9.com/start-tunnel/`. Reference: `docs/src/cli-reference.md`,
105-
`installing.md`, `subnets.md`, `devices.md`, `port-forwarding.md`.
105+
`installing.md`, `subnets.md`, `devices.md`, `published-ports.md`.

projects/start-tunnel/CHANGELOG.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
### Added
1313

14-
- **HTTP→HTTPS redirects on port 80.** StartTunnel now runs an HTTP→HTTPS redirect on port `80` of every public IPv4 it holds, so a plain `http://` request to an exposed service is answered with a redirect to the same host over `https://` instead of a connection error. These are **on by default** — every public IPv4 gets one on a fresh install and after an update — and reuse the same redirect handler the OS serves on its own TLS ports. Each address has a toggle in the **HTTP Redirect (80 → 443)** section of the `Settings` page (and `start-tunnel http-redirect list` / `set-enabled <ip> [--enabled]` on the CLI) to turn it off; your choice persists. A redirect and a port-80 forward are **mutually exclusive and never both enabled**: forwarding port 80 is rejected while the redirect is on (turn it off first), and enabling the redirect is rejected while port 80 is forwarded (delete the forward first). Port 80 is also never auto-forwarded — StartTunnel refuses PCP/UPnP requests to map it — and the add-forward dialog no longer offers to also forward `80 → 443`. See the HTTP Redirects page in the docs.
14+
- **HTTP→HTTPS redirects on port 80.** StartTunnel now runs an HTTP→HTTPS redirect on port `80` of every public IPv4 it holds, so a plain `http://` request to an exposed service is answered with a redirect to the same host over `https://` instead of a connection error. These are **on by default** — every public IPv4 gets one on a fresh install and after an update — and reuse the same redirect handler the OS serves on its own TLS ports. Each address has a toggle in the **HTTP Redirect (80 → 443)** section of the `Settings` page (and `start-tunnel http-redirect list` / `set-enabled <ip> [--enabled]` on the CLI) to turn it off; your choice persists. A redirect and a port-80 forward are **mutually exclusive and never both enabled**: forwarding port 80 is rejected while the redirect is on (turn it off first), and enabling the redirect is rejected while port 80 is forwarded (delete the forward first). Port 80 is also never auto-forwarded — StartTunnel refuses PCP/UPnP requests to map it — and the Add published port dialog no longer offers to also forward `80 → 443`. See the HTTP Redirects page in the docs.
1515

1616
- **Per-subnet IPv6.** A subnet can now carry a routed IPv6 prefix your VPS delegates, and every host on it — the tunnel and each device — gets one globally-routable `/128` with its tunnel IPv4 embedded (`prefix-network | tunnel-IPv4`), so a device's address is stable and derivable from its IPv4 alone. Configure it per subnet with `start-tunnel subnet <SUBNET> set-ipv6 --prefix <prefix>` or the subnet's Add/Edit dialog (disable by omitting the prefix). Configuring per subnet lets a server with multiple disjoint allocations point different subnets at different prefixes. On the common single-/64 case the tunnel answers Neighbor Discovery for each device's address on the VPS network; device IPv6 is carried full-tunnel (`AllowedIPs = ::/0`) so replies return through the tunnel. Devices can make outbound IPv6 connections, and — on a device running a current StartOS (0.4.0-beta.10+) — accept unsolicited inbound connections too, so a service can be hosted over IPv6. The subnets and devices tables show the prefix and each device's computed address. See the IPv6 page in the docs.
1717
- **`subnet … set-ipv6` validates the server can route the prefix.** Because a device with an IPv6 assignment routes all its IPv6 full-tunnel (`AllowedIPs = ::/0`), a prefix delegated on a server without working IPv6 egress just blackholes. The command **hard-errors** (leaving the config unchanged) when the server has no IPv6 default route, and logs an actionable warning when the prefix is neither on-link on a WAN interface nor otherwise verifiable — so operators catch a misconfigured VPS at set-time instead of discovering dead IPv6 on their devices.
18-
- **Port-range forwarding.** A manual port forward can now span a contiguous range of ports. Set "Number of Ports" in the Add Port Forward dialog — or `--count` on `start-tunnel port-forward add` — to forward that many consecutive ports counting up from both the external and internal port. Ranges are plain port forwards and cannot be combined with SNI demux. (Automatic PCP PORT_SET range forwarding requested by connected devices was already supported; this exposes it to manually-added forwards.)
19-
- **IPv6 port forwarding (firewall pinholes).** A port forward can now expose a device over IPv6, not just IPv4. Because each device has its own globally-routable address (its GUA — see the IPv6 page), an IPv6 forward is a firewall _pinhole_ on `[GUA]:port` with no NAT, rather than a DNAT from a shared public IPv4. The Add Port Forward dialog gained an **IP Version** selector (`IPv4` / `IPv6` / `IPv4 + IPv6`) so one dialog covers both stacks — the external/internal port fields apply to whichever you pick — and each forward's **External IP** is the public IPv4 (v4) or the device's GUA (v6). Choosing an external port different from the internal one (e.g. the `80 → 443` redirect) turns the v6 side into a port-only translation on the same GUA. IPv6 requires the selected server's subnet to have a routed prefix; the dialog says so when it doesn't. Manage them from the CLI with `start-tunnel pinhole add|remove|set-enabled|update-label`. Connected StartOS servers open v6 pinholes **automatically** via PCP (including the `80 → 443` redirect) the same way they already do for IPv4, so hosting a service over IPv6 works end to end.
18+
- **Port-range forwarding.** A manual port forward can now span a contiguous range of ports. Set "Number of Ports" in the Add published port dialog — or `--count` on `start-tunnel port-forward add` — to forward that many consecutive ports counting up from both the external and internal port. Ranges are plain port forwards and cannot be combined with SNI demux. (Automatic PCP PORT_SET range forwarding requested by connected devices was already supported; this exposes it to manually-added forwards.)
19+
- **IPv6 port forwarding (firewall pinholes).** A port forward can now expose a device over IPv6, not just IPv4. Because each device has its own globally-routable address (its GUA — see the IPv6 page), an IPv6 forward is a firewall _pinhole_ on `[GUA]:port` with no NAT, rather than a DNAT from a shared public IPv4. The Add published port dialog gained an **IP Version** selector (`IPv4` / `IPv6` / `IPv4 + IPv6`) so one dialog covers both stacks — the external/internal port fields apply to whichever you pick — and each published port's **IP** is the public IPv4 (v4) or the device's GUA (v6). Choosing an external port different from the internal one (e.g. the `80 → 443` redirect) turns the v6 side into a port-only translation on the same GUA. IPv6 requires the selected server's subnet to have a routed prefix; the dialog says so when it doesn't. Manage them from the CLI with `start-tunnel pinhole add|remove|set-enabled|update-label`. Connected StartOS servers open v6 pinholes **automatically** via PCP (including the `80 → 443` redirect) the same way they already do for IPv4, so hosting a service over IPv6 works end to end.
20+
- Contextual help sidebar with per-screen guidance, linking out to the docs.
21+
- Internationalization: a translatable UI with a language selector; English and Spanish included.
22+
- Sortable columns on the Subnets, Devices, Published Ports, and DNS tables.
2023

2124
### Changed
2225

2326
- **Automatic (PCP) mappings now honor their lease.** A forward, pinhole, or SNI route opened automatically by a connected device carries a finite lease that the device renews while it still wants the port. The tunnel now expires and tears down an automatic mapping whose device stops renewing it — because it went offline, rotated its key, or withdrew the exposure — instead of leaving a stale forward in place indefinitely. Manually-added forwards are unaffected and remain persistent.
24-
- **Admin actions retire a device's forwards immediately.** Deleting a device or demoting it to a client now clears all of its forwards, SNI routes, and IPv6 pinholes (previously a deleted device's v6 pinholes could linger); disabling **automatic port forwarding** for a device clears its automatic forwards while leaving any you added manually. Cleanup no longer waits for the lease to lapse.
27+
- **Admin actions retire a device's forwards immediately.** Deleting a device or demoting it to a client now clears all of its forwards, SNI routes, and IPv6 pinholes (previously a deleted device's v6 pinholes could linger); disabling **auto-publish** for a device clears its automatic forwards while leaving any you added manually. Cleanup no longer waits for the lease to lapse.
28+
- Renamed "Port Forwards" to "Published Ports" (and the device "Auto Port Forward" capability to "Auto-publish"); CLI/RPC unchanged.
29+
- Relabeled the DNS "Name" column as "Hostname".
2530

2631
### Fixed
2732

2833
- **`--version` now reports StartTunnel's own version** (`1.1.0`) instead of the StartOS
2934
platform version.
3035

36+
### Documentation
37+
38+
- Expanded the Subnets and DNS Records pages, and renamed the Port Forwarding page to Published Ports.
39+
3140
## [1.0.0]
3241

3342
- **Independent versioning.** `start-tunnel` now carries its own version (starting at `1.0.0`) in its `Cargo.toml`, decoupled from the StartOS release line; its `.deb` is versioned from the manifest.

projects/start-tunnel/docs/src/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ StartTunnel is a virtual private router (VPR) — a minimal, self-hosted router
1212

1313
- [Subnets](subnets.md)
1414
- [Devices](devices.md)
15-
- [Port Forwarding](port-forwarding.md)
15+
- [Published Ports](published-ports.md)
1616
- [Updating](updating.md)
1717
- [Uninstalling](uninstalling.md)
1818

projects/start-tunnel/docs/src/SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
- [Subnets](subnets.md)
1616
- [Devices](devices.md)
17-
- [Port Forwarding](port-forwarding.md)
17+
- [Published Ports](published-ports.md)
1818
- [HTTP Redirects](http-redirects.md)
1919
- [IPv6](ipv6.md)
2020
- [DNS Records](dns-records.md)

projects/start-tunnel/docs/src/architecture.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ StartTunnel is a virtual private router (VPR) — a minimal, self-hosted router
1414

1515
- **Create Subnets** — Each subnet is a private LAN, just like the one your home router creates
1616
- **Add Devices** — Servers, phones, laptops join the LAN and get an IP address and WireGuard config
17-
- **Forward Ports** — Expose specific ports on specific devices to the public Internet, just like port forwarding on a home router. StartTunnel also acts as a port-control gateway (PCP and UPnP), so a StartOS device can open its own ports automatically
17+
- **Publish Ports** — Expose specific ports on specific devices to the public Internet, the way a home router forwards ports to devices on your LAN. StartTunnel also acts as a port-control gateway (PCP and UPnP), so a StartOS device can open its own ports automatically
1818

1919
## How StartTunnel Compares
2020

2121
StartTunnel occupies a unique position between Cloudflare Tunnel and Tailscale. All three solve the problem of connecting devices across the Internet, but they make fundamentally different trade-offs around trust, control, and convenience.
2222

2323
### Architecture
2424

25-
**StartTunnel** is a virtual private router that runs on a VPS you control. Like a home router, it creates private networks, assigns IPs, and forwards ports — but using WireGuard tunnels instead of physical cables. Port forwarding uses kernel-level iptables NAT (Layer 3/4) to route public traffic to devices on the VPN. There is no central service, no coordination server, and no third party in the data path.
25+
**StartTunnel** is a virtual private router that runs on a VPS you control. Like a home router, it creates private networks, assigns IPs, and forwards ports — but using WireGuard tunnels instead of physical cables. Publishing a port uses kernel-level iptables NAT (Layer 3/4) to route public traffic to devices on the VPN. There is no central service, no coordination server, and no third party in the data path.
2626

2727
**Cloudflare Tunnel** runs a daemon (`cloudflared`) on your machine that makes outbound connections to Cloudflare's global edge network. Public traffic hits Cloudflare's CDN first, where Cloudflare terminates TLS, inspects the request at Layer 7, and proxies it to your origin through the tunnel.
2828

@@ -32,7 +32,7 @@ StartTunnel occupies a unique position between Cloudflare Tunnel and Tailscale.
3232

3333
This is the most important difference. It comes down to: **who can see your traffic?**
3434

35-
**StartTunnel**: Nobody but you. Port forwarding operates at Layer 3/4 (iptables DNAT), meaning the VPS rewrites IP headers and forwards packets without inspecting payloads. If a service uses HTTPS, TLS terminates at the service itself — the VPS never sees plaintext. For VPN traffic between devices, WireGuard provides end-to-end encryption. Since you own the VPS, there is no third party with access to your traffic or metadata.
35+
**StartTunnel**: Nobody but you. Published ports operate at Layer 3/4 (iptables DNAT), meaning the VPS rewrites IP headers and forwards packets without inspecting payloads. If a service uses HTTPS, TLS terminates at the service itself — the VPS never sees plaintext. For VPN traffic between devices, WireGuard provides end-to-end encryption. Since you own the VPS, there is no third party with access to your traffic or metadata.
3636

3737
**Cloudflare Tunnel**: Cloudflare terminates TLS at their edge and re-encrypts to your origin. This means Cloudflare can — and does — see plaintext traffic. They offer "TLS inspection" as a feature and can scan request bodies, filter content, and inject responses. Using Cloudflare Tunnel requires trusting a publicly traded company not to misuse its position as a man-in-the-middle on all your traffic.
3838

@@ -77,7 +77,7 @@ This is the most important difference. It comes down to: **who can see your traf
7777

7878
StartTunnel prioritizes sovereignty over convenience. That means:
7979

80-
- **No DDoS protection** — Your VPS IP is exposed on forwarded ports. Use your VPS provider's DDoS protection, or place a CDN in front if needed.
80+
- **No DDoS protection** — Your VPS IP is exposed on published ports. Use your VPS provider's DDoS protection, or place a CDN in front if needed.
8181
- **No global edge network** — Traffic routes through one VPS, not a global CDN. Latency depends on VPS location.
8282
- **No built-in DNS** — You manage your own DNS records.
8383
- **No identity provider integration** — Authentication is key-based and password-based, not SSO.
@@ -92,14 +92,14 @@ StartTunnel is built on [WireGuard](https://www.wireguard.com/), a modern VPN pr
9292
- **Encryption**: ChaCha20-Poly1305 for symmetric encryption, Curve25519 for key exchange, BLAKE2s for hashing
9393
- **Pre-shared keys**: Each peer connection uses an additional pre-shared key (PSK) for a layer of post-quantum resistance
9494
- **Key isolation**: Private keys are generated on-device and never leave the device. Only public keys are exchanged.
95-
- **TLS passthrough**: Port-forwarded traffic is not decrypted by the VPS. If your service uses HTTPS, TLS terminates at the service, not the tunnel.
95+
- **TLS passthrough**: Traffic to a published port is not decrypted by the VPS. If your service uses HTTPS, TLS terminates at the service, not the tunnel.
9696

9797
## Requirements
9898

9999
- Debian 13
100100
- x86_64, aarch64, or riscv64
101101
- Root access
102-
- Public IP (required for clearnet port forwarding; not required for private VPN use)
102+
- Public IP (required for publishing ports to the clearnet; not required for private VPN use)
103103

104104
## Source Code
105105

projects/start-tunnel/docs/src/cli-reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Manage devices within a subnet. Each device gets a unique WireGuard configuratio
8989

9090
Add a device to a subnet. Optionally assign a specific IP address.
9191

92-
- `--kind <client|server>` — Device kind (default `client`). A `server` enables gateway autoconfiguration (DNS injection + auto port forwarding) by default.
92+
- `--kind <client|server>` — Device kind (default `client`). A `server` enables gateway autoconfiguration (DNS injection + auto-publish) by default.
9393

9494
### `start-tunnel device list <SUBNET>`
9595

0 commit comments

Comments
 (0)