FrontierStack User Manual Manual home
Desktop Manual Mobile Manual 日本語한국어 frontierstack.app ↗

Part II

II
Running Services

Running the web stack, databases, the service catalog and your sites on the Mac in front of you.

4

Chapter 4

The Web Stack

Apache or Nginx, the PHP version each site needs, virtual hosts, trusted local HTTPS and DNS — the whole web stack, controlled from one window with no hand-edited config.

A web server is the heart of most self-hosted setups, so FrontierStack treats it as a first-class citizen. The Apache pane installs, starts, validates and configures a Homebrew Apache; the PHP, Localhost, Certificates and DNS panes round out a complete development and hosting stack — and every change goes through validation so a typo never takes a site down silently.

This chapter covers the panes that make and run web sites on the Mac in front of you. Connecting that stack to a real domain and the public internet is Chapter 7; tightening it for production is Chapter 10.

4.1The Apache pane

Open the Apache pane from the sidebar to see your web server’s state at a glance: version, whether it is running, and the ports it listens on. The buttons across the top are the controls you reach for daily — Start, Stop, Restart and Validate Config. Validation runs apachectl -t (a real syntax check) and shows the result in Last Result, so you can confirm a change is sound before you reload.

FrontierStack recommends a Homebrew Apache rather than the macOS system copy. The Homebrew server lives under /opt/homebrew (or /usr/local on Intel Macs), runs as you through brew services without a root prompt for every action, and is not locked down by System Integrity Protection — so a current mod_php loads cleanly and the whole stack stays on one toolchain. The system Apache under /etc/apache2 is wiped by OS updates and ties you to Apple’s bundled libphp. If Homebrew Apache is not installed, the pane offers Install Homebrew Apache… in one click.

If you keep several Apache builds — the Homebrew one, a legacy local build, or a remote server’s — the binary picker (see Add Homebrew Apache / Add Local Build…) lets you register and switch between them, each with its own version and ports shown.

NoteAll of FrontierStack’s own additions to Apache live in an app-managed config tree at /opt/homebrew/etc/httpd/frontierstack/, pulled in by an IncludeOptional from httpd.conf. Keeping the app’s vhosts, MIME types and managed includes there means your hand-written httpd.conf stays clean and you can always tell what FrontierStack added.

4.2Modules, ports and the managed config

Lower in the Apache pane are the parts of the config you most often edit, each surfaced as a control rather than a file:

SectionWhat it does
PortsSet the HTTP and SSL listen ports (default 80 and 443). Move Apache off 80/443 if Nginx is using them. Apply rewrites the Listen directives and reloads.
Apache Modules (Modules…)List loaded modules and enable or disable them. Disabling an unused module is the simplest hardening step you can take.
PHP ModuleChoose which version’s mod_php (libphp.so) Apache loads for websites — see the next section.
WebDAVEnable mod_dav for a shared folder, with optional Basic-auth user, written into a managed include.
Edit MIME Types…Add or remove AddType mappings in a FrontierStack-managed MIME file, never touching the distro’s mime.types.

For anything not exposed as a control, the config rows give you Edit Managed Config… (the FrontierStack include) and Edit httpd.conf… (the main file) directly. Every save validates with apachectl -t, reloads gracefully, and rolls back if the new config does not parse — so a bad edit is caught before it can break the running server.

WarningEditing httpd.conf by hand is powerful and unguarded. The app validates and rolls back on a syntax error, but a config that parses yet points a document root at the wrong place can still expose files. Prefer the managed include for FrontierStack’s own additions, and keep a copy of any large change.

Toggling a module rewrites its LoadModule line and revalidates. If a change leaves httpd -t failing — the classic case is enabling proxy_fcgi without proxy, which the app now auto-enables for you — the Modules window shows the error and won’t close silently: you either correct it or choose Save anyway. When Apache is wedged and won’t start (the classic Homebrew Bootstrap failed: 5: Input/output error, from a service that was already loaded, or from sudo brew services leaving some httpd paths owned by root), the pane’s Recovery & reset section offers three escalating fixes: Restart cleanly (stops httpd in both the user and system launchd domains, then starts it once), Reset config to default (backs up your httpd.conf and restores Homebrew’s), and Remove & Reinstall (clears the root-owned paths and reinstalls the formula). All run in the in-app console so you see the sudo prompt and output. If Service Watchdog keep-alive is also on for Apache, it may restart httpd on its own — expected, but pause it if it fights a manual recovery.

4.3Choosing the PHP version

Open the PHP pane to manage the PHP runtimes installed on the Mac. Homebrew lets several major versions live side by side (for example [email protected] through the current release), and FrontierStack treats them as a set you switch between rather than a single global install.

Version ▸ Add Version… installs another version alongside the ones already there — nothing is replaced, and the version you are using does not change. The list has two parts. Homebrew’s own releases are the ones still supported upstream. Below them sit the end-of-life builds — PHP 8.0 back to 5.6 — which PHP itself no longer patches and Homebrew has dropped; FrontierStack fetches those from the community shivammathur/php tap, and asks you to confirm each one first, because installing from a tap means running that tap’s own code. Keep an end-of-life PHP for testing or maintaining a legacy site on your own machine, and never point the public internet at it.

There are two distinct choices:

  • The Apache module. In the Apache pane’s PHP Module section, the Load for websites picker chooses which version’s libphp.so Apache loads. Changing it rewrites the managed config and reloads Apache.
  • Per-site PHP. A local dev server (the Localhost pane, below) has its own PHP Version picker listing every installed version, so one project can run on an older PHP while another runs on the latest — without changing what the rest of the machine uses. This is the usual way to keep a legacy app and a new one happy at the same time. It applies to both local runtimes: the PHP built-in server and the Apache runtime. One caveat for Apache, which serves through mod_php: a version is only usable there if its keg ships libphp.so, and the editor tells you when the one you picked does not. When it does not, run that site on the built-in server, or serve it through PHP-FPM.

PHP Cache. The PHP pane’s PHP Cache section chooses between No cache, OPcache and OPcache + APCu. OPcache keeps each script’s compiled form in shared memory, so pages run faster; APCu adds a key-value cache that apps call directly (apcu_store/apcu_fetch) — WordPress object-cache plugins, Laravel and Symfony use it. Set the OPcache memory and Check for changed files: Every request suits development, because an edited file shows on the next reload; Never suits production, where code changes appear only after a restart. APCu is a PECL extension, so the first time you pick it, press Install APCu. Apply Cache Settings writes php.ini and restarts Apache. Sites served through PHP-FPM pick up the change when their pool restarts.

The Runtime Health pane gives the wider picture — PHP alongside Python, Node.js, Java, Go, Rust, Ruby, Perl and .NET — with a self-check that flags a missing or end-of-life runtime before it bites you.

The Runtimes section also carries a React pane for front-end work. It scaffolds a new app (Vite, TanStack Start or Next.js), points at any React project, and offers a curated companion-library list filed by the job each does — state management (Zustand, Jotai, Redux Toolkit), data fetching and server state (TanStack Query — the library formerly called React Query — and SWR), full-stack frameworks (TanStack Start, Next.js), routing, validation (ArkType, Zod), forms, and authentication (Clerk). Each row shows its docs, whether the selected project already uses it, and a one-click npm install into that project.

4.4Updating PHP on an older Mac with MacPorts

Older Macs (macOS 10.13 High Sierra and earlier, including Apple Server.app machines) still run Apple's built-in PHP. On High Sierra that is PHP 7.1, which has had no security fixes since 2019. Homebrew no longer supports macOS this old, but MacPorts still does. Use it to install a current PHP alongside Apple's, then move the command line and the websites over to it. Run the commands in Terminal on that Mac, or over SSH. Every port command that changes something needs sudo; the error “attempt to write a readonly database” means it was left off. For a linked server, you can also ask the AI Administrator to walk you through these steps.

