# Konduit Server Quickstart Running your own Konduit server takes three binaries: `konduit-server` (the VPN server), `konduit-ctl` (provisioning), and `konduit` (a client, for testing). ## 1. Install Download `konduit-server--linux-x86_64` and `konduit-ctl` from the [Releases](../../releases) page, plus `konduit--linux-x86_64` if you want to test the tunnel from the same host. ```bash sudo mkdir -p /opt/konduit sudo cp konduit-server konduit-ctl konduit /opt/konduit/ cd /opt/konduit sudo chmod +x konduit-server konduit-ctl konduit ``` Run everything from `/opt/konduit` — `konduit-ctl` writes `server.toml` into the current directory, and the systemd unit expects the config at `/opt/konduit/server.toml`. ### Capabilities Grant the binary permission to create TUN devices and bind port 443 without running as root: ```bash sudo setcap cap_net_admin,cap_net_bind_service=+ep /opt/konduit/konduit-server ``` Do this **after** copying the binary. Capabilities are stored as an extended attribute on the file, and a copy made across filesystems can drop them — a `konduit-server` that quietly lost `cap_net_bind_service` fails with a permission error the moment it tries to bind 443. The unit in step 6 runs as `User=root`, where capabilities are irrelevant; this matters for running it by hand. To confirm what the binary actually ended up with: ```bash getcap /opt/konduit/konduit-server ``` ## 2. Prerequisites ### IP forwarding ```bash sudo sysctl -w net.ipv4.ip_forward=1 # Persist: add 'net.ipv4.ip_forward=1' to /etc/sysctl.conf ``` ### TUN device ```bash ls /dev/net/tun || sudo modprobe tun ``` Without it the server cannot create its interface and exits at startup. ## 3. Bootstrap Konduit derives its identity key from a **mantra** (secret phrase) using Argon2id. ```bash cd /opt/konduit echo "your secret mantra phrase here" | ./konduit-ctl bootstrap -l vpn.example.com:443 -p - ``` `-l` sets both the port the server binds and the hostname written into every client config, so use the name you will actually serve. Bootstrap refuses to overwrite an existing `server.toml` unless you pass `--force`. It prints the server's public identity key — clients need this, and it is already inside the generated `.client.toml` files. **Behind a reverse proxy** (HAProxy on 443, konduit on 8443): ```bash echo "your secret mantra phrase here" | \ ./konduit-ctl bootstrap -l vpn.example.com:8443 --public-port 443 -p - ``` `--public-port` sets the port written into client configs, so they connect to 443 even though konduit listens on 8443 — useful when running behind any TCP-passthrough reverse proxy (e.g. HAProxy, nginx `stream` module). Konduit can also terminate TLS itself; see `[tls]` in the [server configuration reference](server-config.md). > **Back up `server.toml` now, before you need it.** It holds the server's > private identity key in plaintext, and its `[kdf] salt_hex` is 32 random bytes > generated once at bootstrap. The mantra is only half the key material — if you > lose the file you lose the salt, and the mantra alone cannot regenerate the > key. See [Key handling](server-config.md#key-handling). ```bash sudo install -m 600 server.toml /root/konduit-server.toml.bak ``` ## 4. Add a Client ```bash ./konduit-ctl add-client my-laptop ``` Creates `my-laptop.client.toml` and appends the peer to `server.toml`. Transfer the `.client.toml` to the client device, or scan the QR payload with the mobile app. **The running server does not see this yet.** `add-client` only edits the file on disk; the live peer list updates on the next reload. Either add `--reload` to the command, or reload separately: ```bash ./konduit-ctl add-client my-laptop --reload # or, on an already-running server: ./konduit-ctl reload ``` `--reload` talks to the control API on `127.0.0.1:3001`. Running `konduit-ctl` on a different machine than the server needs `--control-url`, and the API is bound to loopback — see [Reloading](server-config.md#reloading) before changing that. ## 5. TUN Interface Name Set a fixed TUN interface name so firewall rules are stable: ```toml # server.toml [network] tun_name = "konduit0" ``` The default is `tun0`, but konduit falls back to the first free `tunN` if that name is taken. On a host that also runs WireGuard or OpenVPN the name then shifts underneath you and any firewall rule keyed to it stops matching. The masquerade rule in step 7 uses this name. ## 6. Run ```bash ./konduit-server --config server.toml ``` Check the file before starting for real: ```bash ./konduit-server --config server.toml --validate ``` For persistent operation, use the provided systemd units in [docs/systemd/](systemd/). Copy `konduit-server.service` to `/etc/systemd/system/`, then: ```bash sudo systemctl daemon-reload sudo systemctl enable --now konduit-server sudo journalctl -u konduit-server -f ``` ## 7. NAT / Masquerade VPN clients send packets with source IP `10.10.0.x` — the `/24` implied by the default `server_ip = "10.10.0.1"`. Masquerade rewrites this to the server's public IP so internet hosts can reply. If you changed `server_ip`, match the rule to the new subnet. ### firewalld (RHEL, Fedora, recent Ubuntu) ```bash # Trust the VPN interface sudo firewall-cmd --zone=trusted --add-interface=konduit0 --permanent # Enable masquerade on the public zone sudo firewall-cmd --zone=public --add-masquerade --permanent sudo firewall-cmd --reload ``` > **Important:** `iptables` commands are silently ignored on firewalld systems. Always use `firewall-cmd`. ### iptables (Debian/Ubuntu without firewalld) ```bash IFACE=$(ip route get 1.1.1.1 | awk '{print $5; exit}') sudo iptables -t nat -I POSTROUTING 1 -s 10.10.0.0/24 -o $IFACE -j MASQUERADE sudo iptables -I FORWARD 1 -i konduit0 -o $IFACE -j ACCEPT sudo iptables -I FORWARD 2 -i $IFACE -o konduit0 -m state --state RELATED,ESTABLISHED -j ACCEPT # Persist sudo apt install iptables-persistent && sudo netfilter-persistent save ``` ## 8. Verify ```bash # Connect a client and confirm the tunnel comes up ./konduit --config my-laptop.client.toml # Is the peer actually connected? ./konduit-ctl peers # Check konduit logs journalctl -u konduit-server -f ``` `./konduit-ctl peers` returning your peer's address is the check worth having — it distinguishes "the client authenticated" from "the client is routing traffic", and only the second one proves NAT is set up. ## Troubleshooting | Symptom | Cause | |---|---| | `Permission denied` binding 443 | `cap_net_bind_service` was lost in a copy. Re-run `setcap` against the final path and confirm with `getcap`. | | `No such file or directory` on startup | `/dev/net/tun` missing — `sudo modprobe tun`. | | Tunnel connects, but no internet | Masquerade missing or scoped to the wrong subnet. Check step 7 matches your `server_ip`. | | iptables rules look right but do nothing | firewalld is running and ignoring them. Use `firewall-cmd`. | | New client cannot connect | Peer was added to `server.toml` but never reloaded. Run `konduit-ctl reload`. | | Revoked client still has access | `/reload` does not disconnect live sessions. Restart the service. | | `IP pool exhausted (10.10.0.10-254)` | The `/24` is full. Widen `netmask` or move `server_ip` to another subnet. | For more detail than the table, set `RUST_LOG=debug`: ```bash sudo systemctl edit konduit-server # [Service] # Environment=RUST_LOG=debug ```