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
4 changes: 2 additions & 2 deletions docs/guides/config-distribution.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ graph TD
```

:::caution
The distribution public key also acts as the decryption key for your network config. To keep your internal network structure private, only share this key with the nodes in your network.
Despite being called a "public" key, the distribution key also acts as the shared secret for decrypting your network config. To keep your internal network structure private, only share this key with the nodes in your network.
:::

<Steps>
Expand Down Expand Up @@ -71,4 +71,4 @@ The distribution public key also acts as the decryption key for your network con

Nylon polls for updates every 10 seconds and applies them.

</Steps>
</Steps>
6 changes: 3 additions & 3 deletions docs/guides/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ graph LR
- The `nylon` binary downloaded on both machines from the [releases page](https://github.com/encodeous/nylon/releases).

:::note
The Linux and macOS versions are well tested, but the Windows client currently has issues. For Windows, we recommend using [WireGuard for Windows](https://www.wireguard.com/install/) and connecting to a Linux/macOS machine as a [passive client](/guides/wg-clients).
The Linux and macOS versions are well tested, but the Windows TUN interface has known stability issues. For Windows, we recommend using [WireGuard for Windows](https://www.wireguard.com/install/) and connecting to a Linux/macOS machine as a [passive client](/guides/wg-clients).
:::

<Steps>
Expand Down Expand Up @@ -99,5 +99,5 @@ The Linux and macOS versions are well tested, but the Windows client currently h
- Learn how to connect [Passive Nodes](/guides/wg-clients) to support edge platforms like iOS.
- Discover how to use [Config Distribution](/guides/config-distribution) to manage your network configuration with ease.
- Setup nylon without a static public IP using [Dynamic DNS & Port Forwarding](/guides/port-forward).
- Explore [Advanced Routing](/guides/advanced-routing). features like Anycast and Prefix Healthchecks.
- View your network's real-time status, and debug issues with [Monitoring and Debugging](/guides/monitoring-debugging).
{/* TODO: Advanced Routing guide (Anycast, Prefix Healthchecks) */}
{/* TODO: Monitoring and Debugging guide */}
16 changes: 11 additions & 5 deletions docs/guides/wg-clients.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,22 @@ graph LR
Add the passive node to your `central.yaml`. Passive nodes should **not** have endpoints.

```yaml title="central.yaml"
clients:
- id: node-1 # this node should already exist on the network
routers:
- id: node-1
pubkey: <GATEWAY_NODE_PUBLIC_KEY>
...
addresses: [10.0.0.1]
endpoints:
- "node1.example.com:57175"
# ... other routers ...

clients:
- id: my-phone
pubkey: <PHONE_PUBLIC_KEY>
addresses:
- 10.0.0.5

