docs: correct the self-hosted server path and document server.toml
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
This commit is contained in:
@@ -1,50 +1,129 @@
|
||||
# Konduit Server Quickstart
|
||||
|
||||
## 1. Prerequisites
|
||||
Running your own Konduit server takes three binaries: `konduit-server` (the VPN
|
||||
server), `konduit-ctl` (provisioning), and `konduit` (a client, for testing).
|
||||
|
||||
### IP Forwarding
|
||||
## 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
|
||||
```
|
||||
|
||||
### Capabilities
|
||||
|
||||
Konduit needs permission to create TUN devices and bind privileged ports without running as root.
|
||||
### TUN device
|
||||
|
||||
```bash
|
||||
sudo setcap cap_net_admin,cap_net_bind_service=+ep ./konduit-server
|
||||
sudo setcap cap_net_admin=+ep ./konduit
|
||||
ls /dev/net/tun || sudo modprobe tun
|
||||
```
|
||||
|
||||
## 2. Bootstrap
|
||||
Without it the server cannot create its interface and exits at startup.
|
||||
|
||||
Konduit derives its identity key from a **mantra** (secret phrase) using Argon2id. Keep the mantra safe — it lets you recover the same identity if the config file is lost.
|
||||
## 3. Bootstrap
|
||||
|
||||
**Standard (konduit binds on 443):**
|
||||
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 -
|
||||
```
|
||||
|
||||
**Behind a reverse proxy (HAProxy on 443, konduit on 8443):**
|
||||
`-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 -
|
||||
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).
|
||||
`--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).
|
||||
|
||||
## 3. Add a Client
|
||||
> **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.
|
||||
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.
|
||||
|
||||
## 4. TUN Interface Name
|
||||
**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:
|
||||
|
||||
@@ -54,24 +133,37 @@ Set a fixed TUN interface name so firewall rules are stable:
|
||||
tun_name = "konduit0"
|
||||
```
|
||||
|
||||
Without this, konduit picks the first available `tunN`, which shifts if other VPN interfaces exist.
|
||||
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.
|
||||
|
||||
## 5. Run
|
||||
## 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
|
||||
```
|
||||
|
||||
## 6. NAT / Masquerade
|
||||
## 7. NAT / Masquerade
|
||||
|
||||
VPN clients send packets with source IP `10.10.0.x`. Masquerade rewrites this to the server's public IP so internet hosts can reply.
|
||||
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)
|
||||
|
||||
@@ -99,12 +191,39 @@ sudo iptables -I FORWARD 2 -i $IFACE -o konduit0 -m state --state RELATED,ESTABL
|
||||
sudo apt install iptables-persistent && sudo netfilter-persistent save
|
||||
```
|
||||
|
||||
## 7. Verify
|
||||
## 8. Verify
|
||||
|
||||
```bash
|
||||
# Connect a client and confirm the tunnel comes up
|
||||
./konduit --config client.toml
|
||||
./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
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user