1. Make sure Terminal finds MacPorts. If port answers “command not found” although /opt/local/bin/port exists, the MacPorts installer didn't add its PATH line. Open ~/.bash_profile (or ~/.profile, if that is the file your shell reads) and find the comment “MacPorts Installer addition”. If nothing sits between it and “Finished adapting”, add this line there, then open a new Terminal window:

export PATH="/opt/local/bin:/opt/local/sbin:$PATH"

2. Update MacPorts and see what's installed. The last command lists the PHP 8 versions MacPorts offers.

sudo port selfupdate
port installed 'php*'
port echo 'name:^php8[0-9]$'

3. Install the new PHP and its extensions. The example uses PHP 8.4. Install the same extensions your sites already use; port installed 'php80-*' lists an older version's set.

sudo port install php84 php84-fpm php84-mysql php84-openssl
sudo port install php84-curl php84-intl php84-mbstring php84-gd php84-zip
sudo cp /opt/local/etc/php84/php.ini-production /opt/local/etc/php84/php.ini

Set date.timezone in the new php.ini. MacPorts usually downloads a ready-made build. If it compiles from source instead, this can take an hour and needs Apple's command-line tools (xcode-select --install).

4. Switch the command line.

sudo port select --set php php84
hash -r; php -v

php -v should now report 8.4. Apple's /usr/bin/php stays at 7.1, so cron jobs and scripts that name it by its full path keep the old version until you change them to /opt/local/bin/php.

5. Switch the websites to PHP-FPM. Apple's Apache can't load MacPorts' mod_php, which is built for MacPorts' own Apache. Run PHP as a FastCGI service instead:

cd /opt/local/etc/php84
sudo cp php-fpm.conf.default php-fpm.conf
sudo cp php-fpm.d/www.conf.default php-fpm.d/www.conf

In php-fpm.d/www.conf, set user = _www and group = _www, the account Apache runs as on macOS. PHP-FPM listens on 127.0.0.1:9000; if lsof -iTCP:9000 -sTCP:LISTEN shows something already using that port, choose another. Start it now and at every boot:

sudo port load php84-fpm

Then tell Apache to send .php files to it. Save the lines below as a file ending in .conf, for example zz-php84-fpm.conf. On a Server.app Mac it goes in /Library/Server/Web/Config/apache2/other/. On a Mac without Server.app, put it in /etc/apache2/other/ and remove the # in front of the mod_proxy and mod_proxy_fcgi LoadModule lines in /etc/apache2/httpd.conf.

<FilesMatch "\.php$">
    SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>

This takes precedence over Apple's PHP module without removing it, so leave Server.app's PHP setting as it is. Apple's setup also runs .html pages through PHP, but PHP-FPM handles only .php. To include other extensions, add them both here and to security.limit_extensions in www.conf.

6. Check the configuration and restart the web server. On a Server.app Mac:

export SERVER_INSTALL_PATH_PREFIX=/Applications/Server.app/Contents/ServerRoot MODULE_INSTALL_PATH_PREFIX=
httpd -t -D WEBSERVICE_ON -f /Library/Server/Web/Config/apache2/httpd_server_app.conf
sudo serveradmin stop web; sudo serveradmin start web

Server.app's Apache keeps its own process ID file, so don't use apachectl graceful there. On a Mac without Server.app, run sudo apachectl configtest, then sudo apachectl graceful. If the check reports anything other than “Syntax OK”, fix the file before restarting.

7. Confirm. Put a file containing <?php phpinfo(); in a site's folder and open it in a browser. Server API should read “FPM/FastCGI” and the version should be 8.4. Delete the file afterwards, because it shows the server's configuration to anyone.

WarningMoving from PHP 7 to 8 breaks some older code, so test each site after switching. To go back, delete the .conf file you added and restart the web server: the sites return to Apple's PHP straight away. sudo port select --set php none returns the command line to Apple's PHP. Keep the older MacPorts PHP installed until every site works.
TipIf a site can't reach MySQL on localhost (“No such file or directory”), PHP is looking for the database socket in the wrong place. Find the right path with mysql -e 'select @@socket', set mysqli.default_socket and pdo_mysql.default_socket to it in php.ini, then run sudo port reload php84-fpm.

