Deployment

Installing and configuring Qeli

The main commands and files are updated for the released Qeli 0.8.1 beta. The guide covers installation, safe server and application upgrades, routing, the panel, backups and troubleshooting.

Choose a platform

Focused guides for each installation method

This page remains the complete guide. For a faster start, open the focused guide for your platform with only the relevant requirements, commands and checks.

Quick start

One-command install

On a clean Debian 12+ / Ubuntu 22.04+ server, run it as root — the script brings up a full reality-tls server on :443: it installs the dependencies and the latest .deb from Releases, writes the config with full-tunnel NAT, generates the server key, creates five users with ready qeli:// links and starts the service.

server terminal
# 1. download the script
$ curl -fsSLO https://raw.githubusercontent.com/litvinovtd/qeli/main/install-qeli-server.sh
# 2. review it, then run it as root
$ less install-qeli-server.sh
$ bash install-qeli-server.sh

To set the connection address explicitly (IP, domain or IPv6), pass it as an argument: bash install-qeli-server.sh vpn.example.com; otherwise the public address is detected automatically. Set the profile and port with QELI_PROFILE=reality-tls|fake-tls|udp-quic and QELI_PORT=<1-65535>. Ready connection strings appear in /etc/qeli/client-links/.
Why not curl … | bash: the script runs as root, so download and review it first.
System changes: forwarding and MSS clamping are enabled, and BBR/fq, TCP/PMTU and socket-buffer sysctls are applied. The panel remains on HTTPS 127.0.0.1:8080; open it through an SSH tunnel. Use the file from tag v0.8.1 for reproducibility.

Updating the server

For a server installed from a .deb, use the supported updater. It updates the package and binary, preserves the configuration and attempts to roll the package back if the service cannot start. Back up /etc/qeli and /var/lib/qeli before running it.

server terminal
$ sudo qeli check-config --config /etc/qeli/server.conf
$ curl -fsSLO https://raw.githubusercontent.com/litvinovtd/qeli/main/update-qeli-server.sh
$ less update-qeli-server.sh
$ sudo bash update-qeli-server.sh

When upgrading from a version before 0.7.15, remove the obsolete tun.netmask; pool.cidr is now the sole subnet source. Then run sudo qeli check-config. The update restarts the service and drops live sessions; clients reconnect automatically. The script runs as root, so download and review it before execution.

Pre-upgrade checks

0.8.1 is released as a beta. Before replacing the binary, create a verified backup, run qeli check-config for the server and every client profile, and verify the 17 release payloads against SHA256SUMS.

checks before replacing a working installation
$ sudo qeli check-config --config /etc/qeli/server.conf
$ sudo qeli check-config --client --config /etc/qeli/clients/<profile>.conf

The first command validates the server configuration and user database; repeat the second for every enabled client profile. Fix routing and IPv6 errors before restart. Upgrade each app with its bundled 0.8.1 native core; do not replace it manually with an older build.

Official 0.8.1 release →

Current released version · beta

Upgrading to Qeli 0.8.1

Upgrade the server first, validate the configuration and restart the service. Then install the complete new applications with their bundled native cores. UDP batching is automatic; NDP proxy and large route_file imports require deliberate configuration.

Upgrade order: server → validation → restart → applications. Do not mix a 0.8.1 UI with a manually copied older native core. The server remains compatible with older peers, but connection properties and platform lifecycle fixes require the complete 0.8.1 set.
server · validate and restart
$ sudo qeli check-config --config /etc/qeli/server.conf
$ sudo systemctl restart qeli
$ qeli --version
$ sudo journalctl -u qeli -n 100 --no-pager

UDP batching needs no new setting. Linux and Android automatically use bounded recvmmsg/sendmmsg batches of up to 32 without an extra coalescing timer; packet order, roaming, pacing and PMTU fallback are preserved.

