Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"license": "MIT",
"scripts": {
"ng": "ng",
"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",
"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",
"check:shared": "tsc --project shared-libs/ts-modules/shared/tsconfig.json --noEmit --skipLibCheck",
"check:marketplace": "tsc --project shared-libs/ts-modules/marketplace/tsconfig.json --noEmit --skipLibCheck",
"check:setup": "tsc --project projects/start-os/web/setup-wizard/tsconfig.json --noEmit --skipLibCheck",
Expand All @@ -15,6 +15,7 @@
"check:brochure": "tsc --project projects/brochure-marketplace/tsconfig.json --noEmit --skipLibCheck",
"check:wrt": "tsc --project projects/start-wrt/web/tsconfig.json --noEmit --skipLibCheck",
"check:i18n": "node shared-libs/ts-modules/scripts/check-i18n.mjs",
"check:i18n:tunnel": "node projects/start-tunnel/web/scripts/check-i18n.mjs",
"check:i18n:wrt": "node projects/start-wrt/web/scripts/check-i18n.mjs",
"build:patch-db": "cd shared-libs/crates/patch-db/client && npm ci && npm run build",
"build:core": "cd shared-libs/ts-modules/start-core && make dist",
Expand Down
2 changes: 1 addition & 1 deletion projects/start-tunnel/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,4 @@ rest of the Angular workspace via `make web-format`.
User-facing changes (UI, CLI flags/output, install flow, subnet/device/forward
behavior) must update `docs/src/` in the same change. The mdbook is published at
`start9.com/start-tunnel/`. Reference: `docs/src/cli-reference.md`,
`installing.md`, `subnets.md`, `devices.md`, `port-forwarding.md`.
`installing.md`, `subnets.md`, `devices.md`, `published-ports.md`.
17 changes: 13 additions & 4 deletions projects/start-tunnel/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **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.
- **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.

- **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.
- **`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.
- **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.)
- **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.
- **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.)
- **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.
- Contextual help sidebar with per-screen guidance, linking out to the docs.
- Internationalization: a translatable UI with a language selector; English and Spanish included.
- Sortable columns on the Subnets, Devices, Published Ports, and DNS tables.

### Changed

- **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.
- **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.
- **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.
- Renamed "Port Forwards" to "Published Ports" (and the device "Auto Port Forward" capability to "Auto-publish"); CLI/RPC unchanged.
- Relabeled the DNS "Name" column as "Hostname".

### Fixed

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

### Documentation

- Expanded the Subnets and DNS Records pages, and renamed the Port Forwarding page to Published Ports.

## [1.0.0]

- **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.
Expand Down
2 changes: 1 addition & 1 deletion projects/start-tunnel/docs/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ StartTunnel is a virtual private router (VPR) — a minimal, self-hosted router

- [Subnets](subnets.md)
- [Devices](devices.md)
- [Port Forwarding](port-forwarding.md)
- [Published Ports](published-ports.md)
- [Updating](updating.md)
- [Uninstalling](uninstalling.md)

Expand Down
2 changes: 1 addition & 1 deletion projects/start-tunnel/docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

- [Subnets](subnets.md)
- [Devices](devices.md)
- [Port Forwarding](port-forwarding.md)
- [Published Ports](published-ports.md)
- [HTTP Redirects](http-redirects.md)
- [IPv6](ipv6.md)
- [DNS Records](dns-records.md)
Expand Down
12 changes: 6 additions & 6 deletions projects/start-tunnel/docs/src/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ StartTunnel is a virtual private router (VPR) — a minimal, self-hosted router

- **Create Subnets** — Each subnet is a private LAN, just like the one your home router creates
- **Add Devices** — Servers, phones, laptops join the LAN and get an IP address and WireGuard config
- **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
- **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

## How StartTunnel Compares

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.

### Architecture

**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.
**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.

**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.

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

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

**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.
**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.

**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.

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

StartTunnel prioritizes sovereignty over convenience. That means:

- **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.
- **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.
- **No global edge network** — Traffic routes through one VPS, not a global CDN. Latency depends on VPS location.
- **No built-in DNS** — You manage your own DNS records.
- **No identity provider integration** — Authentication is key-based and password-based, not SSO.
Expand All @@ -92,14 +92,14 @@ StartTunnel is built on [WireGuard](https://www.wireguard.com/), a modern VPN pr
- **Encryption**: ChaCha20-Poly1305 for symmetric encryption, Curve25519 for key exchange, BLAKE2s for hashing
- **Pre-shared keys**: Each peer connection uses an additional pre-shared key (PSK) for a layer of post-quantum resistance
- **Key isolation**: Private keys are generated on-device and never leave the device. Only public keys are exchanged.
- **TLS passthrough**: Port-forwarded traffic is not decrypted by the VPS. If your service uses HTTPS, TLS terminates at the service, not the tunnel.
- **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.

## Requirements

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

## Source Code

Expand Down
2 changes: 1 addition & 1 deletion projects/start-tunnel/docs/src/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Manage devices within a subnet. Each device gets a unique WireGuard configuratio

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

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

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

Expand Down
Loading