---
title: "Our User-Mode WireGuard Year"
description: "Fly.io’s flyctl needed to let users SSH into Firecracker VMs and reach private 6PN networks without requiring root access or system-level WireGuard configuration. The solution runs wireguard-go, a userland TCP/IP stack derived from gVisor’s Go implementation, and golang.org/x/crypto/ssh inside flyctl, later coordinating sessions through a cross-platform background agent. The design initially exposed serious operational and usability problems: concurrent sessions displaced one another, agent behavior was fragile, and remote peer creation was slow, while deploys and remote builds expanded the mechanism’s role. The team improved concurrency, Windows support, DNS resolution, configuration handling, and peer-creation latency, and built an unmerged WebSocket path for networks blocking WireGuard’s UDP transport. The author concludes that the complexity was costly early in 2021 but enabled capabilities such as private DNS lookup and ping."
---

# Our User-Mode WireGuard Year

[Fly.io](https://yomu.fyi/company/fly-io) · Feb 9, 2022

**Type:** Explainer

## Summary

Fly.io’s flyctl needed to let users SSH into Firecracker VMs and reach private 6PN networks without requiring root access or system-level WireGuard configuration. The solution runs wireguard-go, a userland TCP/IP stack derived from gVisor’s Go implementation, and golang.org/x/crypto/ssh inside flyctl, later coordinating sessions through a cross-platform background agent. The design initially exposed serious operational and usability problems: concurrent sessions displaced one another, agent behavior was fragile, and remote peer creation was slow, while deploys and remote builds expanded the mechanism’s role. The team improved concurrency, Windows support, DNS resolution, configuration handling, and peer-creation latency, and built an unmerged WebSocket path for networks blocking WireGuard’s UDP transport. The author concludes that the complexity was costly early in 2021 but enabled capabilities such as private DNS lookup and ping.

## Context

Fly.io needed to provide shell access to app VMs and access to private 6PN networks from users’ laptops, but changing network configuration generally requires privileges on mainstream operating systems. Requiring root access or manual system WireGuard setup was considered unattractive. The implementation also encountered problems with concurrent sessions, background-agent behavior, slow peer creation, and networks that block UDP.

## Approach / What changed

flyctl embeds wireguard-go, a userland TCP/IP stack based on gVisor’s Go stack, and the Go SSH library to create WireGuard sessions and SSH connections without changing the host operating system’s network configuration. A background agent holds sessions for multiple flyctl processes, with Unix-domain socket support on Windows, a Windows-compatible DNS resolver, configuration-change detection, and later faster peer creation. A WebSocket-over-HTTPS transport was also built for environments that block WireGuard’s UDP transport, though its branch remained unmerged.

## Takeaways

- A single flyctl process can create a WireGuard VPN session, run a userland TCP/IP stack, and carry an SSH session over the resulting synthetic TCP connection.
- The initial design allowed a new WireGuard source to displace an existing SSH session; a persistent flyctl agent was introduced so multiple commands could share WireGuard sessions.
- The WebSocket transport uses an HTTPS endpoint upgraded to WebSockets to proxy length-prefixed WireGuard packets when UDP is unavailable, but the flyctl branch had not been merged.

**Tags:** [Go](https://yomu.fyi/topic/go), [SSH](https://yomu.fyi/topic/ssh), [WireGuard](https://yomu.fyi/topic/wireguard)

- Source: [Fly.io](https://fly.io/blog/our-user-mode-wireguard-year)
- Source URL: https://fly.io/blog/our-user-mode-wireguard-year
- Ingested by Yomu: 2026-09-03T01:24:52.983Z

[Read original post](https://fly.io/blog/our-user-mode-wireguard-year)