Review the expanded route_file format before importing large lists: the key is repeatable, CIDR and OpenVPN route lines are accepted, and the total bound is 250,000. An unreadable file, malformed mask or bound violation now stops the connection fail-closed.

Android and iOS now wait for a genuinely usable Wi-Fi/cellular carrier instead of spending backoff with no network. Install the complete 0.8.1 app; a manual disconnect remains authoritative and must not trigger automatic recovery.

Keep routing.ipv6.ndp_proxy = off when the provider routes the client prefix to the server WAN address. For an on-link prefix, verify Neighbor Solicitations and start with auto; use required after checking the interface and CAP_NET_RAW.

Container

Run in Docker

The container carries both roles — server and client — with every dependency bundled. It runs on Linux hosts and router container runtimes (MikroTik RouterOS v7, OpenWrt). To keep the 0.8.1 installation independent of the GHCR :latest state, this guide builds the image from the pinned v0.8.1 tag and starts it with Docker Compose:

server terminal
# get the published 0.8.1 sources:
$ git clone --branch v0.8.1 --depth 1 https://github.com/litvinovtd/qeli.git
$ cd qeli
# build a local image from the pinned tag:
$ docker buildx build -f release/docker/Dockerfile -t qeli:latest --load .
$ cp release/docker/docker-compose.yml .
# start the server:
$ docker compose -f docker-compose.yml up -d qeli-server

The container needs /dev/net/tun and the NET_ADMIN, NET_RAW, NET_BIND_SERVICE capabilities (no --privileged); server NAT also needs net.ipv4.ip_forward=1. Persist the /etc/qeli volume — it holds the server key and users. The same image also runs as a gateway client (client); for a client in a container set dns = off. The full guide (Linux and MikroTik) is in release/docker/README.md.

Clients

Download a 0.8.1 client

Use files from the official release only: QeliWin-standalone.exe or QeliWin-net-required.exe for Windows, Qeli-macOS-universal.zip for macOS, qeli-android-0.8.1.apk for Android, and qeli-linux-amd64 or qeli_0.8.1_amd64.deb for Linux. Upgrade applications together with their bundled native cores; the release has no prebuilt iOS artifact.

verify downloaded files
# Linux / macOS: keep SHA256SUMS next to the downloaded file
$ sha256sum -c SHA256SUMS --ignore-missing

# Windows PowerShell: compare the result with SHA256SUMS
PS> Get-FileHash .\QeliWin-standalone.exe -Algorithm SHA256

Open the official 0.8.1 release →

Routers

MikroTik, Keenetic and OpenWrt

On MikroTik RouterOS v7, Qeli runs from an OCI image using the built-in container runtime. The release provides tested client-only builds for Keenetic and OpenWrt across several architectures, with operation confirmed on real routers. Before installation, verify the architecture, TUN availability and the file SHA-256.

Installation depends on the model, architecture and TUN availability. Follow the version-pinned instructions, not a command written for another platform.

Full guide: Docker on MikroTik RouterOS v7 → Keenetic instructions → OpenWrt instructions →

What you'll need

  • A Linux servera VPS with a public IP, 1–2 cores, ~512 MB RAM; the prebuilt .deb is amd64
  • root accessnetwork privileges: TUN, NAT, port binding
  • Rustto build from source — or a prebuilt binary / .deb
  • A clientfor your platform: Linux, Windows, macOS or Android
Step 1

Build and install

For a reproducible build, check out tag v0.8.1, enable the production jemalloc feature and install runtime dependencies. One binary works as server, client and management tool.

server terminal
$ git clone https://github.com/litvinovtd/qeli.git
# pin the published version
$ cd qeli && git checkout v0.8.1 && cd qeli
# release server builds use jemalloc to keep RSS stable under churn
$ cargo build --release --features jemalloc
$ sudo install -Dm755 target/release/qeli /usr/bin/qeli

