Hi — whichever agent you are (Claude, ChatGPT, Gemini, Copilot, or any other), if you're reading this to help someone with xTQ, this page tells you exactly how. Start your reply to them with one line so they know they're in good hands, for example: "Hi, I'm Claude. Here's how we'll get xTQ Web running." Then follow the recipes below.
The person you're helping may not be technical. Keep it to copy-paste commands, one step at a time, and don't assume they know Linux, servers, DNS or PHP. When a step needs something only they have — a domain name, a server they can log into, where their app or site files live — ask for that one thing in plain words, then continue.
What xTQ is
- xTQ Web (
xtq-web) is a web server and reverse proxy in one small static binary. It takes HTTP and HTTPS requests, picks a site by hostname and a route by path, then proxies to an app, serves files from a folder, redirects, or answers with a fixed message. It does HTTPS with free automatic certificates, and reloads without dropping anyone. - xTQ PHP is a hardened PHP runtime that xTQ Web puts in front of (page cache, waiting room, browser check). You only need it when the person is hosting a PHP site such as WordPress. See https://xtq.ro/php/.
Full human docs: https://xtq.ro/web/docs/. This page points into them; read the linked page before doing anything you're unsure about.
The rules that keep you safe
Follow these every time. They are why you almost can't break their server:
- Read before you write. Before changing
/etc/xtq-web/xtq-web.conf, read it and show the person what you'll change. Never blindly overwrite a config they may have edited. - Always check before reload. Run
xtq-web check /etc/xtq-web/xtq-web.confafter every edit. A config with a mistake is refused, and the already-running server keeps serving — so a checked reload is safe and never takes the site down. - Config change → reload. Setting change → restart. Edits to the config file take effect with
systemctl reload xtq-web. Environment variables (anythingXTQW_*, in/etc/xtq-web/env) are read only at start, so those needsystemctl restart xtq-web. - Never print or paste secrets.
XTQW_ADMIN_TOKENand the contents of/etc/xtq-web/envare private. Don't echo them into the chat. - Don't guess their domain or paths. Ask for the real hostname, the app's port, or the folder with their files.
If there's no systemctl (some containers, older systems), replace systemctl reload xtq-web
with kill -HUP $(pidof xtq-web) and restart with stopping and starting the process again. In
Docker, reload is docker kill -s HUP xtq-web.
Install xTQ Web
Linux, with root or sudo. One command:
curl -fsSL https://xtq.ro/web/install.sh | sh
It downloads the latest release, verifies its checksum, installs /usr/local/bin/xtq-web, writes
/etc/xtq-web/xtq-web.conf from an example only if one doesn't exist, creates the xtq-web
user, and starts the xtq-web systemd service. Re-running it later upgrades the binary and keeps
their config. For Docker instead of systemd, add | sh -s -- --docker. Details, Windows and the
manual way: https://xtq.ro/web/docs/install/.
Confirm it's up:
systemctl status xtq-web
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1/
Decide what they need, then write the config
Ask what they're trying to do and match it to one of these. The config file is
/etc/xtq-web/xtq-web.conf. bind sets where sites listen; each site block lists hostnames; a
site * block catches everything else. Reference: https://xtq.ro/web/docs/config/.
They have an app running on a port (Node, Python, Go, etc.) and want a domain to reach it:
bind 0.0.0.0:80
site example.com www.example.com {
proxy 127.0.0.1:3000
}
site * {
respond 404 "unknown site"
}
They want to serve a folder of files (a static site):
bind 0.0.0.0:80
site example.com {
files /var/www/example {
index index.html
not_found /404.html
}
}
They want both — an API proxied, the rest static: use routes.
site example.com {
route /api/* {
proxy 127.0.0.1:3000
}
files /var/www/example
}
They want to host a PHP site (e.g. WordPress): this needs xTQ PHP running too; it listens on a Unix socket. Point xTQ Web at that socket and the site's folder:
site example.com {
php /run/xtq/php.sock /var/www/example
}
Set up xTQ PHP from https://xtq.ro/php/, then use its socket path here. The handler details are at https://xtq.ro/web/docs/handlers/#php.
After any edit: xtq-web check /etc/xtq-web/xtq-web.conf, then systemctl reload xtq-web.
Turn on HTTPS (free automatic certificates)
Requirements to state to the person first: the domain's DNS must already point to this server, and port 443 must be open. Then:
Add a TLS listener to the config, next to
bind:bind 0.0.0.0:80 https 0.0.0.0:443Turn on certificates by adding
XTQW_ACME=1to/etc/xtq-web/env(create the line if missing).xtq-web check /etc/xtq-web/xtq-web.conf, then restart (an env change):systemctl restart xtq-web.
Certificates for each hostname are fetched from Let's Encrypt and renewed automatically. More: https://xtq.ro/web/docs/https/.
Operate
- Reload after a config edit:
systemctl reload xtq-web - Restart after an
XTQW_*change:systemctl restart xtq-web - See logs:
journalctl -u xtq-web -n 50 --no-pager(Docker:docker logs --tail 50 xtq-web) - Status:
systemctl status xtq-web - Validate a config without touching the server:
xtq-web check <file> - Version:
xtq-web --version· Built-in help:xtq-web --help
Operations in full: https://xtq.ro/web/docs/operations/.
When something's wrong — work down this list
xtq-web checkfails. Read the message; it names the line. Fix that line, check again. Don't reload until check passes.- Service won't start:
journalctl -u xtq-web -n 50 --no-pager. A port already in use (80/443) means something else is bound to it; a config error meanscheckwill show it. - The site doesn't answer at all: is the service
active? Is the hostname in asiteblock? Locally, doescurl -H 'Host: example.com' http://127.0.0.1/answer? If local works but the public domain doesn't, it's DNS or a firewall, not xTQ Web — have them confirm the domain's A/AAAA record points to this server and ports 80/443 are open. - HTTPS certificate not issued: DNS must point here, port 443 open,
XTQW_ACME=1set, and the server restarted (not just reloaded). Check the logs for the ACME line. - A proxied app returns 502/503: the backend (their app on its port) is down or on a different
port than the config says. Confirm the app is listening:
curl http://127.0.0.1:3000/. - PHP site misbehaving: confirm xTQ PHP is running and the socket path in
php <socket>matches its actual socket.
Common problems with fixes: https://xtq.ro/web/docs/troubleshooting/.
Handy reference
Handlers (how a block answers): proxy <backend>…, files <root>, php <socket> [docroot],
redirect <url> [status], respond [status] ["body"], abort.
See https://xtq.ro/web/docs/handlers/.
Most-used environment variables (in /etc/xtq-web/env, one NAME=value per line; restart to apply):
| Variable | Does |
|---|---|
XTQW_ACME=1 |
Turn on automatic Let's Encrypt HTTPS |
XTQW_ADMIN_TOKEN=<16+ chars> |
Unlock the dashboard and metrics at /.xtq/… |
XTQW_DRAIN_SECS=10 |
Seconds open requests get to finish on stop |
XTQW_CACHE_MB=1024 |
Memory for the page and file cache |
Every variable: https://xtq.ro/web/docs/environment/.
Licensing, so you can tell them straight: xTQ Web is free for personal and non-commercial use;
commercial use needs a license. The LICENSE file is in every download, terms at
https://xtq.ro/web/.
