herd-community icon indicating copy to clipboard operation
herd-community copied to clipboard

[Bug]: Laravel Herd using wrong user group in php-fpm config

Open carnevalle opened this issue 2 months ago • 1 comments

Platform

macOS

Operating system version

MacOS Tahoe 26.0.1

System architecture

Intel (x86)

Herd Version

1.22.3

PHP Version

No response

Bug description

By default, PHP-FPM assumes that the current macOS user belongs to the system group called staff. However, in some environments — especially managed or MDM-enrolled Macs — users are not part of the staff group. This causes 502 Bad Gateway errors in Nginx because PHP-FPM sockets can’t be accessed by the running user.

You can manually fix this by editing the PHP-FPM config for each PHP version as described here beyondcode/herd-community#10 (comment)

The problem is that Herd regenerates these config files every time you switch PHP versions, which means the manual changes are lost and have to be redone.

It would be great if Laravel Herd handled this automatically — it’s a small issue but a major headache for affected users.

Until that’s built in, here’s a simple workaround (courtesy of ChatGPT 😄) that automatically patches the PHP-FPM configs whenever Herd regenerates them.

🧰 Herd FPM Admin Patch — Fix PHP-FPM Group Issues Automatically on macOS

📖 Overview

This small utility fixes a recurring problem with Laravel Herd where PHP-FPM sockets are created with the wrong group permissions, resulting in 502 Bad Gateway errors when switching PHP versions.

It installs two simple components:

  1. A Bash script (herd-fpm-admin-patch) — fixes group permissions in Herd PHP-FPM config files.
  2. A LaunchAgent — automatically runs the patch every time Herd regenerates its config.

After installation, your setup will self-heal whenever Herd changes PHP versions — no more manual edits.


🧠 The problem

When you switch PHP versions in Herd, it regenerates FPM pool configs such as:

~/Library/Application Support/Herd/config/fpm/8.4-fpm.conf

These contain:

group = staff
listen.group = staff
listen.mode = 0660

On many macOS setups — especially managed or MDM-enrolled Macs — your user account is not in the staff group.
When this happens, PHP-FPM fails to create its socket, and Nginx returns:

502 Bad Gateway
connect() to unix:/Users/.../herd84.sock failed (61: Connection refused)

💡 What this fix does

The patch ensures all Herd PHP-FPM configs use a valid group your user belongs to (e.g., admin).

Specifically, it:

  • Changes
    group = staff
    listen.group = staff
    
    group = admin
    listen.group = admin
    
  • Keeps
    listen.mode = 0660
    
  • Restarts Herd so changes take effect.

It’s safe, idempotent, and automatic.


🛠️ How to install

Copy and paste the following command block into your terminal:

# 1️⃣ Create the patch script
sudo tee /usr/local/bin/herd-fpm-admin-patch >/dev/null <<'SH'
#!/bin/sh
# herd-fpm-admin-patch (macOS)
# Patches Herd PHP-FPM pool files to use a specific socket group & mode, then restarts Herd.
#
# Env overrides:
#   HERD_GROUP=admin        # which group should own the FPM socket
#   HERD_MODE=0660          # socket mode
#
# Usage:
#   HERD_GROUP=admin HERD_MODE=0660 sh herd-fpm-admin-patch
#
# Description:
# - Scans all Herd PHP-FPM pool config files (e.g., 8.3-fpm.conf, 8.4-fpm.conf)
# - Replaces "group" and "listen.group" with HERD_GROUP
# - Ensures "listen.mode" matches HERD_MODE
# - Restarts Herd after applying changes
#
# Works around an issue where Herd sets group=staff by default, breaking sockets
# for users who aren’t in the staff group.
set -eu

HERD_GROUP="${HERD_GROUP:-admin}"
HERD_MODE="${HERD_MODE:-0660}"
HERD_BIN="$HOME/Library/Application Support/Herd/bin/herd"

echo "Scanning for FPM pool files…"
LIST="$(mktemp)"
find "$HOME/Library/Application Support/Herd" "/Library/Application Support/Herd"   -maxdepth 6 -type f -name "*fpm*.conf" 2>/dev/null | sort -u > "$LIST" || true

[ -s "$LIST" ] || { echo "No *fpm*.conf files found."; rm -f "$LIST"; exit 0; }