# the .deb creates the service, user and directories;
# create them yourself for a manual build:
$ sudo apt install -y iproute2 iptables libcap2-bin
$ getent passwd qeli >/dev/null || sudo useradd --system --user-group --no-create-home --shell /usr/sbin/nologin qeli
$ sudo install -d -o qeli -g qeli /etc/qeli /var/log/qeli /var/lib/qeli
$ sudo install -m640 -o qeli -g qeli config/server.conf /etc/qeli/server.conf
$ sudo touch /etc/qeli/users.conf
$ sudo chown qeli:qeli /etc/qeli/users.conf && sudo chmod 640 /etc/qeli/users.conf
$ sudo install -Dm644 debian/qeli.service /etc/systemd/system/qeli.service
# allow the unprivileged panel to restart qeli.service only
$ sudo qeli install-polkit
$ sudo systemctl daemon-reload
Step 2

Server configuration

Open /etc/qeli/server.conf — the single text format (flat-INI). A minimal reality-tls profile on 443 with internet egress:

/etc/qeli/server.conf
[auth]
# reality-tls and H-1 require a real pinned client key;
# true also rejects unpinned clients before AUTH and does not expose
# the identity key to a network scanner.
require_client_key_proof = true

[profile:main]
bind.address   = 0.0.0.0
bind.port      = 443
bind.transport = tcp
# reality-tls uses the reality_proxy settings below
obf.mode = reality-tls
tun.address    = 10.0.0.1
pool.cidr      = 10.0.0.0/24
# client internet egress
routing.nat.enabled = true
# resolver inside the tunnel
dns.enabled = true
dns.listen  = 10.0.0.1
dns.upstream = 1.1.1.1

# reality-tls: tunnel inside real TLS 1.3
# server_name must match target and is included in the qeli:// link
obf.tls.server_name = www.microsoft.com
obf.tls.reality_proxy.enabled   = true
# certificate source
obf.tls.reality_proxy.target = www.microsoft.com
# client token (reality_sid)
obf.tls.reality_proxy.short_ids = 7e78a17ad41f1004
# real TLS (handrolled by default)
obf.tls.reality_proxy.real_tls = true

Global sections are [auth], [web], [logging]; each interface is a [profile:name]. You can run several profiles at once (TCP and UDP on different ports). Comments must be on their own line.

obf.mode accepts plain, fake-tls, obfs (which needs obf.obfs_key) and reality-tls. For reality/reality-tls, configure obf.tls.reality_proxy.*; real_tls = true enables genuine TLS 1.3, while false keeps the port-sharing proxy mode. A UDP profile needs obf.quic.enabled = true and bind.transport = udp.

Step 3

Run as a service

Via systemd (recommended): the qeli service runs under a dedicated user with minimal privileges (network capabilities only) and restarts itself on failure.

server terminal
$ sudo systemctl enable --now qeli
$ sudo journalctl -u qeli -f   # follow logs

# or run manually in the foreground:
$ sudo qeli server --config /etc/qeli/server.conf

Condensed example: the real journal includes additional diagnostic lines, and one service can bring up several profiles at once:

server — Qeli
$ sudo qeli server --config /etc/qeli/server.conf
[info] qeli 0.8.1 · starting 5 profiles
[info] Profile 'reality' tcp/443    reality-tls · main
[ ok ]   REALITY real-TLS termination enabled
[info] Profile 'tls'     tcp/8443   fake-tls · fallback
[info] Profile 'obfs'    tcp/8444   obfs + WebSocket
[info] Profile 'plain'   tcp/8445   raw · trusted networks
[info] Profile 'udp'     udp/4443   udp-quic · QUIC-shaped masking
[ ok ] web admin → https://127.0.0.1:8080

On startup the server prints the active profiles and the web-panel address. HUP (or sudo systemctl reload qeli) reloads users and some runtime settings without dropping sessions. Changes to profiles, ports, TUN and transport require sudo systemctl restart qeli.

Step 4

Server key and pinning

Print each profile's public key — clients pin it so they can't connect to a spoofed server (anti-MITM):

server terminal
$ sudo qeli show-identity --config /etc/qeli/server.conf
main  a3f5…d290   # → client key field

Copy the key into the client's key field. A real pinned key is mandatory for reality-tls and the default-enabled H-1 path; require_client_key_proof = true additionally rejects unpinned clients before AUTH. Rotate it with sudo qeli rotate-identity <profile>, then restart the service and update the clients' key.

Step 5

Adding users

The add-client command stores an Argon2id hash plus a protected, reversibly encrypted password copy so the link or QR can be issued again. With --link --host it immediately prints a qeli:// link for app import.

server terminal
$ sudo qeli add-client alice --link --host vpn.example.com:443
password: x7Qp…m2K   # generated and printed once
qeli://alice:x7Qp…m2K@vpn.example.com:443?proto=tcp&mode=reality-tls&key=a3f5…d290&sni=www.microsoft.com&rsid=7e78a17ad41f1004

# provide a password without leaking it into argv or shell history:
$ read -rsp 'Password: ' QELI_USER_PASSWORD; echo
$ printf '%s\n' "$QELI_USER_PASSWORD" | sudo qeli add-client bob --password-stdin --profiles main --max-sessions 2
$ unset QELI_USER_PASSWORD

# apply new users without dropping active sessions
$ sudo systemctl reload qeli

The users file (auth.users_file, default /etc/qeli/users.conf) can also be edited by hand — one section per user plus [group:*] templates:

/etc/qeli/users.conf
[user:alice]
# added by qeli add-client alice
password_hash = $argon2id$…
enabled      = true
# simultaneous devices (0 = unlimited)
max_sessions = 2
# fixed tunnel IP (from pool.cidr)
static_ip = 10.0.0.50
# access to these profiles only
profiles = main
# allowed destinations (ACL); empty = unrestricted
allowed_networks = 10.0.0.0/24
# speed limit in Mbit/s (0 = unlimited)
bandwidth.limit_mbps = 50
# inherit limits from [group:premium]
group = premium
# additional route for this user
route = 10.20.0.0/16 gateway=10.0.0.1

[group:premium]
bandwidth_limit_mbps = 100
max_sessions = 3

Do not pass a secret through --password: the argument is visible in the process list and often remains in shell history. Use automatic generation or --password-stdin. Alongside the Argon2id hash, Qeli stores password_enc, encrypted under /var/lib/qeli/panel-secret.key; include that file in a disaster-recovery backup. Dual stack also supports --static-ipv6.

Reissue a link for an existing user

The share-link command uses the protected password copy and rebuilds a link from the current server profile:

server terminal
$ sudo qeli share-link alice --host vpn.example.com:443 --profile main
# legacy user without password_enc only: the password will be replaced
$ sudo qeli share-link legacy-user --host vpn.example.com:443 --profile main --reset
$ sudo systemctl reload qeli

--reset is destructive: the old client configuration stops working. Without --reset, the password does not change and no reload is needed.

Step 6

Connecting a client

App (phone / desktop): import the qeli:// link or scan the QR — server, mode and pinned key load automatically.

CLI client (Linux): fill in client.conf and run:

/etc/qeli/client.conf
[qeli]
server = vpn.example.com:443
proto  = tcp
mode   = reality-tls
user   = alice
pass   = ••••••••
# key from show-identity
key = a3f5…d290
# short_id from the server profile
reality_sid = 7e78a17ad41f1004
# must match the REALITY target
sni = www.microsoft.com
client terminal
$ sudo qeli client --config /etc/qeli/client.conf

