xTQ Web is the program that sits in front of a website: every visitor reaches it first, and it adds HTTPS, serves files, passes requests to the app behind it, and keeps floods out. 1.0.3 is the release for people running more than one site behind it, and if that's you, it's worth the upgrade.
Short version: run the installer again and you're on 1.0.3. Your config keeps working unchanged.
curl -fsSL https://xtq.ro/web/install.sh | sh
If you installed it with Docker, add -s -- --docker at the end as before.
A certificate for each site
Until now every site shared one fallback certificate and automatic HTTPS handled the rest. 1.0.3 lets a site carry its own:
site example.com {
tls /etc/ssl/example.com/fullchain.pem /etc/ssl/example.com/key.pem
proxy 127.0.0.1:3000
}
Point tls at a certificate and key and that site serves them. A site that sits behind a proxy terminating HTTPS itself (Cloudflare's "Full" mode, say) can use tls internal for a self-signed one instead. xTQ Web picks the right certificate per connection: the site's own first, then an automatic one, then the fallback. A reload re-reads the files, so renewing a certificate is a reload away.
Split your config into files
One big config file gets unwieldy once you host a lot of sites. include pulls in others:
include /etc/xtq-web/sites/*.conf
Drop one file per site into a folder and they are all picked up. A folder that is empty, or not there yet, is fine. It is made for tools that write a file per site and reload, but it tidies a hand-written setup just as well. Mistakes still point at the real file and line, so a typo in one included file is easy to find.
Your own page when an app is down
When the app behind a site cannot answer, xTQ Web returns a plain "service unavailable". Now you can answer with something of your own instead:
site example.com {
proxy 127.0.0.1:3000
errors {
files /var/www/maintenance
}
}
The errors block runs only when xTQ Web itself could not get an answer (nothing listening, a timeout, every slot busy), not when your app returns its own error. It can serve a file, send a fixed response, redirect, or hand off to another backend, and the answer carries that handler's own status. So a visitor sees your "back shortly" page, not a bare error.
The real visitor's details, where your app expects them
Values in the headers xTQ Web sends your app, and in the headers and redirects it sends back, can now carry placeholders:
proxy 127.0.0.1:3000 {
header_up X-Real-IP {client_ip}
}
{client_ip} is the visitor's address worked out through your trusted proxies, {remote_ip} is the raw connection, and {host}, {uri}, {path}, {query}, {scheme} and {header.Name} fill in the rest. An app that needs the real client address in a particular header gets exactly that, however many proxies sit in front.
Send different requests different ways
A route can now match on more than the path:
site app.example.com {
route /live {
websocket
proxy 127.0.0.1:3000
}
route /admin/* {
remote_ip 10.0.0.0/24
proxy 127.0.0.1:3000
}
respond 426 "upgrade required"
}
websocket matches a WebSocket connection, remote_ip matches the address that actually connected (not one a header claims), and has header Name value matches a request header. Each has a not form. Together they let you send live connections one way and everything else another, or lock a path to a range of addresses.
Automatic HTTPS got tidier
Automatic certificates no longer chase names they should not: a site with its own tls, a name already covered by a wildcard certificate, and a site that only serves plain HTTP are all skipped. Fewer pointless requests to Let's Encrypt, and no wasted tries against names that were never going to get a certificate that way.
Where to read more
The documentation has all of it in full, and the configuration reference lists every directive. If something does not behave the way you expect, start at troubleshooting.

Comments