CHANGED=0
while IFS= read -r f; do
  [ -f "$f" ] || continue
  echo "Checking: $f"
  tmp="${f}.tmp.$$"

  /usr/bin/awk -v G="$HERD_GROUP" -v M="$HERD_MODE" '
    BEGIN { g=0; lg=0; lm=0 }
    /^[[:space:]]*group[[:space:]]*=/         { print "group = " G; g=1; next }
    /^[[:space:]]*listen\.group[[:space:]]*=/ { print "listen.group = " G; lg=1; next }
    /^[[:space:]]*listen\.mode[[:space:]]*=/  { print "listen.mode = " M; lm=1; next }
    { print }
    END {
      if (!g)  print "group = " G;
      if (!lg) print "listen.group = " G;
      if (!lm) print "listen.mode = " M;
    }' "$f" > "$tmp"

  if ! cmp -s "$f" "$tmp"; then
    [ -w "$f" ] && mv "$tmp" "$f" || { echo "  (not writable; using sudo)"; sudo mv "$tmp" "$f"; }
    echo "  → Patched"
    CHANGED=1
  else
    rm -f "$tmp"
    echo "  (no changes)"
  fi
done < "$LIST"
rm -f "$LIST"

if [ "$CHANGED" -eq 1 ]; then
  echo "Changes applied. Restarting Herd services…"
  if [ -x "$HERD_BIN" ]; then
    "$HERD_BIN" stop && "$HERD_BIN" start || echo "Patched configs; restart via the Herd app."
  else
    echo "Herd CLI not found at: $HERD_BIN"
    open -g -a Herd || true
  fi
else
  echo "No changes needed."
fi
SH
sudo chmod +x /usr/local/bin/herd-fpm-admin-patch

# 2️⃣ Create a LaunchAgent that auto-runs when Herd changes configs
mkdir -p "$HOME/Library/Logs" "$HOME/Library/LaunchAgents"

cat > "$HOME/Library/LaunchAgents/com.herd.fpm-admin-patch.plist" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.herd.fpm-admin-patch</string>

  <key>ProgramArguments</key>
  <array>
    <string>/bin/sh</string>
    <string>-lc</string>
    <string>/usr/local/bin/herd-fpm-admin-patch</string>
  </array>

  <key>EnvironmentVariables</key>
  <dict>
    <key>PATH</key>
    <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
  </dict>

  <key>RunAtLoad</key>
  <true/>

  <key>WatchPaths</key>
  <array>
    <string>$HOME/Library/Application Support/Herd/config/fpm</string>
    <string>$HOME/Library/Application Support/Herd/fpm</string>
  </array>

  <key>StandardOutPath</key>
  <string>$HOME/Library/Logs/herd-fpm-admin-patch.out</string>
  <key>StandardErrorPath</key>
  <string>$HOME/Library/Logs/herd-fpm-admin-patch.err</string>
</dict>
</plist>
PLIST

launchctl unload "$HOME/Library/LaunchAgents/com.herd.fpm-admin-patch.plist" 2>/dev/null || true
launchctl load "$HOME/Library/LaunchAgents/com.herd.fpm-admin-patch.plist"

echo "✅ Installed herd-fpm-admin-patch. It will now auto-fix FPM configs whenever Herd rewrites them."

🧾 Verify the installation

Run:

launchctl list | grep herd-fpm

You should see:

com.herd.fpm-admin-patch

Check logs:

tail -n 20 ~/Library/Logs/herd-fpm-admin-patch.out

🧹 To uninstall

launchctl unload ~/Library/LaunchAgents/com.herd.fpm-admin-patch.plist
rm -f ~/Library/LaunchAgents/com.herd.fpm-admin-patch.plist
sudo rm -f /usr/local/bin/herd-fpm-admin-patch

💡 Recommendations for Herd maintainers

  1. Detect if the user belongs to staff before setting group = staff.
  2. Default to the user’s primary group if not.
  3. Add a configurable override (e.g. “Preferred FPM Group”) in settings.
  4. Introduce herd restart --all to restart all PHP-FPM pools.

✅ Result

After installation:

  • No more 502 Bad Gateway errors after PHP version changes.
  • PHP-FPM sockets always use the correct group (admin).
  • Fully automatic — patches itself whenever Herd regenerates configs.

Steps to reproduce

No response

Relevant log output


carnevalle avatar Oct 20 '25 12:10 carnevalle

I guess the group (admin) is not static and depends on your specific setup. I'll have to see how we can safely test this once we make adjustments to the group detection.

mpociot avatar Oct 30 '25 08:10 mpociot