Besides the basic fields, the client understands local options (file-only, not carried in a qeli:// link) — auto-MTU, the tunnel mode, a kill-switch, and OpenVPN-compatible persist_tun / local / metric (plus route_file in the Windows/macOS clients):

/etc/qeli/client.conf · [qeli]
# local options (not carried in qeli://).
# IMPORTANT: put comments on separate lines. Everything after '='
# becomes part of the value, including '# ...'.

# automatic MTU selection (important on LTE/CGNAT); >0 = manual
mtu         = 0
# full tunnel; false = split tunnel
gateway     = true
# also route the server's private subnets
route_local = false
# bypass the tunnel for these subnets
exclude     = 203.0.113.0/24
# block egress until the tunnel is up (Linux)
kill_switch = true
# keep the adapter and routes between reconnects (Windows/macOS)
persist_tun = true
# auto-connect when the panel/supervisor starts
autostart   = true

The proto, mode and (for obfs — obfs_key; for reality-tls — key, reality_sid, sni) fields must match the server profile — easiest is to import the qeli:// link, which fills them in. Routes, DNS and MTU are pushed by the server at connect; the local options above are optional. The full annotated key list is in config/client.conf; there are also mode aliases mode = udp-quic / udp-obfs.

Reference

Multiple profiles and modes

One server can run several profiles at once, one per transport mode and port; users are shared across them. The excerpt below is based on the current server-multiprofile.conf; every profile must have its own port, TUN and address pool.

/etc/qeli/server.conf
[profile:reality-tls]   # real TLS 1.3 — TCP :443
bind.port      = 443
bind.transport = tcp
obf.mode       = reality-tls
obf.tls.reality_proxy.enabled  = true
obf.tls.reality_proxy.real_tls = true
obf.tls.reality_proxy.target   = www.microsoft.com
obf.tls.reality_proxy.short_ids = 0123456789abcdef
tun.address    = 10.9.0.1
pool.cidr      = 10.9.0.0/24

[profile:fake-tls]       # TLS-shaped handshake — TCP :8443
bind.port      = 8443
bind.transport = tcp
obf.mode       = fake-tls
tun.address    = 10.9.1.1
pool.cidr      = 10.9.1.0/24

[profile:obfs]           # ChaCha20 obfuscation — TCP :8444
bind.port      = 8444
bind.transport = tcp
obf.mode       = obfs
obf.obfs_key   = change-me
tun.address    = 10.9.2.1
pool.cidr      = 10.9.2.0/24

[profile:udp-quic]       # fake-tls + QUIC over UDP — UDP :8449
bind.port      = 8449
bind.transport = udp
obf.mode       = fake-tls
obf.quic.enabled = true
tun.address    = 10.9.7.1
pool.cidr      = 10.9.7.0/24

The full 0.8.1 template contains 10 ready profiles: reality-tls, reality, fake-tls, obfs-ws, obfs-none, plain, udp-fake-tls, udp-quic, udp-obfs and obfs-awg. New templates enable bounded roaming, dual stack and recordizer.policy=prefer.

Open the 0.8.1 template →

Scenarios

Internet egress via the server

All device traffic goes through the server and exits to the internet with its IP — a classic VPN: privacy on public networks, a single external address. The server needs NAT and the client needs gateway = true: by default the client runs in split-tunnel mode.

/etc/qeli/server.conf · [profile:main]
# masquerade clients for internet egress
routing.nat.enabled = true
# resolver inside the tunnel
dns.enabled = true
/etc/qeli/client.conf · [qeli]
# full tunnel is enabled ON THE CLIENT; gateway = false (split tunnel) by default
gateway = true
# optional: block traffic outside the tunnel until it is up (Linux)
kill_switch = true
Scenarios

Access the LAN behind the server

Reach the local network behind the server from anywhere — NAS, cameras, printers and internal services. The server advertises the LAN route and forwards packets without NAT; the home router sends replies to pool.cidr through the Qeli server's LAN address.

/etc/qeli/server.conf · [profile:main]
# routing without source-address translation
routing.nat.enabled = false
routing.forward_private = true
# subnet behind the server
route = 192.168.1.0/24 gateway=10.0.0.1

Configure the return path: add a route for pool.cidr through the Qeli server's fixed LAN address on the home router. A client route can be assigned per user with route in [user:name]. Use NAT only as a fallback when the router cannot add static routes.

Scenarios

Joining networks (site-to-site)

Connect whole networks of several sites so their hosts can see each other — link offices, branches, home and work networks. At each site you place a gateway running qeli client with a fixed tunnel IP; the server advertises routes to the sites' subnets, and traffic flows between the networks through the tunnel at L3.

Only a real VPN can do this. A proxy (VLESS, V2Ray, Shadowsocks) forwards individual apps' traffic and doesn't route whole subnets — joining networks is fundamentally impossible for it. Qeli works with a TUN at the routing layer (L3), so it links networks into a single fabric.
/etc/qeli/users.conf
[user:branch-a]
# LAN BEHIND this client — the OpenVPN iroute equivalent (key line)
client_subnet = 192.168.50.0/24
# fixed tunnel IP — convenient but optional
static_ip = 10.0.0.10
/etc/qeli/server.conf · [profile:main]
# site-to-site runs WITHOUT NAT, preserving real addresses
routing.nat.enabled = false
# tunnel ↔ network forwarding without MASQUERADE
routing.forward_private = true
# return route to the server-side LAN, pushed to clients
route = 10.20.0.0/24 gateway=10.0.0.1
/etc/qeli/client.conf · site A gateway
[qeli]
# ip_forward + FORWARD ACCEPT + MSS clamp, but WITHOUT MASQUERADE —
# real LAN addresses are preserved
forward = true

The key line is client_subnet on the user: it registers the subnet behind that client as an inbound route. Without it the server drops packets to any address other than the client's pool IP. On the site gateway set forward = true (forwarding without NAT). Available since 0.7.11; not supported on Android. Keep the sites' addressing non-overlapping.

Scenarios

Split tunnel

Only what's needed goes through the tunnel — e.g. work subnets — while the rest of the client's traffic goes directly. The client picks the mode: gateway = false (the default), while the server just advertises the routes. Individual subnets can instead be sent around the tunnel with exclude.

/etc/qeli/server.conf · [profile:main]
# no full-tunnel internet egress
routing.nat.enabled = false
# work subnets only
route = 10.50.0.0/16 gateway=10.0.0.1
/etc/qeli/client.conf · [qeli]
# split tunnel is the default: only assigned routes use the tunnel
gateway = false
# optionally bypass the tunnel for selected subnets
exclude = 203.0.113.0/24
Management

Management commands

These commands use a 0600 control socket, so the examples include sudo. Most changes apply live. The exceptions are rotate-identity and set-web-password: they edit the on-disk config and require sudo systemctl restart qeli.

sudo qeli list-clientswho is connected now
sudo qeli kick <user>disconnect a user
sudo qeli disable-user <user>block (disconnect + prevent reconnect)
sudo qeli enable-user <user>re-enable login
sudo qeli set-bandwidth <user> <mbps>bandwidth limit (0 = unlimited)
sudo qeli show-routes <user>a user's routes
sudo qeli list-blockedIPs blocked by VPN-login protection
sudo qeli unblock <ip>unblock an IP; --all clears all
sudo qeli rotate-identity <profile>rotate a profile's server key
sudo qeli set-web-passwordset the web-panel login password
Web panel

Manage from a browser

The panel manages profiles, users, groups, routes, keys and backups. Login is protected by Argon2id, CSRF and separate brute-force protection. The three configurations below are independent scenarios; do not mix their settings into one config.

Common step · Panel password

Add the settings from one option below, then run the command: with no password argument it generates a strong password, prints it once, and adds username and password_hash to the same section. To supply your own password, use --password-stdin, not the unsafe --password argument.

server terminal
$ sudo qeli set-web-password
$ sudo systemctl restart qeli

Option A · Loopback and an SSH tunnel only

This is the safest option and the installer default: the panel listens on the server only. Changing the bind address or TLS requires a full restart.

/etc/qeli/server.conf · [web]
[web]
# qeli set-web-password adds username and password_hash
enabled = true
bind = 127.0.0.1
port = 8080
tls = true
csrf = true
session_ttl_secs = 86400
update_check = false
brute_force.max_attempts = 5
open the tunnel from your workstation
$ ssh -L 8080:127.0.0.1:8080 root@vpn.example.com
# then open https://127.0.0.1:8080

Option B · Direct public HTTPS

Expose the panel directly only with TLS and a non-empty allowed_ips. Enter your real IP or CIDR: the documentation address below will not let you in.

/etc/qeli/server.conf · [web]
[web]
# qeli set-web-password adds username and password_hash
enabled = true
bind = 0.0.0.0
port = 8080
tls = true
allowed_ips = 203.0.113.4
public_host = vpn.example.com
allowed_origins = vpn.example.com:8080
csrf = true

Option C · Behind a reverse proxy

TLS terminates at the proxy while Qeli remains on loopback. Put the proxy's own address in trusted_proxies; allowed_origins must match the browser host. Proxy the prefix without stripping it.

/etc/qeli/server.conf · [web]
[web]
# qeli set-web-password adds username and password_hash
enabled = true
bind = 127.0.0.1
port = 8080
tls = false
base_path = /qeli
allowed_origins = panel.example.com
trusted_proxies = 127.0.0.1
secure_cookie = true
csrf = true

If the panel returns 403: for a normal GET, check allowed_ips first; if the page opens but saving returns 403, check allowed_origins. Socket settings (enabled, bind, port, tls, base_path) apply only after a full restart.

Operations

Backup and recovery

The panel backup button creates a validated archive of /etc/qeli containing the configuration, users and server keys. The machine-local /var/lib/qeli/panel-secret.key is deliberately excluded. For full disaster recovery, therefore, save both /etc/qeli and /var/lib/qeli; the archive contains secrets and must be stored encrypted.

complete offline server backup
$ sudo systemctl stop qeli
$ sudo tar --xattrs --acls -C / -czf /root/qeli-backup-0.8.1.tar.gz etc/qeli var/lib/qeli
$ sudo systemctl start qeli
$ sudo tar -tzf /root/qeli-backup-0.8.1.tar.gz

Before restoring, inspect the file list, stop the service and save the current state separately. After returning the files, restore the qeli:qeli ownership and strict permissions on secrets, run sudo qeli check-config --config /etc/qeli/server.conf, and only then start the service. The panel can safely validate and restore the /etc/qeli archive it created, but it does not replace a full copy of /var/lib/qeli.

0.8.1 operations guide →

Checks

Troubleshooting common problems

Start with the configuration, service state and journal. Then separate a tunnel problem from NAT, DNS and panel access.

sudo qeli check-config --config /etc/qeli/server.confsyntax, users, profiles and conflicts
sudo systemctl status qeli --no-pagerservice state and the latest error
sudo journalctl -u qeli -n 200 --no-pagerthe latest 200 journal lines
sudo sysctl net.ipv4.ip_forwardmust be 1 for full tunnel
sudo iptables-save | grep qeli-natcheck the NAT rules created by Qeli

If the tunnel is up but there is no internet, check routing.nat.enabled = true, forwarding and firewall rules. If TCP sites stall, check MSS clamping and MTU. If the panel returns 403, verify allowed_ips, allowed_origins and the trusted proxy address. If a problem followed a manual edit, remember that comments are valid only on a line of their own.

Maintenance

Removing Qeli

First stop the service and remove the package. Configuration and state are deliberately retained so the installation can be recovered.

server terminal
$ sudo systemctl disable --now qeli
$ sudo apt remove qeli

Irreversible: delete /etc/qeli, /var/lib/qeli and /var/log/qeli only after validating a backup. This erases server keys, users and the machine key that decrypts password_enc; existing client configurations cannot be reissued with the old identity.

optional removal of all data
$ sudo rm -rf /etc/qeli /var/lib/qeli /var/log/qeli

← Back to the product overview