4.5The Modernize Old Mac Server pane

For a linked Mac that still runs Apple’s Server.app, the Modernize Old Mac Server pane (Setup & Migration) does the steps above for you, then keeps going. Choose the server and press Check server. It first finds out which services the server actually runs and shows only the sections that apply, listing the ones it left out; nothing changes until you press a button, and every change runs in the console so you can watch it.

  1. System disk — shown at the top when the system runs from a spinning disk: move it to an SSD, inside the Mac or as an external SSD over Thunderbolt, USB 3 or FireWire 800, whichever is fastest on that model.
  2. MacPorts — install or update MacPorts, and put it on the Terminal PATH.
  3. PHP 8.4 (PHP-FPM) — install PHP 8.4 beside Apple’s PHP, then Switch websites: the old php.ini limits are copied, Deprecated notices hidden, and every site’s home page checked before and after, with an automatic switch back if one breaks. The PHP-FPM pool is sized to the Mac’s memory (not PHP’s stock 5 workers); Size Workers to Memory redoes it from the real worker size.
  4. Health check — which PHP answered each site, failures, visible PHP messages and the most frequent PHP errors.
  5. Code updates — mechanical PHP 8 fixes ($s{0} offsets, each() loops, literal create_function(), magic quotes, error_reporting(E_ALL), opt-in short <? tags), with the rest handed to the AI Administrator.
  6. Apache migration (optional) — everything else in the pane works with Server.app’s web service, so you can keep it (Keep Server.app’s web; the one-run paths then leave it alone). Or move all web services to MacPorts Apache, which still gets fixes — serviceproxy and Server.app’s own Apache behind it (after Apple’s PHP is retired; Test Front End Only moves serviceproxy alone): Retire serviceproxy works like Retire Apple’s PHP — every site, Server.app service path, page and file is named and fetched through both front ends before and after, scripts other than a folder’s index page are never opened, and serviceproxy comes straight back if any answer differs. Restore serviceproxy undoes it.
  7. Server.app services — a guard that keeps the service proxy (ports 80/443) running and reports a broken proxy configuration rather than restarting it blindly; for an installation still running Apple’s BIND, a guided move to Cloudflare or a current MacPorts BIND; where Server.app’s L2TP VPN runs, a recommendation to move users to WireGuard, OpenVPN or Tailscale and turn it off.
  8. Directory (LDAP & Kerberos) — checks for anonymous reads, the LDAPS certificate and weak Kerberos encryption; a pf rule that limits the directory ports to private networks; nightly encrypted Open Directory archives.
  9. Password-guessing blocks — the mail block described in Chapter 18, plus a login guard for SSH, Screen Sharing, Kerberos and websites. Attacks arriving through Cloudflare are listed per site for a Cloudflare rate-limit rule.
  10. Mail authentication (DKIM) — OpenDKIM, a key per domain, signing once DNS has the key; records published from the pane, copied, or handed to the AI.
  11. Mail TLS — TLS 1.2 and later only, and a Let’s Encrypt certificate issued on this Mac in place of a self-signed one.
  12. Mail DNS — SPF (with its lookup count), DMARC, DKIM, TLS-RPT and MTA-STS per domain; DMARC to quarantine and TLS-RPT from the pane, SPF fixes and MTA-STS with the AI.
  13. Spam filtering — rspamd, adding X-Spam headers only.
  14. Remote access (Tailscale) — Tailscale as a system service that starts at boot with nobody logged in, from the 1.44.3 build staged for macOS 10.13 (the installer refuses a server older than the build supports). It also checks that tailnet traffic really leaves through the tunnel: Tailscale.app running alongside fights over the routes and takes them away when it quits. Retire Tailscale.app quits it, stops it starting at login and restarts the daemon.
  15. Newer curl, rsync & OpenSSL — installed in /opt/local beside Apple’s copies, which Server.app keeps using.
  16. Admin-ports firewall — Screen Sharing, Remote Desktop, port 311, AFP, SMB and optionally SSH answer only private networks, Tailscale and the address FrontierStack connects from. The rules undo themselves within 10 minutes unless FrontierStack confirms them over a fresh connection.
  17. File integrity — a daily, root-only SHA-256 check of startup jobs, sudoers, pf, ssh keys, cron, Server.app and Apache configuration and the sites’ PHP. FrontierStack alerts on changes, and on a baseline replaced behind its back; Accept changes records the current files as the new baseline.
  18. Scanning with ClamAV — the pane installs and schedules the open-source ClamAV scanner: daily signature updates and a weekly, report-only scan of the websites plus a check for web-shell code and PHP in upload folders; optionally virus scanning of incoming mail through the spam filter.
  19. OpenSSH — install a newer OpenSSH, run it on port 2222 with Apple’s host keys, test a login, then switch port 22. The switch needs a second way in, and reverts by itself unless FrontierStack reconnects to confirm.
  20. Network around this server — read from your linked firewall and Subnets: Suricata and Zenarmor on the OPNsense in front of it, where a web application firewall belongs, VPN-only administration, and which machines share its network.
  21. Security checklist — TLS, SPF, DMARC, DKIM, reverse DNS, the service proxy, SSH logins and OS support, each linked to the pane that fixes it.

