What is pigeons?
SSH to any machine without an IP address, behind a NAT or firewall, with no port forwarding and no VPN setup.
# on the server
> pigeons
# on the client — add a route, then ssh as normal
> pigeons
> ssh
That's it. ssh and sshd need to be installed.
Under the hood pigeons dials by public key over iroh, which establishes a direct QUIC connection between the two machines, hole-punching whenever it can and falling back to relay servers when it cannot.
pigeons add writes a Host entry to your SSH config whose ProxyCommand
runs pigeons fly --stdio, so ssh reaches the tunnel over that command's
stdin and stdout.
Installation
Download a binary for your operating system from Releases, or use the install script:
|
Getting Started
Server
Start a roost to accept incoming connections. Keys are persisted by default, so the endpoint ID stays the same across restarts:
> pigeons
Use --ephemeral for a throwaway identity, or --ssh-port when sshd listens
somewhere other than 22:
> pigeons
Client
Add a pigeon route, which writes an entry into your SSH config:
> pigeons
Then connect with standard ssh, from anywhere:
> ssh
Service Mode
Install pigeons as a system service for always-on access. Supported on Linux (systemd), macOS (launchd), and Windows (SCM):
> pigeons > pigeons > pigeons > pigeons
Rust Library
The tunnel is also usable as a library. Add it with cargo add iroh-pigeons;
the API is documented on docs.rs. Note that the crate is published
as iroh-pigeons while the CLI it installs is called pigeons.
Commands
# Server
> pigeons > pigeons > pigeons
# Client
> pigeons > pigeons > pigeons > pigeons > pigeons
# Service
> pigeons > pigeons > pigeons > pigeons > pigeons > pigeons
# Misc
> pigeons > pigeons
How It Works
┌──────────────┐ ┌─────────────────┐ ┌──────────────┐
│ SSH Client │───────▶│ QUIC Tunnel │───────▶│ pigeons │
│ │ │ (P2P Network) │ │ roost │
└──────────────┘ └─────────────────┘ └──────────────┘
│ ▲ │
│ │ │
▼ │ ▼
┌──────────────┐ ┌─────────────────┐ ┌──────────────┐
│ ProxyCommand │ │ pigeons fly │ │ SSH Server │
│ pigeons fly │───────▶│ --stdio │ │ localhost:22 │
│ --stdio │ │ │ └──────────────┘
└──────────────┘ └─────────────────┘
- SSH client invokes
pigeons fly --stdiothrough SSH'sProxyCommand. - Fly establishes a QUIC connection over iroh's P2P network, traversing NAT automatically.
- Roost accepts the connection and proxies it to the local SSH daemon.
- Authentication stays standard SSH, end-to-end over the encrypted tunnel.
Security Model
- Endpoint ID access: anyone holding the endpoint ID can reach your SSH port
- SSH authentication: standard SSH auth (keys, certificates, passwords) still applies
- Persistent keys: uses a dedicated
.ssh/pigeons_ed25519keypair - QUIC encryption: transport-layer encryption between endpoints
License
Copyright 2025 fun with rust y2
Copyright 2026 N0, INC.
This project is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.