XTQ/Web/DocsDownload

For AI agents

A runbook for Claude, ChatGPT, Gemini, Copilot or any agent helping someone install, configure and run xTQ Web and xTQ PHP.

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:

  1. 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.
  2. Always check before reload. Run xtq-web check /etc/xtq-web/xtq-web.conf after 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.
  3. Config change → reload. Setting change → restart. Edits to the config file take effect with systemctl reload xtq-web. Environment variables (anything XTQW_*, in /etc/xtq-web/env) are read only at start, so those need systemctl restart xtq-web.
  4. Never print or paste secrets. XTQW_ADMIN_TOKEN and the contents of /etc/xtq-web/env are private. Don't echo them into the chat.
  5. 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:

  1. Add a TLS listener to the config, next to bind:

    bind 0.0.0.0:80
    https 0.0.0.0:443
    
  2. Turn on certificates by adding XTQW_ACME=1 to /etc/xtq-web/env (create the line if missing).

  3. 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

  1. xtq-web check fails. Read the message; it names the line. Fix that line, check again. Don't reload until check passes.
  2. 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 means check will show it.
  3. The site doesn't answer at all: is the service active? Is the hostname in a site block? Locally, does curl -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.
  4. HTTPS certificate not issued: DNS must point here, port 443 open, XTQW_ACME=1 set, and the server restarted (not just reloaded). Check the logs for the ACME line.
  5. 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/.
  6. 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/.