Octa Engineering Notes Christian Elías Request for Comments: OCTA-14 octa.page Category: Informational June 2026 Building @avelor/vhost: From Repeated Pain to Open Source Tool Abstract @avelor/vhost generates Apache VirtualHost configs from a YAML file — with a managed-config marker for gradual migration, a default-vhost that blocks unrecognized requests, and content-negotiated error pages that serve HTML or JSON based on the Accept header. Status of This Memo This memo documents systems notes for the Internet community. It does not specify an Internet standard of any kind. Distribution of this memo is unlimited. The canonical version lives at https://octa.page/doc/building-avelor-vhost/ and the machine-readable source at https://octa.page/doc/building-avelor-vhost.md Every new domain starts the same way. Copy a VirtualHost template, replace three strings, uncomment the SSL block after Certbot runs, verify the HTTP→HTTPS redirect is there. Repeat for aliases. The template is maybe 40 lines. After the tenth domain, you have ten variants, some with subtle differences: a missing "AllowOverride All", a wrong log path, an alias that didn't make it to the "RewriteCond". The other half of the problem is invisible. Apache's default behavior when a VirtualHost doesn't match is to fall through to the first ".conf" alphabetically. On a server with ten domains, an unrecognized request — a crawler, a scanner, a misconfigured DNS — silently gets served content from whichever site happens to sort first. No error page. No indication anything went wrong. The fix for both problems is the same: stop treating VirtualHost configs as files you edit and start treating them as artifacts you generate. 1. The tool "@avelor/vhost" is a Node.js CLI that takes a "sites.yml" and produces Apache configs. sites: avelor.com: aliases: [www.avelor.com] mode: static root: /home/avelor/avelor api.avelor.es: mode: proxy port: 3000 "sudo vhost apply" generates the ".conf" files, runs "a2ensite", runs "apache2ctl configtest", and reloads Apache. Every generated file has "# Generated by @avelor/vhost" on the first line. That comment is load-bearing — "vhost check" reads it to distinguish generated configs from hand-written ones. 2. Gradual migration The tool was designed around an existing server with hand-written configs. Requiring a full migration upfront is a non-starter: ten domains, some with complex rewrite rules, some with custom headers. One bad config and the whole server is down. The managed marker solves this without ceremony. Every ".conf" that predates "vhost apply" shows up in "vhost check" as "manual config" — functional, not yet under source-of-truth control: ✓ avelor.com managed /home/avelor/avelor ! old-client.com manual config not in sites.yml ! staging.app.com manual config → run: vhost apply staging.app.com to migrate Migration is one site at a time. Add the domain to "sites.yml", run "vhost apply ", the generated config overwrites the manual one. When "vhost check" shows no "manual config" entries, the migration is complete. 3. Error pages via content negotiation "vhost apply" installs built-in error pages for the full 4xx/5xx range. The design constraint: a server that hosts both web apps and APIs needs error responses in the right format depending on who's asking. The implementation uses Apache's "MultiViews" content negotiation with static files. Each error code has three variants: /var/www/vhost-errors/ 404.html 404.json 404.xml 500.html 500.json 500.xml ... The "ErrorDocument" directive points to the path without extension: ErrorDocument 404 /vhost-errors/404 Apache picks ".html", ".json", or ".xml" based on the request's "Accept" header. No PHP, no CGI, no runtime. The JSON response is "{"code": 404, "message": "Page not found."}". The HTML page shows the status code large, a generic message, and "Avelor · vhost" fixed at the bottom. 4. Why open source Avelor already publishes independent developer tools. The pattern is consistent: if the problem is universal and the solution has no coupling to private infrastructure, it goes public. The Apache VirtualHost problem isn't specific to Avelor. Any developer running multi-domain Apache on a VPS encounters it. The tool is a YAML-to-Apache-config transformer with a CLI and nothing else. Keeping it private would be the stranger choice. Christian Elías Informational [Page 1]