graph:
- node-1, my-phone # Connect the passive node to a gateway node (e.g., node-1)
- node-1, my-phone # Connect the passive node to a gateway node
```

3. ### Connect to a Gateway
Expand Down Expand Up @@ -104,4 +110,4 @@ Nylon retains the route for passive nodes indefinitely, ensuring they remain rea
For mobile devices, leaving Keepalive disabled is recommended to maximize battery life.


> For a deep dive into how nylon handles roaming and keeps idle clients reachable, see the [Passive Nodes Reference](/reference/passive-nodes).
> For a deep dive into how nylon handles roaming and keeps idle clients reachable, see the [Passive Nodes Reference](/reference/passive-nodes).
44 changes: 41 additions & 3 deletions docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,15 @@ Nylon tries [to do one thing, and do it well](https://en.wikipedia.org/wiki/Unix

## Example

This is a conceptual illustration of how nylon routes traffic. Here is a network of 5 nodes, where the numbers on the edges represent the routing metric (nylon uses latency).
Here is a network of 5 nodes, where the numbers on the edges represent the routing metric (nylon uses latency).

:::note
Nylon does not require a fully connected network. Nodes forward packets on behalf of their neighbours, so routing works as long as any path exists between two nodes. Forwarding can be disabled per-node in config.
Nylon does not require a fully connected network. Nodes forward packets on behalf of their neighbours, so routing works as long as any path exists between two nodes.
:::

<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1rem; align-items: center;">
<div>

```mermaid
graph LR
vps --- |2| charlie
Expand All @@ -68,6 +71,41 @@ graph LR
alice --- |1| bob
```

</div>
<div>

```yaml title="central.yaml"
routers:
- id: vps
pubkey: dJcUE1qnXCQ5x8pMhFb/MZab7YrBaaHcrgfbmQI0MW4=
addresses: [10.0.0.1]
endpoints:
- "vps.encodeous.ca"
- id: alice
pubkey: xmfAovAKN4AY5ocK5s+/VsG9I27KrQ13Vzb0HOsLKAs=
addresses: [10.0.0.2]
- id: bob
pubkey: 4GfHHSyVpXc+wkbjyIIONERa6Xf5EafB0nVGZLf2r2o=
addresses: [10.0.0.3]
endpoints:
- "192.168.1.19:57175"
- id: charlie
pubkey: WcCkKijU0brYnRzxk867HTDyYFf/cqiKTTOLSxtWoFc=
addresses: [10.0.0.4]
- id: eve
pubkey: 2mXTTD+FYdtJm/v1vSHz8qimvCucjW9vY+nLYacXJFE=
addresses: [10.0.0.5]

graph:
- trio = alice, charlie, eve
- vps, trio
- bob, eve
- bob, alice
```

</div>
</div>

From `alice`, nylon selects the path of least metric to each destination (highlighted):

```mermaid
Expand Down Expand Up @@ -97,4 +135,4 @@ graph LR
linkStyle 2 stroke:#4caf50,stroke-width:2px
linkStyle 3 stroke:#4caf50,stroke-width:2px
linkStyle 4 stroke:#e53935,stroke-width:2px,stroke-dasharray:5
```
```
147 changes: 147 additions & 0 deletions docs/reference/config.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
title: Configuration Reference
description: Annotated reference for central.yaml and node.yaml.
sidebar:
order: 1
---

## node.yaml

Each node has its own `node.yaml` with local settings. Generate a keypair with `nylon key` — stdout is the private key, stderr is the public key.

```yaml title="node.yaml"
key: 0NcrMcaS1tORCTA88L5ZPE+H6yUMV4e5vRp6iypnPW8= # private key (from `nylon key`)
id: alice # must match this node's id in central.yaml
port: 57175 # UDP port nylon listens on

# --- Optional fields below ---

use_system_routing: false # if true, all peer packets exit via the TUN interface
no_net_configure: false # if true, nylon won't touch system routes or interfaces
log_path: "" # write logs to this file (empty = stderr only)
interface_name: "" # override the interface name (default: "nylon", or utunX on macOS)
dns_resolvers: [] # DNS servers for nylon's own lookups, e.g. ["1.1.1.1:53"]

# Bootstrap: fetch central.yaml from a remote bundle on first start
dist:
url: https://static.example.com/network1.nybundle
key: 7PaN6DmAayz4KnDnsXSXJH+Oy0TFGeoM4FEbQfLriVY= # distribution public key

# Split tunneling (per-node overrides)
exclude_ips: # add to the central exclude list
- 192.168.0.0/24
unexclude_ips: [] # subtract from the central exclude list

# Lifecycle hooks (run in order)
pre_up: []
pre_down: []
post_up:
- iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -d 192.168.0.0/24 -j MASQUERADE
post_down: []
```

---

## central.yaml

The central config defines the entire network topology. It is shared across all nodes (either copied manually or via config distribution).