Keeping PHP patched. The pane compares the server’s PHP with php.net’s latest release of its branch, so it warns the day PHP ships a security release, even before MacPorts has packaged it; until MacPorts has, the warning says so. Once it has, Update PHP 8.4 (the Install button, run again) upgrades the PHP ports and restarts PHP-FPM, so no worker keeps running the old code. The Update for curl, rsync and OpenSSL upgrades those ports the same way, and the MacPorts section lists every MacPorts tool that is out of date on the server. The MacPorts installer works on every macOS version MacPorts supports, including macOS 26 and 27. In the security checklist, websites still served by Apple’s PHP are a failing item: it has had no fixes since 2019 and runs inside Apache as mod_php, the setup most exposed to remote-code flaws.

WarningA fixed file keeps its original beside it as .bak-fsmodernize-<date>, and is written only when it passes PHP’s syntax check on the new PHP (and on Apple’s PHP too, if it passed there before). A syntax check can’t prove a page behaves the same, so run the health check afterwards and look at the pages you care about.

4.6Sites and virtual hosts

The Websites list in the Apache pane is where you manage virtual hosts. Each row shows the site’s name, the bind address and the port (for example :8080), and a Running toggle for its live status. The buttons let you Add Site…, edit, duplicate, disable, Push to Server… (copy a vhost to a linked server), and open the site in a browser. Import Sites… and Copy from… pull existing vhosts in from MAMP, XAMPP, Apple’s Server.app or another Apache, bound to localhost by default.

Adding or editing a site, you set the essentials a vhost needs: its ServerName (the domain), the document root (Choose… a folder), and the bind address and port. Enable the site and it appears in the list with a live status dot; FrontierStack writes the vhost into a .conf file under the managed tree, validates, and reloads. To create the vhost, certificate and a Cloudflare DNS record together, use New Site + DNS… — the one-flow wizard described in Chapter 7.

screenshot to be added
Figure 4.1. A virtual host’s settings: ServerName, document root, bind address and port, with TLS and PHP options.Capture: open the Apache pane, select a site in the Websites list, and show its settings editor with ServerName and document root filled in
TipBind a site to 127.0.0.1 while you develop and it is reachable only from your Mac — the safest default for work in progress. Move the bind address to 0.0.0.0 or a LAN IP only when you genuinely want other machines to reach it.

4.7TLS certificates for sites

The Certificates pane issues and manages the certificates that put the padlock on your sites. It offers three paths, suited to different needs:

