Skywire in brief
- Skywire is an overlay network. Programs called visors run on computers, phones and browser tabs, connect to each other over the internet and local networks, and carry traffic for one another.
- A visor’s public key is its address. Every connection proves the key at the other end with a Noise handshake, and every handshake also runs a post-quantum key exchange (ML-KEM-768). There is no plaintext mode and no certificate authority.
- Traffic travels on routes, chains of direct links between visors that run one hop or several. A visor calculates routes itself from what it already knows, or asks a route finder, and a small policy program can decide how each connection is routed.
- One connection can use several routes at once. Its streams spread over separate tunnels, and inside a tunnel its packets are striped over legs that take different paths, so cutting one path does not end the connection and no single path carries all of it.
- Apps come with every visor: a VPN, a SOCKS5 proxy, chat with groups and voice calls, mail, port forwarding, a remote shell, and websites published on the visor’s key and opened by name.
- The same program runs as a full visor in a browser tab at skywire.dev. The native program also carries a Skycoin node and wallet, a CXO node and every service a Skywire network needs.
What Skywire is
Skywire is Skycoin’s open-source networking software and the network its users form with it. It is an encrypted peer-to-peer overlay network. It runs on top of the internet and local networks, and the machines on it reach each other by public key rather than by IP address.
The program that joins the network is called a visor, a word chosen because “node” usually means the hardware it runs on. Each visor makes its own key pair. Other visors dial its public key wherever it is, and that includes a visor behind a home router with no open port.
Visors connect to each other with transports, encrypted links over TCP, UDP, QUIC, WebSocket, WebTransport or WebRTC, or relayed through a dmsg server. On top of transports a visor builds routes, which may pass through other visors, and on top of routes it runs apps. Transports and routes each have their own encryption.
All of Skywire is one Go program, skywire, under the AGPL-3.0 license. It runs on Linux, Windows and macOS, there is an Android app, and the same program built for WebAssembly runs as a visor in a browser tab. More than a thousand visors run on the public network, as the live charts at status.skywire.dev show.
Why the key is the address
On the internet the address, the identity and the name live in three separate systems. IP addresses come from whoever runs the network, names come from DNS, and identity comes from certificates issued by certificate authorities. Each was added to fix a gap in the others, and an attack on any one of them, such as a hijacked route, a poisoned name or a wrongly issued certificate, breaks the rest.
Skywire starts from one decision: the address is the cryptographic identity. You dial a public key, and the handshake succeeds only if the other end holds the matching private key. There is no name to register, no certificate to buy and nothing between the name and the key that could be swapped out. The same holds for every operation, whether a transport, a route, an app connection, a CLI command or a hypervisor managing a visor.
Identity and encryption
A visor’s public key is a 33-byte secp256k1 key. It is written as 66 hex characters or as 53 base32 characters. The base32 form fits in a DNS label, which is why mesh names use it.
Every transport between two visors begins with a Noise KK handshake. Both sides already know each other’s public key, and each proves it holds its own private key. Traffic is then encrypted with ChaCha20-Poly1305. There is no setting to turn this off.
A route adds a second layer. The two ends of a route run their own Noise session over it, so the visors in the middle forward packets they cannot read. Each of them knows only the visor before it and the visor after it, not where the route starts or ends.
Every Noise handshake in Skywire, whether for dmsg, a transport or a route, is also post-quantum hybrid. The handshake messages carry an ML-KEM-768 key exchange, and its secret is mixed into the session keys, so reading recorded traffic needs both X25519 and ML-KEM-768 broken. The aim is to protect traffic recorded today from a quantum computer later. Visors have negotiated the hybrid since v1.3.80 in June 2026, and since October 2026 a handshake that leaves it out is refused in both directions (#5641), because an attacker could otherwise strip the post-quantum part from an unauthenticated offer.
Transports, the links between visors
A transport is a link that a visor creates to another visor and that its router can use as one hop of a route. Each transport runs a Noise session with a yamux stream multiplexer over a carrier. Its ID is fixed by the two keys and the type, so adding the same transport twice does nothing.
| Type | Carrier | What it is for |
|---|---|---|
stcpr | TCP | The peer’s address comes from the address resolver. The most reliable direct type. |
stcp | TCP | Addresses from a local table, for a LAN or a fixed setup. |
sudph | UDP | Hole punched, so two visors behind NAT can link directly. |
squicr | QUIC | QUIC’s own TLS is also bound to the visor’s key. |
swsr | WebSocket | Between visors directly. A browser visor can dial it. |
swtr | WebTransport | HTTP/3 with a short-lived certificate pinned by its hash, no CA and no domain. A browser visor can dial it. |
webrtc | WebRTC data channel | Through NAT by ICE, signalled over dmsg. Works between two browser tabs. |
dmsg | dmsg relay | Through a dmsg server. It can always be made, and it is the only relayed type. |
The names follow a pattern. The leading s means the Skywire Noise session runs over that carrier, and a trailing r means the peer’s address comes from the address resolver. sudph is the exception, UDP with hole punching.
A visor fills itself with transports on its own. Public autoconnect, on by default, dials stcpr transports to public visors and sudph transports to visors connected to them, so a new visor soon has enough links for routes of several hops. To find a peer’s address, a visor needs no central lookup most of the time. Every visor serves a signed reach card with its own addresses (#5512). A dialer uses a card it already holds, or else the address resolver’s bindings feed while it fetches the peer’s card (#5449), and asks the resolver only when neither answers. sudph still goes through the resolver, which also asks the peer to dial back.
A transport can also be made from the other side. A transport setup node can ask a visor that trusts it to dial a given key, which is how you get a direct transport from a visor behind NAT. In the browser, a visor can dial WebSocket, WebTransport, WebRTC and dmsg, and with the host bridge it gains stcpr and sudph too.
In this article, “transport” always means a link a visor made and can route over. A bare encrypted link between two keys outside that, such as two dmsg clients talking to each other, is a connection.
dmsg, the relay that is always there
dmsg (read “D-message”) is Skywire’s relay network. A dmsg client connects out to dmsg servers, over TCP, QUIC, WebSocket or WebTransport, so neither side needs an open port. To reach another key, the server passes an encrypted stream between the two clients. It cannot read the stream, and neither client learns the other’s IP address. dmsg servers forward to each other too, so two clients on different servers still meet.
That makes dmsg the one transport type that can always be established, and it is how a new visor gets started. It reaches the network’s services and its first peers over dmsg, then builds direct transports. dmsg between two visors is a transport like any other and can be one hop of a route.
dmsg also runs over Skywire itself. A visor relays dmsg-style streams for peers it has transports to, signed by the visor that started them, so a .dmsg address can be reached over a direct transport with no dmsg server involved (#3814, #3818). The resolving proxy can carry dmsg over the same transport it uses for skynet (#5506). The direction is for dmsg servers to be needed only to bootstrap and as a fallback, once a visor has its own transports. That move is under way and not finished.
Routing
Routing is what Skywire is built around. A connection between two apps does not travel through one fixed hop or along one fixed path. It travels on a route the visor chooses for it, and it can travel on several at the same time. The privacy, the resilience and most of the engineering of the project come from here.
Routes and route groups
A route is a chain of one or more transports from one visor to another. A route may not pass through the same key twice, which rules out loops. A route with one hop uses a direct transport, and a route with more hops passes through other visors, each of which forwards packets by a rule it was given for that route.
An app connection rides a route group, a forward route and a reverse route. The two need not take the same path, and each direction can ask for its own minimum number of hops and its own number of parallel legs.
Route rules are installed by route setup. A route setup node signs a capability for each hop and is never on the data path, and a visor installs rules only for setup nodes it trusts. The forward and reverse setups are sent together. Two visors that already share a transport skip the setup node altogether and build a one-hop route between themselves (#5465).
Finding routes from partial knowledge
Skywire has a route finder service that holds the whole transport graph and can answer any query. A visor does not need it for most routes, because it usually knows enough to route on its own. When it dials, it tries these in order and stops at the first that gives a route:
- A transport it already holds. If a direct transport to the destination exists and one hop is allowed, that is the route, and no service is asked.
- Two hops from both ends’ lists. The visor asks the destination for its own transport list through a query signed by a route setup node, and intersects it with its own. A shared neighbour is a two-hop route.
- Three hops from the neighbours’ lists. Every visor serves its live transports, signed by its key, to any visor that asks over a Skywire transport (#5488). Reading its neighbours’ lists gives a visor the middle link of a three-hop route (#5489).
- A hypervisor’s own graph. A hypervisor already holds the transports of the visors it manages, so it routes to them from that graph (#4751).
- The route finder. If none of these gives a route, the visor asks the route finder. A visor can also be told to calculate every route locally, from the transport discovery’s routing feed.
The point is that routing uses partial data. No visor needs the whole network graph, and the data it does use comes signed from the visors it describes, not from a central list. The route finder stays as the simple path for a device that cannot afford to search a graph, such as a small board or a browser tab.
Routing policies
How a connection is routed can be programmed. A routing policy is a small program the visor runs when a connection is dialed and again on a timer while it is open. It decides how many legs to run, how many hops each needs, and which peers and transports to prefer or avoid. Policies are written in Starlark or compiled to WebAssembly, run sandboxed within a time budget, and reload when the file changes.
Twelve presets are built in, among them rotating-bw, latency-adaptive, elastic-mux, geo-avoid, transport-diverse, trust-tiered, and coupled and ledbat, which follow MPTCP’s coupled congestion control and RFC 6817. Example policies in the repository avoid transit through one country, use only trusted intermediates, stop a VPN when no acceptable route exists, or change routing with the time of day. A policy applies to one app, to every dial, or to a running app without a restart, and skywire cli route policy test shows what it would decide before you use it. See multipath routes and routing policies.
Route multiplexing
Skywire can carry one connection over several routes at once, and it does so at two levels that work together.
Stream level. An app such as the SOCKS5 client opens several tunnels to the same exit. Each tunnel is its own route group with its own Noise session and stream multiplexer, and new streams spread across them. No two active tunnels leave over the same first hop, and a pool of standby tunnels stays dialed and ready to take over. One download can be split into HTTP range requests over separate tunnels and put back together by offset, and a tunnel that stops delivering is set aside while its share goes elsewhere. These ideas come from BitTorrent, where one file comes from many peers.
Packet level. Inside one tunnel the route group holds several legs, each a separate route over a different first hop. Frames are striped across the legs. A scheduler sends each frame on the leg expected to deliver it soonest (ECF, from multipath TCP research), a reorder buffer puts frames back in order, lost frames are detected with RACK-TLP and sent again on another leg, and Reed-Solomon repair symbols can rebuild a frame stuck on a slow leg.
Both at once. By default each active tunnel holds two legs, and it keeps them while idle (#5135), so a second path is already up when the first one is cut. The arrangement is described as a shape, k tunnels of n legs. 4x1 is pure stream level, four tunnels with one leg each. 1x4 is pure packet level, one tunnel with four legs. An operator can name a shape with the mux.shape setting, and the router moves a live session toward it one step at a time. A standby route becomes a leg, a leg goes back to standby, or a tunnel is promoted or parked, and no route is torn down to do it (#5142).
Fail-over and privacy, not speed
Packet-level legs are there for fail-over and privacy. They are not there to make one connection faster, and a shape that spends its routes on legs moves somewhat less data than the same routes spent on separate tunnels. That cost is accepted.
Fail-over. When a leg is cut, the frames it was carrying are sent again on another leg from the retransmit buffer, and the app is not meant to notice. Because the legs are held while idle, the second path does not have to be dialed after the first one fails.
Privacy. No single path carries the whole connection. A visor that is a hop on one leg, or someone watching one link, sees only part of the traffic and does not know where the route starts or ends. Spread limits such as spread.max_share keep any one route from carrying more than a set share of an object. Transports also carry many unrelated flows at once, which makes matching traffic in to traffic out harder.
The comparison in the Skywire README sets twelve networks side by side. Skywire is the only one there that has all six of dialing by key, reaching a node with no open port, hole punching, multi-hop routing, multi-path transfer and carrying IP traffic. Among the others, Tor’s Conflux splits a stream over two circuits to the same exit, and iroh keeps standby paths behind a single active one.
What is proven and what is still being tested
Proven on the live network
- Packet-level striping over legs that share no transport, with route setup standing up several disjoint legs at once.
- A leg that stops delivering is probed and replaced, and the reorder buffer keeps the encrypted stream intact.
- In a test against an exit on 16 October 2026, downloads striped across two legs over different transport types (stcpr and squicr), and a 40 MB download finished while one leg was cut under load.
Still being tested
- That same test found two defects. A two-hop tunnel never got its second leg, and losing a QUIC leg under load closed the whole tunnel. Both are fixed (#5700, with a follow-up in #5701) and are being tested again live.
- Fail-over on legs of two or more hops.
- New streams spreading across several tunnels to one exit at the same time is built and covered by tests, and has not yet been seen on the live network.
Skynet: services by key
Skynet is the routed side of Skywire. A key is dialed over transports and routes, as opposed to dmsg, where a server relays the stream. Every visor has ports of its own, and a service published on one is reached at the visor’s key, with no domain, no open port and no certificate on the visor’s side. The service itself only listens on localhost.
Names come in two suffixes. <key>.skynet goes over transports and routes, and <key>.dmsg reaches the same visor over dmsg. The key can be hex or base32, and a name to the left of the key picks a site on that visor. For example, the project’s status page is served by a visor at
http://status.skywire.dev.aka2cawifaqoqejwrsgqfdhrdmnjqucdw4tldpg3r7hitmttqszmw.skynet/
That connects to port 80 of the visor whose key is the long label and asks for the site status.skywire.dev. One visor can serve many sites this way. skywire cli serve vhost add blog --to 127.0.0.1:8080 publishes a named site, and a catch-all vhost hands every name to a web server such as Caddy, which then serves its own sites over the mesh too. Port forwarding works in both directions, exposing a local port on the visor’s key or bringing a remote key:port to a local port, with a whitelist of keys for access.
Programs reach these names in several ways:
- the resolving proxy, a SOCKS5 proxy built into the visor that resolves
.dmsgand.skynetnames and dials them over the mesh, and that the SOCKS5 client app answers too; - SkyDNS, which makes the names work in every program on the computer with no proxy setting. It starts by default on Linux with systemd-resolved (#5691) and works on Android;
- a local certificate authority, so a browser opens mesh sites over HTTPS with a padlock and no public CA;
- the browser visor’s own browser, and links such as
skywire.dev/?skynet=<name>that open a mesh site from anywhere.
home.skynet is a directory every visor serves. It lists the network’s services, the visor’s own sites and those of the visors it manages, and every visor the address resolver knows (#5694, #5698). Mail uses the same names, so anyone@<base32 key>.skynet is a working address. See mesh addresses and publishing a site.
Managing visors
Skywire is a full networking suite, and the tools for running it travel over the same key-authenticated network.
The hypervisor. Any visor can manage others. It serves a web dashboard and the desk, the browser desktop described below, and the visors it manages dial out to it, so they can sit behind NAT. Each managed visor lists the hypervisor’s key, and that list, the visor’s own key and a pty whitelist are the only keys allowed to control it. The dashboard login is hashed with Argon2id (#5639).
The command line. skywire cli drives everything a visor does: transports, routes, apps, routing policies, settings and logs. With --via dmsg://<key> the same commands drive a visor on another machine. skywire cli visor state reads a running visor’s whole state in one call, hv map draws a tree of managed visors and what each runs, every command can print JSON, and a jq filter is built in.
The pty. skywire cli pty gives a remote shell, one-shot command execution and a remote filesystem mount, addressed by key over dmsg, skynet or direct TCP. The server’s key is pinned by a Noise XK handshake and the client is allowed by its key alone, the way authorized_keys works for SSH, without SSH being involved. A browser visor answers with its own shell. gotop --remote shows another visor’s CPU, memory and temperature, and visor log --via reads its log.
What comes with every visor
The apps run inside the visor process. Server apps register in service discovery, and clients dial them by key over a direct or multi-hop route.
- VPN
- A client and server that carry all of a machine’s IP traffic to an exit visor. A VPN router can serve a whole LAN and answers
.dmsgand.skynetnames for programs on it. - SOCKS5 proxy
- skysocks carries one application’s traffic, uses the multiplexing above, picks and checks exits on its own, and answers mesh names itself.
- Skychat
- Direct and group messages, voice calls and file sending, with history kept in CXO and bbolt. It runs in the terminal and in the browser desk.
- Every visor has a mailbox. Mail to
anyone@<base32 key>.skynetarrives over SMTP across the mesh, and the sender is authenticated by its key, with no SPF, DKIM or certificate. A bridge accepts mail from ordinary SMTP senders. - Skynet
- Port forwarding and published sites, as above.
- SkyDNS
- Mesh names for every program, as above.
- Skycoin wallet
- The skycoin-web wallet runs in the visor and reaches Skycoin nodes over the mesh.
Standalone tools ship in the same binary as Skywire utilities: a standalone chat and pty over TCP, dmsg clients for curl, SOCKS5, file copy and probes, and bridges that carry SMTP or UDP over dmsg.
A full visor in a browser tab
Open skywire.dev and a visor starts in the tab. It is the same skywire program as the native visor, built with Go 1.27 for GOOS=js GOARCH=wasm. On its first visit the tab makes its own key and keeps it, so it is the same visor every time, and it joins the same network as every other visor. Nothing is installed.
Making that work means everything a visor does runs inside a page. The router, the transports, the apps, the command line and a shell are all WebAssembly, and they can only use what a page is allowed to use:
- the visor runs in a worker the page starts, as it would run on a computer, with an in-memory filesystem that the tab saves to IndexedDB;
- vnet is a virtual loopback network, so
127.0.0.1:<port>works inside the tab, and a service worker lets the page load the pages the visor serves on it; - a page cannot open raw TCP or UDP sockets, so the tab connects with dmsg over WebSocket, WebSocket and WebTransport transports to visors that accept them, and WebRTC to other tabs and visors;
- only one tab per site runs the visor, and a second tab passes its link to the one that is running.
The tab is a desktop, called the desk. It has the same dashboard a native hypervisor serves, a terminal running websh, a bash-like shell in which the whole skywire CLI works and curl reaches mesh names, a browser for .dmsg and .skynet sites and for the web through an exit, chat, mail, files and the network graph. Another visor can open a shell in the tab with skywire cli pty (#5396), and the Skycoin web wallet runs in the tab as on a native visor (#5410).
A tab cannot accept stcpr or sudph links. The host bridge, a small program the tab hands out from its own dashboard, lends it the computer’s sockets, so it can take inbound links on real ports and offer its proxy to programs on the computer. The module that runs the visor is about 38 MB. A visor fetches it from the network’s source visor over dmsg when its desk is opened, or from the release over HTTPS. The whole program also builds with TinyGo, from a TinyGo fork, and has run commands in the desk that way. The module the site serves is the standard Go build.
Linux over the tab’s visor. LinuxOnTab runs a Linux system in a browser tab. Inside the desk its network goes through the tab’s visor. The guest’s connections and DNS lookups reach the visor’s Wisp server and leave through a Skywire exit, so the internet sees the exit’s address, and the guest can open .dmsg and .skynet names (#5688). Try it at linux.skywire.dev.
A tab has limits. It cannot be an exit for others, its VPN covers only the tab, it runs while the tab is open, and browser visors are left out of rewards. See the browser visor and the host bridge.
One program, the whole suite
The skywire binary carries nearly every maintained part of the Skycoin software: the Skywire visor and its apps, the services a Skywire network runs on, a CXO node, and the Skycoin node, command line, explorer, fiber coin creator and web wallet. The browser build carries the parts a page can run.
| Part | Native visor | Browser visor |
|---|---|---|
| Router, routes and multiplexing | yes | yes |
| Transports | every type | dials swsr, swtr and dmsg, and webrtc both ways. stcpr and sudph through the host bridge |
| VPN client | the whole machine | the tab |
| Exit for other visors | yes | no |
| SOCKS5 client, chat, mail, remote shell | yes | yes |
| Publishing sites and ports | yes | on the tab’s own loopback |
| Hypervisor dashboard and desk | yes | yes |
| CXO feeds, published and read | yes | yes, held in memory |
| Skycoin web wallet | yes | yes |
| Skycoin node, CLI, explorer, newcoin | yes, skywire skycoin | no |
Network services, skywire svc | yes | no |
The Skycoin node, CLI, explorer and newcoin are not built for the browser, where skywire skycoin explains that and exits. The wallet works there because skycoin-web runs inside the tab’s visor.
CXO: signed feeds instead of plain HTTP
CXO is Skycoin’s object replication system. A publisher signs a tree of objects with the key of its feed, and subscribers fetch the tree, check the signature and keep a copy. Objects are addressed by their hash.
Skywire uses CXO to move network state off plain HTTP requests to central servers. The transport discovery publishes the routing feed visors route on, in shards that ship only when they change. The address resolver publishes every peer’s addresses and whether each can be reached. Service discovery publishes services, dmsg discovery publishes which client sits on which server, and a deployment’s config service publishes its service keys, so a deployment can change them without a release. Visors publish their own transport lists and registrations as feeds too, and the transport discovery records a visor as online from its feed instead of from HTTP heartbeats (#5448).
A signed feed can be checked by whoever receives it, however it arrived, and a copy answers locally. Answering an address lookup from a warm copy of the bindings feed takes about 119 µs, against about 140 ms for each HTTP request it replaces (#5449). When visors switched to the routing feed, the transport discovery stopped serving the whole transport graph, which had been 88% of its outbound traffic (#5485). Skychat keeps its history and group state in CXO as well, and skywire cxo daemon runs a standalone CXO node.
The services behind a network, and running your own
A Skywire network has a deployment: dmsg servers and dmsg discovery, transport discovery, an address resolver, a route finder, service discovery, route setup and transport setup nodes, a STUN server and a config service. They are open source and they are in the same binary, under skywire svc and skywire dmsg.
Since October 2026 these services run inside a visor, each under its own key (#5513, #5564). The public network’s own services run this way, together in one visor process, as its status page shows. A private network takes one command. skywire autoconfig --deployment <host> sets up the whole deployment inside a visor, and skywire cli config deployment prints the file other visors join it with (#5560). Browser visors can join one too (#5582). See running your own deployment.
Skycoin is not mined. Visors on the public network that meet the eligibility rules share a daily reward in Skycoin, which is how the coin is distributed.
Try it, run it, read the code
- Try it with nothing to install at skywire.dev, or run Linux over a browser visor at linux.skywire.dev.
- Run it from a package or a release on the downloads page, following the install guide. With Go installed, a visor runs straight from source:
go run github.com/skycoin/skywire@develop cli config gen -r
go run github.com/skycoin/skywire@develop visor
- Read the documentation and the source code (use the develop branch), and follow the daily development updates on the blog.
- Watch the network live at status.skywire.dev.
Watch an introduction
Terms used on this page
- visor
- The Skywire program running on one machine or in one tab, with its own key pair.
- transport
- An encrypted link a visor creates to another visor and can route over.
- connection
- An encrypted link between two keys outside a visor’s routing, such as between two dmsg clients.
- route
- A chain of one or more transports from one visor to another.
- route group
- The forward and reverse routes that carry one app connection.
- leg
- One route inside a route group that stripes packets over several.
- tunnel
- A route group an app uses as one of several to the same exit.
- dmsg
- The relay network, where servers pass encrypted streams between clients.
- skynet
- Reaching a key over transports and routes, and the
.skynetnames for it. - hypervisor
- A visor that manages other visors.
- deployment
- The set of services a Skywire network runs on.