```yaml title="central.yaml"
# --- Config Distribution (optional) ---
dist:
# The distribution key is used to verify and decrypt sealed bundles.
# Despite being called "public", treat it as a shared secret — it can decrypt your topology.
key: 7PaN6DmAayz4KnDnsXSXJH+Oy0TFGeoM4FEbQfLriVY=
# Nylon polls these URLs every 10 seconds for config updates
repos:
- file:central.nybundle # local file
- https://static.example.com/network1.nybundle # remote URL (HTTP GET)

# --- Routers ---
# Active nylon nodes that participate in routing and can forward traffic.
routers:
- id: alice
pubkey: xmfAovAKN4AY5ocK5s+/VsG9I27KrQ13Vzb0HOsLKAs==
addresses: [10.0.0.1] # nylon interface addresses (auto-advertised as /32 or /128)
endpoints:
- "alice.example.com:57175" # domain name (re-resolved periodically)
- "192.168.1.2:57175" # LAN IP
prefixes:
# Static: always advertised at the given metric
- type: static
prefix: 192.168.0.0/24
metric: 0 # optional, default 0

# Ping: advertised with RTT as metric, withdrawn after max_failures consecutive failures
- type: ping
prefix: 10.1.0.0/24
addr: 10.1.0.8 # address to ping
delay: 10s # interval between pings (default: 15s)
max_failures: 3 # failures before withdrawal (default: 3)
bind_if: en10 # optional: bind to a specific interface
# metric: 0 # optional: override RTT with a static metric

# HTTP: advertised with request duration as metric, withdrawn on non-200 response
- type: http
prefix: 10.2.0.0/24
url: http://example.com/healthz
delay: 15s # interval between probes (default: 15s)
# metric: 5 # optional: override request duration with a static metric

- id: bob
pubkey: 4GfHHSyVpXc+wkbjyIIONERa6Xf5EafB0nVGZLf2r2o=
addresses: [10.0.0.2, 10.1.0.2] # multiple addresses are fine
endpoints:
- "192.168.1.1:57175"
- "nylon.example.org" # port defaults to the node's configured port

- id: eve
pubkey: 2mXTTD+FYdtJm/v1vSHz8qimvCucjW9vY+nLYacXJFE=
addresses: [10.0.0.3]
# no endpoints — eve can only connect outward to nodes that have endpoints

- id: public
pubkey: dJcUE1qnXCQ5x8pMhFb/MZab7YrBaaHcrgfbmQI0MW4=
addresses: [10.0.0.4]
endpoints:
- "123.123.123.123:57175" # multiple endpoints; nylon picks the best one dynamically
- "123.123.123.124:57175"

# --- Clients ---
# Passive WireGuard clients that don't run nylon. Only static prefixes allowed.
clients:
- id: client1
pubkey: SBI+yvF30Ba4xo0GKTtKHSSfbXAnRNFTBwydJyJp6Rk=
addresses: [10.0.0.7]
prefixes:
- type: static
prefix: 192.168.1.0/24 # also add this to AllowedIPs in the WireGuard client config

# --- Split Tunnel ---
# Excluded prefixes are NOT routed through nylon (network-wide default).
# Per-node overrides are in node.yaml (exclude_ips / unexclude_ips).
exclude_ips:
- 192.168.0.0/24

# --- Graph ---
# Defines which nodes will peer with each other. Only nodes connected in the graph
# will attempt to establish WireGuard tunnels.
graph:
# Groups: a shorthand for sets of nodes (nodes within a group are NOT auto-connected)
- Group1 = alice, bob
- Group1, Group1 # connect every node in Group1 to every other node in Group1
- Group2 = Group1, client1 # groups can contain other groups
- client1, eve, alice # all three fully interconnected

# Updated automatically by `nylon seal`; used as a version number for config distribution.
timestamp: 1740832962209309000
```

---

## Naming Rules

Node and group IDs must:
- Match `^[0-9a-z._/-]+$`
- Be at most 100 characters
- Be unique across all routers and clients
4 changes: 2 additions & 2 deletions docs/reference/passive-nodes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ This means:

</Aside>

