Server
Environment file
eonpath-server reads its configuration from /etc/eonpath/server.env, an
environment file loaded by the systemd unit (EnvironmentFile=). This is the
configuration surface installed and pre-populated by the eonpath-server
.deb package; see Install: Server for the install
steps.
# /etc/eonpath/server.env
# SSH listener (post-quantum SSH proxy method)
EONPATH_SSH_ADDR=0.0.0.0:2022
# Local PQKS API endpoint (used to look up client keys when a client connects)
EONPATH_API_ENDPOINT=http://localhost:8080
# HTTP CONNECT proxy address (for the proxy method's tunnels)
EONPATH_PROXY_ADDR=localhost:2290
# SSH host key path (generated by the postinstall script on first install)
EONPATH_HOST_KEY=/var/lib/eonpath/host_key
# Per-user authorized_keys directory
EONPATH_AUTHORIZED_KEYS_DIR=/var/lib/eonpath/authorized_keys
# WireGuard VPN settings (for the routing method)
EONPATH_WG_KEX_ADDR=0.0.0.0:9998
EONPATH_WG_LISTEN_PORT=51820
# Security audit log (empty discards the events)
EONPATH_AUDIT_LOG=/var/lib/eonpath/audit.logAfter editing, apply the change with:
sudo systemctl restart eonpath-server| Key | Type | Default | Description |
|---|---|---|---|
EONPATH_SSH_ADDR | address | 0.0.0.0:2022 | Listen address for the post-quantum SSH proxy method. |
EONPATH_API_ENDPOINT | URL | http://localhost:8080 | Address of the eonpath-api server, used to look up a connecting client’s registered public key. |
EONPATH_PROXY_ADDR | address | localhost:2290 | Listen address for the HTTP CONNECT proxy that backs the proxy method’s tunnels. |
EONPATH_HOST_KEY | path | /var/lib/eonpath/host_key | Path to the server’s SSH host key, generated on first install. |
EONPATH_AUTHORIZED_KEYS_DIR | path | /var/lib/eonpath/authorized_keys | Directory of per-user authorized_keys files consulted by the SSH proxy method. |
EONPATH_WG_KEX_ADDR | address | 0.0.0.0:9998 | TCP listen address for the WireGuard routing method’s key-exchange handshake (see API for the protocol). |
EONPATH_WG_LISTEN_PORT | int | 51820 | UDP port for the WireGuard data tunnel. |
EONPATH_AUDIT_LOG | path | /var/lib/eonpath/audit.log | Security audit log. It has to stay under a ReadWritePaths directory, since the unit sets ProtectSystem=strict; set it empty to discard the events. Rotated by /etc/logrotate.d/eonpath-server. |
The routing method itself (-wg-enabled) is always passed by the packaged
systemd unit’s ExecStart line — the shipped .deb runs both the SSH proxy
method and the WireGuard routing method from a single eonpath-server
process. Disabling the routing method requires editing the systemd unit
directly, since it isn’t exposed through the environment file.
server.conf: registration and endpoints
The unit also passes -config /etc/eonpath/server.conf. Flags override the
file, and the unit passes a flag for every ssh:, proxy:, api: and
wireguard: value — so on a stock .deb install those sections have no
effect; change them in server.env instead, or drop the corresponding flag
with systemctl edit eonpath-server.
The registration: and endpoints: sections have no flag counterpart. They
are why the file exists.
registration:
enabled: true
api_url: "https://api.example.com" # also the signed audience
license_key_file: /etc/eonpath/license_key
timeout: 10s
max_attempts: 8
endpoints:
- name: example-ams-1
method: routing # WireGuard VPN with SIIT/NAT
mode: standby # standby | active
tunnel_ip: 203.0.113.10 # public address clients connect to
tunnel_port: 51820
kex_address: 203.0.113.10:9998 # required for method: routing
companion_hosts:
- git.example.com
- name: example-ams-1-proxy
method: proxy # HTTP CONNECT proxy + SSH port forwarding
mode: standby
tunnel_ip: 203.0.113.10
port: 2022 # required for method: proxy
forward_port: 9999The server publishes these endpoints to the API, signed with its ML-DSA-87 identity key. The first push also presents the licence key; after that the signature alone authenticates the server, and the key can be removed from the host. Registration failing never stops the server — an invalid endpoint entry is skipped with an error in the journal and everything else keeps serving.
tunnel_ip is mandatory and never auto-detected: behind NAT, detection would
register the private address and produce an endpoint no client can reach.
Every name has to be covered by the licence and fall inside a name prefix
reserved for your organization.
The licence key is read from the first source that has it: -license-key,
EONPATH_LICENSE_KEY, license_key in this file, license_key_file. Prefer
the file or the environment — the example ships world-readable.
After editing the endpoint list:
sudo systemctl reload eonpath-server # re-reads server.conf, re-pushes, drops no tunnelmode: standby and mode: active
| Mode | What the server does | Published to clients |
|---|---|---|
standby | Registers itself and nothing else — no WireGuard interface, no kex listener, no proxy listener | No |
active | Serves traffic normally | Yes |
A standby endpoint doesn’t appear in GET /endpoints at all, so no client
ever learns it exists. The state is a commercial fact with a technical
consequence, so it’s recorded in the API and enforced on the server: every
transition is logged with a timestamp, and the first activation starts a
per-endpoint free evaluation window (trial_days on the licence, 30 by
default) that is granted once and does not restart.
Switching state is an edit here plus systemctl restart eonpath-server — a
restart, not a reload. In standby there was nothing serving to interrupt.
Omitting mode means active, so configs written before the option existed
keep working. A field that is present but empty, or holds an unknown value,
rejects that endpoint with an error in the journal rather than guessing: a
guess costs money in one direction or the other. A fresh install ships
mode: standby.
WireGuard VPN settings (command-line flags)
A few less common WireGuard routing-method settings are only available as
eonpath-server command-line flags — they can be added to the
ExecStart= line in /lib/systemd/system/eonpath-server.service (or a
systemd drop-in) if you need to change them from their defaults.
| Key | Type | Default | Description |
|---|---|---|---|
-wg-interface | string | wg0 | WireGuard network interface name. |
-wg-server-ip | string | fd00:4464::a00:1 | Server’s internal address inside the VPN’s IPv6 lease range. |
-wg-subnet | string | fd00:4464::a00:0/112 | IPv6 subnet the server leases client addresses from. |
-wg-masquerade | bool | true | Enable NAT masquerading so VPN clients can reach the internet through the server. |
SSH proxy method and general server flags
| Key | Type | Default | Description |
|---|---|---|---|
-config | path | /etc/eonpath/server.conf on a packaged install | Path to the YAML configuration file described above; command-line flags override values loaded from it. |
-license-key | string | (none) | Licence key for endpoint registration; takes precedence over EONPATH_LICENSE_KEY and both server.conf sources. |
-disable-ssh | bool | false | Disable the SSH proxy method’s listener entirely. |
-proxy-validate-destinations | bool | false | Enable SSRF protection: validate HTTP CONNECT destinations against security rules before dialing them. |
-key-revocation-interval | duration | 5m | How often the server polls the API for revoked keys and removes them from authorized_keys. Set to 0 to disable polling. |
-drop-privileges | bool | false | Drop root privileges after binding to listen ports. |
-run-as-user | string | (auto-detected) | User to run as after dropping privileges; used with -drop-privileges. |
Post-quantum key exchange (SSH proxy method)
The WireGuard routing method’s key exchange (ML-DSA-87 authentication, ML-KEM-1024 encapsulation) is fixed and not configurable — see Post-Quantum Cryptography. The SSH proxy method’s key exchange algorithm selection can be tuned independently, either as command-line flags or the equivalent environment variables:
| Key | Type | Default | Description |
|---|---|---|---|
-pqc-mlkem / PQKEX_MLKEM | bool | true | Enable ML-KEM-768 hybrid key exchange for the SSH proxy method. |
-pqc-frodokem / PQKEX_FRODOKEM | bool | false | Enable FrodoKEM-640 hybrid key exchange (experimental). |
-pqc-ntruprime / PQKEX_NTRUPRIME | bool | false | Enable sntrup761 hybrid key exchange (experimental). |
-pqc-prefer-classical / PQKEX_PREFER_CLASSICAL | bool | false | Prefer classical (non-PQC) key exchange algorithms when negotiating with a peer. |
-pqc-order / PQKEX_ORDER | string | (none) | Comma-separated algorithm priority order (for example mlkem,frodokem); setting this auto-enables the listed algorithms and overrides the individual flags above. |
Command-line flags take precedence over the equivalent environment variable.