Reference · Qeli 0.8.1

Server and client configuration

What lives in server.conf, users.conf and client.conf, which settings are pushed, and which remain local.

Foundation

Three files, one flat-INI model

/etc/qeli/server.conf stores global sections and transport profiles. /etc/qeli/users.conf stores users and groups. Device-side client.conf holds connection data and local client behaviour. A comment is valid only on its own line.

validate without starting TUN or listeners
$ sudo qeli check-config --config /etc/qeli/server.conf
$ sudo qeli check-config --client --config /etc/qeli/client.conf
The version matters. Before copying an example, make sure it targets 0.8.1. Unknown or obsolete keys are rejected by strict validation or have no effect.
Where a setting comes from

What the link, push and client file carry

The link defines connection and handshake data. Server push changes network settings without reissuing the link. Device behaviour stays on the client.

SourceCarriesHow it changes
qeli://Address, port, credentials, mode, pinning/REALITY, handshake parameters and optional MTU/nameReissue the link when any of these values changes
Server pushClient and server IPs, pool prefix, MTU, DNS, keepalive and routesAt the next connection; the link stays unchanged
client.confgateway, route_local, kill_switch, include/exclude, dns, persist_tunChanged on the device or in Client manager
users.confprofiles, max_sessions, allowed_networks, route, client_subnet, quotasMost fields apply on reload without dropping sessions
qeli:// contains no routes or DNS settings. They either arrive from the server after AUTH or are set locally. Changing a pushed route therefore does not require reissuing the QR code.
server.conf

Server profile keys

Each [profile:name] has its own port, transport, TUN and pool. One service can run multiple profiles at once.

KeyDefaultPurpose
bind.address0.0.0.0Profile listener address
bind.port443TCP/UDP port; must not collide with another profile
bind.transporttcpCarrier transport: tcp or udp
tun.address10.9.0.1Server IP inside the tunnel and the usual next hop
tun.namevpn0TUN name; must be unique across profiles
tun.mtu1400Profile MTU, pushed to clients
tun.queues00 = CPU count, 1 = single-threaded pump, N = explicit queue count
pool.cidr10.9.0.0/24Single source for the TUN prefix and address pool
pool.reservation.<user>Reserves a pool IP for a user
obf.modefake-tlsWire mode: plain, fake-tls, obfs or reality-tls
routeRepeatable route pushed to profile clients
routing.nat.enabledfalseSource NAT for client egress through the server
routing.nat.interfaceeth0NAT egress interface; at the default value the server tries to detect it automatically
routing.forward_privatetrueAllows forwarding to private networks behind the server
routing.client_to_clientfalseAllows traffic between VPN clients in the profile
dns.enabledfalseStarts the built-in DNS proxy
dns.push_serversExplicitly sets the DNS address clients receive
perf.connection.max_clients128Profile-wide active session limit
TAP/L2 · refined in 0.8.1

Built-in DHCP: when it is needed and what it guarantees

DHCP is enabled per profile only for TAP/L2 scenarios. A normal L3 TUN receives its address during AUTH, so dhcp.enabled=false remains the correct default.

KeyDefaultPurpose
dhcp.enabledfalseStarts DHCPv4 on the profile actual TUN/TAP interface
dhcp.listenemptyLogical address and port; empty uses tun.address:67. Explicit 0.0.0.0 is rejected
dhcp.pool_start / pool_endOptional range inside the usable part of pool.cidr; otherwise selected automatically
dhcp.lease_time_secs86400Lease lifetime in seconds
dhcp.domain_namevpnDomain name sent to clients

0.8.1 tightens the lease lifecycle: the server distinguishes SELECTING/INIT-REBOOT/RENEWING/REBINDING REQUEST states, sends NAK only when allowed by state and authoritative server identity, frees addresses on RELEASE, quarantines DECLINE and reaps expired leases. Relay and broadcast follow DHCP rules.

DNS without a hidden fallback: with the built-in DNS proxy enabled, DHCP sends the profile address. Otherwise it uses IPv4 addresses from dns.push_servers; an empty list means no DNS option, not silently selected public resolvers.
Do not expose DHCP on WAN. The Linux socket receives broadcast on 0.0.0.0:67, but Qeli binds it through SO_BINDTODEVICE to the profile actual interface only. An unsafe or malformed listen address is rejected at startup.
users.conf

Users, groups and limits

A user's own values override its group. Per-user route entries replace profile routes for that user.

KeyDefaultPurpose
password_hashArgon2id hash used for authentication
password_encEncrypted copy used to reissue a link; the key is stored in /var/lib/qeli
enabledtrueAllows or blocks new connections
profilesallList of permitted profiles
groupLimits and ACL template from [group:name]
max_sessions0Concurrent device limit; 0 = group value or unlimited
static_ipFixed user address from pool.cidr
allowed_networksanyDestination CIDR allowlist; empty = unrestricted
routePer-user route pushed to the client
client_subnetInbound route to the network behind this client, analogous to iroute
bandwidth.limit_mbps0Bandwidth limit; 0 = unlimited or group value
data_limit_gb0Lifetime download quota; upload is accounted separately
expire_atUnix time when the account expires
client.conf

Connection and local behaviour keys

Connection fields normally come from importing qeli://. Gateway, DNS, routing and device-behaviour policies are not included in the link; an explicit MTU is the documented exception.

KeySourcePurpose
server, user, passqeli://Address and credentials
proto, modeqeli://Transport and mode must match the profile
key, reality_sid, sniqeli://Pinning and REALITY/H-1 parameters
gatewaylocaltrue enables full tunnel; false keeps split tunnel
route_locallocalAlso sends private networks through the tunnel
include, excludelocalAdditional CIDRs routed through or around the tunnel
route_fileWindows/macOSCIDR file that locally extends include in split-tunnel mode
kill_switchlocalBlocks full-tunnel leaks while the connection is down
allow_ipv6_leaklocalAllows IPv6 over the physical path only when the negotiated full tunnel lacks IPv6; this explicitly accepts a leak
apps, apps_modeplatform-specificPer-app routing on Windows, macOS and Android
allow_lanAndroidKeeps the home LAN and local multicast outside the VPN
dnslocalResolver management mode: tunnel, off, or the system alias
mtulink/push/local0 accepts push/auto-selection; a value above 0 overrides it
persist_tunlocalKeeps the adapter and routes between reconnects
keepalive, tcp_nodelaylocalClient TCP socket settings
recv_buffer_sizelocalInitial UDP receive buffer size; automatic growth is capped by sysctl
forwardlocalSite-to-site forwarding without NAT; applied on Linux, Windows and macOS
gateway_nat, lan_subnetlocalClient gateway mode for the local network
exit_nodeLinuxSends other clients' traffic through this node's physical WAN
dev_attachLinux CLIAttaches an existing TUN whose addressing and routing are owned by an external controller
Applying changes

When reload is enough

reload covers users and some runtime settings. Anything that changes a listener, transport or TUN device requires a full restart and briefly drops sessions.

ChangeActionEffect
Users, groups, ACLs and limitssudo systemctl reload qeliNo active-session drop when the field supports runtime reload
web.allowed_ips, allowed_origins, public_hostreloadReloaded live
bind.*, web.bind/port/tls/base_pathsudo systemctl restart qeliThe socket changes, so a full restart is required
tun.*, pool.cidr, obf.*restartThe profile and TUN are recreated
rotate-identityrestartClients must update the pinned key
Primary sources

Where to find the complete list

This page covers the operator keys used most often. Rare transport, shaping, multipath, logging, hook and platform-specific settings are listed in the full reference.