Audit of the public repo against the actual server and konduit-ctl source. The happy path was documented; the failure modes were not. - server.toml had no reference at all. Add docs/server-config.md covering every key, [tls], the control API, and key handling. - The mantra could not recover the identity key on its own: derive_from_passphrase needs the [kdf] salt, which is 32 random bytes generated once at bootstrap. bootstrap says so in the file it generates (core/src/config.rs:403); the quickstart claimed the opposite. Fixed, with a backup step added before it is needed rather than after. - konduit-server never appeared in a download step, yet konduit-server.service expects /opt/konduit/konduit-server - a path no instruction created. Added the install section and moved setcap after the copy, since capabilities do not survive every cross-filesystem copy and a binary that silently lost cap_net_bind_service fails at bind time. - Hot config reload was a headline feature with no documented mechanism. It is a control API on 127.0.0.1:3001, and add-client only edits the file on disk, so a new peer is not live until something reloads it. Documented, including that /reload does not disconnect revoked peers but /sync does. - [tls] native termination was entirely undocumented; the key must be PKCS#8. - Dropped a README claim about a konduit-admin-ui unit that does not exist, and fixed a systemd copy path that only resolved if this repo had been cloned to /opt/konduit. #k-ops/#1/#211
230 lines
7.3 KiB
Markdown
230 lines
7.3 KiB
Markdown
# 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-<version>-linux-x86_64` and `konduit-ctl` from the
|
|
[Releases](../../releases) page, plus `konduit-<version>-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
|
|
```
|