To solve this, when a passive node goes silent, the gateway enters a "Passive Hold" state for that node. The gateway continues to advertise the client's prefixes, but at a metric of `INF / 2` (a very high value). This allows the route to remain active in the network, but ensures that any new connection from the client to another gateway will take precedence.
To solve this, when a passive node goes silent, the gateway enters a "Passive Hold" state for that node. The gateway continues to advertise the client's prefixes, but at a metric of `INFM / 2` (where `INFM` = `0xFFFFFFFE`, so the hold metric is `2,147,483,647`). This allows the route to remain active in the network, but ensures that any new connection from the client to another gateway will take precedence.

At the same time, if the gateway detects any new advertisement for that client from another gateway, it will immediately preempt its own "held" route and stop advertising the client altogether. This allows for seamless roaming without the need for keepalives.

Expand All @@ -65,4 +65,4 @@ At the same time, if the gateway detects any new advertisement for that client f
Nylon does support advanced routing features for passive nodes, such as **anycast**. However, there are some important caveats to be aware of when using passive nodes.
1. Anycast passive nodes will stop having their prefixes advertised when they go silent. This can lead to suboptimal routing or oscillations if the passive node sends data over a long interval. You should consider enabling keepalives for anycast nodes to ensure they remain active in the network. (This should be less than `ClientKeepaliveInterval`)
2. Passive nodes cannot advertise the same prefix as the gateway itself, or any other client which might be connected to the same gateway. This is because there is no easy way to determine which client is best.
3. Due to passive hold, there will always be gateway advertising the client's prefixes, even if the client is turned off. (Assuming the gateway is still active.) This means that if a client is truly offline, the route will be effectively blackholed.
3. Due to passive hold, there will always be a gateway advertising the client's prefixes, even if the client is turned off. (Assuming the gateway is still active.) This means that if a client is truly offline, the route will be effectively blackholed.
4 changes: 2 additions & 2 deletions docs/why-nylon.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ How does nylon stack up against other popular mesh networking solutions?
| **Routing Model** | **Intelligent, Optimized Multi-hop** | Peer-to-Peer + Relays | Peer-to-Peer Mesh | Dynamic Multi-hop |
| **Points of Failure** | **Decentralized; heals around outages.** | Down if Coordination/SSO is down. | Fails on strict NAT | Based on routing daemon |
| **Encryption** | Link-level (between nodes) | End-to-end | End-to-end | Link-level (between routers) |
| **Core Protocol** | WireGuard (Polyamide) | WireGuard | Noise-based (Custom) | WireGuard |
| **Core Protocol** | WireGuard ([Polyamide](https://github.com/encodeous/nylon/tree/main/polyamide)) | WireGuard | Noise-based (Custom) | WireGuard |
| **Coordination** | **Decentralized (In-band, same port)**, manual key distribution | Centralized (SaaS/Headscale) | Decentralized (Lighthouse) | Manual (Out-of-band, via routing daemon) |
| **NAT Traversal** | Public nylon node(s) or port forward | **STUN/ICE/DERP** | Public nodes (lighthouses) | Manual (port forward, or public node) |
| **Configuration** | Single Central Config (YAML) | Web Dashboard / SSO | Certificates & CA | Complex (Tunnels + Daemons + Network NS) |
Expand All @@ -44,4 +44,4 @@ Unlike Tailscale or Nebula, which focus on establishing direct P2P tunnels, **ny
1. **No reliance on central coordination**: nylon nodes discover each other and exchange routing information directly, without needing a central server for metadata and key exchange. You can still centrally configure your network using the central configuration.
2. **Automatic & optimized multi-hop routing**: If a direct path between two nodes is blocked (e.g., due to strict NATs), or an indirect path is more optimal, nylon automatically routes traffic through intermediate nodes. This ensures connectivity even in challenging network conditions.
3. **Native WireGuard compatibility**: By using the Passive Nodes feature, you can connect standard WireGuard clients (iOS, Android, etc.) to your nylon mesh. These clients can roam between different gateways without losing connectivity, and benefit from the dynamic routing capabilities of nylon without needing any custom software.
:::
:::