MethodUse it for
mkcert (Get Certificate (mkcert))Trusted local HTTPS. mkcert installs a local certificate authority your Mac trusts, so https://myapp.test works with no browser warning — ideal for development. Install mkcert sets it up first.
Let’s Encrypt (ACME)Public, browser-trusted certificates for real domains, via acme.sh or certbot. Issue by webroot (the domain already serves HTTP) or by DNS-01 via Cloudflare (no inbound HTTP needed). Renew All Now and a renew cron keep them current.
Create Self-Signed CertificateA quick certificate for internal or testing use where a browser warning is acceptable.

Once issued, Deploy to Apache wires the certificate into the site’s vhost. The Expiry Monitoring section watches your certificates (and any domain you add with Watch) and alerts you well before they lapse — the deeper hardening story, including HSTS and modern cipher policy, is in Chapter 10.

4.8Updating certificates, here and on linked servers

Every certificate in Installed Certificates shows who issued it and how many days it has left. Update… on its row renews it in place, offering only the methods that fit that certificate: Re-issue self-signed (the same private key by default, up to 397 days), Renew with certbot or acme.sh (so the client’s own deploy hooks run), Renew with mkcert, or Replace from files… for a certificate bought elsewhere. The previous files are kept beside the new ones as .bak, and you can reload the web server in the same step.

When you have linked servers, a Host picker appears at the top of the pane. Choose a server and the pane reads its certificates over SSH: Let’s Encrypt lineages, acme.sh, /etc/ssl and the nginx, Apache, Caddy and HAProxy certificate folders. Only certificates with their private key beside them are listed. Update and Create… work there too; changes run as root with the server’s saved sudo password, so without one the server is shown read-only.

Installed certificates are watched automatically, on this Mac and on linked servers, so Alerts warn before any of them expire with no setup. The bell on each row turns watching on or off, and certificates that were already expired when first seen are left out.

screenshot to be added
Figure 4.2. The Certificates pane showing a linked server's certificates with expiry and Update buttons.Capture: open Certificates, pick a linked Linux server in the Host picker, with one Let's Encrypt and one self-signed certificate listed
WarningA server certificate valid for more than 398 days is refused outright by Safari and Chrome, with no way to click through. FrontierStack therefore caps self-signed certificates at 397 days; for longer life, use ACME renewal instead.
Securitymkcert’s local CA is trusted only by the Mac it runs on, and Let’s Encrypt certificates are real public certificates — never use a self-signed certificate for a site the public will visit. The Cloudflare API token for DNS-01 issuance is stored as a CF_TOKEN vault secret and injected at run time; it is never sent to a cloud AI.

4.9The .htaccess editor

Per-directory Apache rules — rewrites, redirects, access control — live in .htaccess files, and FrontierStack gives them a dedicated editor with line numbers and a syntax sanity check. Open a site’s document-root .htaccess with Use Site Root, or point it at a custom path. Insert Recipe drops in common, correct snippets (a front-controller rewrite, a force-HTTPS block) so you start from working rules rather than memory, and the editor flags obvious problems before you save. Export PHP Router… turns .htaccess rewrite rules into a router file for a built-in PHP dev server — useful when you move a site to the Localhost pane.

4.10Nginx and reverse proxies

FrontierStack manages Nginx as an alternative web server or a reverse proxy in front of an app. When both are installed, the Domains view groups your sites by server — Apache virtual hosts and Nginx server blocks side by side — reading each Nginx server block’s listen port, root and TLS state. A reverse proxy is the standard pattern for fronting an application that speaks HTTP on a high port (a Node, .NET or Python service): Nginx terminates TLS on 443 and forwards to the app. Because Apache and Nginx both want 80/443 by default, use the Apache pane’s Ports section to move one off those ports if you run them together.

4.11Localhost, DNS and dev stacks

Three more panes complete the local picture:

  • Localhost — a manager for ad-hoc local dev servers. Add a New Local Server, pick a Runtime (PHP, Python/Django, Node/Vite, or a private Apache, Nginx or Caddy…) and folder, set a port and an optional ServerName, and Start it — with per-server Environment Globals and a .test resolver so myapp.test resolves locally. A Free Port helper and a stop whatever is holding localhost action clear the usual conflicts. Tick Also serve on Tailscale to reach a server from your other Tailscale devices at this Mac’s tailnet address on the same port — the server still listens on localhost only and FrontierStack forwards tailnet connections to it, so the LAN can’t reach it. For a Django server, Allow Tailscale Host… adds the tailnet address to the project’s ALLOWED_HOSTS after showing you the change (or hands you the line to add, when the setting is built from environment variables). The AI Administrator (and an agent over MCP) can start a folder the same way with debug_share action serve; the reply names the localhost host and port and, when asked, the Tailscale URL, so the agent can report where the site is running.
  • DNS — local name resolution and authoritative hosting. Run dnsmasq, unbound or nsd; import and export zone files; and flush the resolver when records change so the Mac stops serving a stale answer.
  • LAMP / DevStacks — one-click stacks. The LAMP pane offers presets (Choose a Setup) that install and start a matched set of components together (Install & Start, Start All, Stop All); DevStacks detects the framework of a project folder and shows the right commands and npm scripts to run it.

An Localhost overview shows every local server you have running, side by side, so you can run many sites at once without a wall of Terminal windows to babysit.

4.12Putting a site online, and handing it to an agent

Every local server has an Internet access box in its detail. Pick Cloudflare hostname and type a name on one of your zones (say demo.example.com), and FrontierStack adds the route and the DNS record and runs cloudflared as a system service, so the address stays up when the app is closed and after a reboot. The first site asks once for your admin password. Later sites share the same tunnel, each on its own hostname. A temporary link (trycloudflare.com) and Tailscale Funnel are the other choices. Vite and Django normally refuse hostnames they don’t know, so Cloudflare routes hand them localhost instead and they work unchanged.

The same globe button sits on Apache ▸ Websites rows (the tunnel asks Apache for the site by its ServerName) and on catalogue services, Docker containers, Vagrant boxes and Spin apps.

Hosting Preferences… (in the Localhost pane, and under Settings ▸ Websites & Hosting) says where your new sites belong. Choose this Mac, an Apache site, one of your servers, here.now, Hostinger, Vercel or ChatGPT Sites, and if you like a different place per kind of site. It also holds the web server new sites run on — Apache, Nginx, Caddy, or Ask each time — the domain new sites are named under, the folder they’re created in, who builds them, and the design skills (folders holding a SKILL.md) the builder should follow.

Then ask the AI Administrator for a site (“a one-page site for the bakery, warm colours, opening hours and a map”). Unless you said, or set one in Hosting Preferences, it first asks which web server the site should run on — Apache, Nginx, Caddy or Other (you name it). A static or PHP site is then served on this Mac by a private instance of that server; another server is noted for the builder and previewed with the built-in one. In one step it then creates the folder, writes the .env with the site’s settings (never passwords), a BRIEF.md, rules for the builder in AGENTS.md and your design skills in .claude/skills, starts the server, gives it its public address and makes the first git commit. It then builds the pages itself, or hands the job to Claude Code or Codex running in an isolated Sandcastle container; their files are copied back into the folder when they finish, and you get a notification. An outside agent connected over MCP can ask for the same set-up and build in the folder it’s given.

NoteNothing secret goes into the folder. If the site needs a key, the builder reads it from an environment variable, and you keep the value in FrontierStack’s Secrets.
The same tools the AI uses
Everything in this chapter is also available to the AI Administrator (Chapter 13) and to outside AI tools over MCP (Chapter 14) through the same guarded actions: vhost_create makes a virtual host, reload_webserver tests and gracefully reloads Apache or Nginx, and issue_certificate obtains a Let’s Encrypt certificate. They are mutating tools, so each shows an approval card and requires changes to be enabled — the AI does exactly what you would do in these panes, and nothing it has not been allowed to.

FrontierStack User Manual · Version 1.0.0 · Chapter 4