Run grim projects beside Laravel Herd
Herd and Traefik both want ports 80 and 443, and for a long time grim's answer was to stop Herd. Now the machine can be told that Herd is in front. Traefik moves to a loopback port, Herd proxies each project's names to it, and Herd's own certificate authority signs them.
Before you start
Herd's nginx listens on 127.0.0.1:80 and :443. grim's Traefik binds 0.0.0.0:80 and :443. They cannot both hold the ports, and grim used to win by running herd stop. This recipe is the other arrangement: Herd keeps the ports, and grim runs behind it.
Two things follow from that. Projects behind Herd are reachable at *.test only, because Herd appends .test to any proxy it writes; a project with a tls block of mode custom cannot run this way. And the mode belongs to the machine, not to a project: every project on the Mac goes through the one Traefik, so grim config holds the setting, not grim.json.
Check that Herd is what answers .test and that its tld is test:
$ herd tld
test
$ herd linksMySQL is unchanged. grim projects reach it on the host, and Herd's own services are not needed.
The ritual, in order
Tell the machine that Herd is in front
$ grim config set proxy.mode behind-herd proxy.mode = behind-herdThe port Traefik binds defaults to
8080on the loopback address. When something else holds it, pick another:grim config set proxy.port 8123.Set up Traefik behind Herd
$ grim setup Setting up local dev environment... Creating traefik-public network... OK Checking mkcert... installed Installing mkcert CA... OK SSL certs will be generated per-project on grim up Setting up Traefik... running (behind-herd, 127.0.0.1:8080) Setting up *.test DNS... already configured Local dev environment ready.Traefik now listens on
127.0.0.1:8080only, with no certificates. Herd is not touched. A Traefik that was already running on 80 and 443 is recreated on the new port, and the line says so.$ curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: nothing.test' http://127.0.0.1:8080/ 404The
404is Traefik's: it answers, and knows no project yet.Raise a project
In a project directory, or with a new one from
grim create-project:$ grim up ✓ Herd proxy shop.test → http://127.0.0.1:8080 (written) ✓ Herd proxy mail.shop.test → http://127.0.0.1:8080 (written) Starting: shop ✓ Checking Traefik ✓ Running docker compose up … ✓ Verifying Traefik on 127.0.0.1:8080 ✓ Herd serves https://shop.test (200)The first proxy on a machine asks for your password: Herd installs its certificate authority into the system keychain once. From then on the two proxies are checked on every
grim upand rewritten only when they are missing or point elsewhere. There is no mkcert certificate and no TLS chain check in this mode; Herd terminates TLS, and Vite's dev server reads Herd's certificate for the domain.Open
https://shop.testandhttps://mail.shop.test. Herd's other sites are still up.Put it away
grim downstops the containers and leaves the proxies: Herd answers502for the names until the nextgrim up. To forget the project on this machine, remove the proxies as well:$ grim down --purge ✓ Herd proxy shop.test removed ✓ Herd proxy mail.shop.test removed
What you have now
- Traefik on
127.0.0.1:8080, routing byHostheader, trusting Herd'sX-Forwarded-*headers. - Two Herd proxies per project,
<name>.testandmail.<name>.test, secured by Herd's authority. grim doctorshowsProxy mode ✓ behind-herd (127.0.0.1:8080)and, inside a project,Herd proxies ✓.- Herd's own sites, untouched.
To go back, grim config set proxy.mode traefik and grim setup --stop-herd: Traefik returns to 80 and 443 and Herd has to be stopped for that.
When it does not work
Herd answers 502
Traefik or the project is down. grim up in the project. grim doctor says which proxy is stale and where Traefik binds.
Nothing answers on shop.test at all
Herd's nginx is not listening. After grim had stopped it, herd start reports the services started and yet leaves nginx down; herd restart brings it back. lsof -nP -iTCP:443 -sTCP:LISTEN should show nginx-arm64 on 127.0.0.1:443.
The page is a 500
The request went through: Herd, Traefik and the project's nginx all answered, and the application failed. That is the same 500 you would get on port 8080 directly (curl -H 'Host: shop.test' http://127.0.0.1:8080/). Read grim logs app and storage/logs/laravel.log.
The browser does not trust shop.test
Herd's authority was not installed, usually because the password prompt was dismissed. herd secure shop asks again.
“… which behind-herd cannot serve”
The project has a tls block with a custom domain, or GRIM_LOCAL_DOMAIN in .env. Behind Herd only *.test is served. Remove the block or the key for this machine, or switch the machine back to proxy.mode traefik.
Running without Docker
Not this recipe. grim install --no-docker --no-composer writes a project without Docker files, and the rest is Herd as with any Laravel app: herd link, herd secure, composer install, php artisan migrate, php artisan horizon and php artisan schedule:work in their own terminals. grim up, artisan, composer, test, update and require need the Docker stack; build, deploy and remote:* do not.
Next recipe
Create a project
Answer two questions, let the install run, bring the stack up, sign in as the generated admin, run the suite once and give the first commit a remote.
Read itSpells used here
grim config
Read and write CLI settings
Read, set and remove the per-user settings grim keeps in ~/.grim/config.json.
grim setup
Prepare the machine
Put the shared pieces of local development in place, once per machine: the Traefik proxy, a trusted local certificate authority and .test name resolution.
grim up
Raise the stack
Start the project's containers and its Vite dev server, with a trusted certificate and a working address, and say where to open it.
grim down
Lower the stack
Stop the project's containers and its Vite server. Volumes stay unless you say otherwise.
grim doctor
Check your circle
Check every tool grim expects on this machine, and the project you are standing in, and say what to do about what is missing.