Skip to content

Latest commit

 

History

361 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

wanctl

wanctl controls devices across the public internet from a terminal or an AI agent's shell. It carries commands and files through an end-to-end-encrypted relay, while each device keeps final authority through a local approval policy.

Features

  • End-to-end mutual TLS 1.3 with Ed25519 identities and explicit fingerprint pinning.
  • Device-side policy for command, file, log, and elevated operations, including human approval on rule misses.
  • Friend relationships and per-device sharing with bounded exec/read/write capabilities.
  • GitHub OAuth login with first-user administration and invite-based admission.
  • One Go binary for relay, portal, agent, controller, and MCP roles.
  • Proxy-agnostic HTTP long-poll transport that works through ordinary reverse proxies; WebSocket remains optional.
  • CLI and MCP surfaces designed for scripted and AI-agent-driven control.

Quick start

For a persistent public deployment, follow the self-hosting guide. It starts Postgres, the relay, and the portal with Docker Compose and covers GitHub OAuth, HTTPS termination, admission, and device enrollment.

To try the encrypted relay path locally without Postgres or OAuth, run the local smoke test.

First run

A freshly installed binary does not yet know which instance it talks to. The first command that needs a relay asks, on a terminal, which one to use: the project's hosted instance at https://wanctl.z10.dev — invite-only, so sign in with GitHub there and ask for access — or a relay you run yourself. The answer is saved through the same machinery as wanctl config set relay=... portal=... and the command then carries on.

Nothing unattended is ever blocked by that question. It is skipped when a relay is already configured (a --relay flag, WANCTL_RELAY, the config file, or a value baked into the build), when stdin or stdout is not a terminal, and when WANCTL_NO_PROMPT=1 is set; those runs get an error that names both doors and the exact command for each instead.

Supported platforms

Every release ships signed binaries for the whole matrix below; the one-line installers (install.sh, install.ps1) detect the OS and CPU and fetch the matching one, and wanctl update does the same from inside the binary.

OS 64-bit 32-bit
Linux amd64, arm64 386, arm (armv6/v7), mips, mipsle (softfloat, routers)
macOS amd64, arm64 (Apple silicon) — (macOS has run no 32-bit code since Catalina)
Windows amd64, arm64 386
Android arm64, amd64 — binary + APK each arm (armeabi-v7a), 386 — binary + APK each

The list lives in scripts/release-targets.sh, which the release build, the publisher's checks and CI's cross-compile gate all read.

Staying up to date

A running wanctl agent keeps itself current. It checks the same signed release manifest wanctl update uses — a minute after it starts, then every six hours — and when a newer release is on offer it verifies the signature, swaps the binary and restarts itself in place, keeping its pid so systemd, launchd and wanctl status all still point at it. It waits while a shell session, a background job or a console session is open, and it never tries to elevate: a binary in a root-owned directory such as /usr/local/bin logs that sudo wanctl update is needed and leaves itself alone. Development builds are never replaced. Turn it off with wanctl config set auto_update=off (or WANCTL_AUTO_UPDATE=off); wanctl status shows which way it is set.

Architecture

controller (you/agent) --+                            +-- device (wanctl agent)
   wanctl exec/push/logs  |   relay (public broker)   |     policy engine + approval
                          +-- byte-pipe + registry ---+     JSONL event log
                          |   token auth + ACL + audit|
   E2E mutual-TLS ========+======== over the pipe ====+==== (relay sees only ciphertext)
                          |                           |
   portal (web, SSO) -----+  issues tokens, ACL -----+  (thin proxy to relay /admin/*)

The relay authenticates tokens and authorizes connections but cannot decrypt a session. Controllers and devices establish mutual TLS over the relayed byte pipe, then devices independently enforce local policy. The portal has no database of its own; it authenticates users and scopes calls to the relay's Postgres-backed admin API. See Architecture for the trust model, transports, sharing rules, and component map.

Build

wanctl requires the Go release named by the go directive in go.mod (currently 1.26.6); the Go tool downloads it automatically.

go build -o wanctl .
go test ./...

The same binary selects its role by subcommand:

wanctl relay --addr :8080
wanctl portal --addr :8080
wanctl agent --relay https://relay.example.com --token TOKEN --name DEVICE
wanctl peers                          # your online devices, plus any shared with you
wanctl exec --target DEVICE "uname -a"

Documentation

License

Licensed under the Apache License 2.0. See NOTICE for attribution information.

About

Cross-WAN remote device control for humans and AI agents: E2E-encrypted exec/file/logs over an untrusted relay

Resources

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages