Built-in macOS Apache
Management & Configuration
What is the Built-in Apache?
macOS ships with Apache HTTP Server pre-installed as a system service. It is not enabled by default on modern macOS (Ventura, Sonoma, Sequoia) — Apple removed the GUI toggle from System Preferences — but the binaries and config files are fully intact and manageable from Terminal.
The system Apache is intentionally limited on modern macOS due to System Integrity Protection (SIP). Many system paths under /System/ are read-only. All config lives in /etc/apache2/, which you can edit with sudo.
The built-in Apache binary is at /usr/sbin/httpd and is managed via /usr/sbin/apachectl. All commands require sudo.
Key File Paths
| Purpose | Path |
|---|---|
| Control binary | /usr/sbin/apachectl |
| Apache daemon | /usr/sbin/httpd |
| Main config file | /etc/apache2/httpd.conf |
| Extra configs directory | /etc/apache2/extra/ |
| Virtual hosts config | /etc/apache2/extra/httpd-vhosts.conf |
| Per-user sites config | /etc/apache2/extra/httpd-userdir.conf |
| Default document root | /Library/WebServer/Documents/ |
| Per-user document root | ~/Sites/ |
| Error log | /private/var/log/apache2/error_log |
| Access log | /private/var/log/apache2/access_log |
| LaunchDaemon plist | /System/Library/LaunchDaemons/org.apache.httpd.plist |
| Apache version info | httpd -v |
Start, Stop & Restart
All apachectl commands require sudo because the built-in Apache binds to port 80, which needs root.
// Core Service Commands
# Start Apache sudo apachectl start # Stop Apache sudo apachectl stop # Restart (full stop + start) sudo apachectl restart # Graceful restart — reloads config without dropping connections sudo apachectl graceful # Check syntax of httpd.conf before restarting sudo apachectl configtest # Print full status sudo apachectl status
// Check if Apache is Running
# Check if httpd process is alive ps aux | grep httpd # Check if port 80 is listening sudo lsof -i :80 # Then open browser and visit: http://localhost
If Apache is running correctly, http://localhost will show the default page — usually a file from /Library/WebServer/Documents/.
Auto-Start Apache at Boot
The built-in Apache is controlled by launchctl and a plist in the LaunchDaemons directory. Use these commands to enable or disable it persisting across reboots.
// Enable Auto-Start (load at boot)
sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist
// Disable Auto-Start
sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist
// Check Load Status
sudo launchctl list | grep apache # If running, you'll see a PID in the first column
The plist at /System/Library/LaunchDaemons/ is protected by SIP. You can load and unload it, but you cannot edit or replace it without disabling SIP (not recommended).
Editing httpd.conf
The main configuration file is /etc/apache2/httpd.conf. Always back it up before editing, then test the syntax before restarting.
// Back Up & Open
# Back up the original config sudo cp /etc/apache2/httpd.conf /etc/apache2/httpd.conf.bak # Edit with nano sudo nano /etc/apache2/httpd.conf # Or with vim sudo vim /etc/apache2/httpd.conf # Or open directory in VS Code (edit file with sudo separately) code /etc/apache2/
VS Code and other GUI editors typically cannot save directly to /etc/ without sudo. Use nano or vim with sudo, or use sudo tee to write from VS Code's terminal.
// Change the Server Port
Find the Listen directive and change it from port 80 to any open port:
# Default (requires sudo to bind): Listen 80 # Change to port 8080 (no sudo needed to start): Listen 8080
// Set Server Name
# Uncomment and set (suppresses the ServerName warning): ServerName localhost:80
// Always Test Config After Editing
sudo apachectl configtest # If "Syntax OK" — safe to restart sudo apachectl graceful
Document Root
The default document root is /Library/WebServer/Documents/. You can change it to any directory — commonly your home Sites folder.
// Change Document Root in httpd.conf
# Replace with your username: DocumentRoot "/Users/YOUR_USERNAME/Sites" <Directory "/Users/YOUR_USERNAME/Sites">
// Set Directory Permissions
Inside the <Directory> block that matches your document root, set:
<Directory "/Users/YOUR_USERNAME/Sites"> Options Indexes FollowSymLinks MultiViews AllowOverride All Require all granted </Directory>
// Create the Sites Folder & a Test Page
mkdir -p ~/Sites echo "<h1>macOS Built-in Apache — Working!</h1>" > ~/Sites/index.html
Enabling Modules
Modules are enabled by uncommenting LoadModule lines in httpd.conf. Remove the leading # to activate a module.
// Commonly Needed Modules
# URL rewriting (.htaccess redirects) LoadModule rewrite_module libexec/apache2/mod_rewrite.so # SSL / HTTPS support LoadModule ssl_module libexec/apache2/mod_ssl.so # Per-user ~/Sites directories LoadModule userdir_module libexec/apache2/mod_userdir.so # CGI script support LoadModule cgi_module libexec/apache2/mod_cgi.so # Virtual hosts (usually already enabled) LoadModule vhost_alias_module libexec/apache2/mod_vhost_alias.so # PHP (macOS removed bundled PHP in Monterey+) # Install PHP via Homebrew first, then: LoadModule php_module /opt/homebrew/opt/php/lib/httpd/modules/libphp.so
// List All Available Modules
# List compiled-in + loaded modules httpd -M # List available .so files on disk ls /usr/libexec/apache2/
macOS Monterey and later removed the bundled PHP. Use brew install php for PHP support, then load the Homebrew PHP module as shown above.
Per-User Sites (~/Sites)
macOS supports serving from each user's ~/Sites folder at http://localhost/~username/. This requires enabling both the module and the include in httpd.conf.
// Step 1 — Enable in httpd.conf
# 1. Uncomment the userdir module: LoadModule userdir_module libexec/apache2/mod_userdir.so # 2. Uncomment the include: Include /private/etc/apache2/extra/httpd-userdir.conf
// Step 2 — Configure httpd-userdir.conf
sudo nano /etc/apache2/extra/httpd-userdir.conf
Include /private/etc/apache2/users/*.conf
// Step 3 — Create Your User Config
sudo nano /etc/apache2/users/YOUR_USERNAME.conf
<Directory "/Users/YOUR_USERNAME/Sites/"> AddLanguage en .en AddHandler cgi-script .cgi .pl Options Indexes MultiViews FollowSymLinks AllowOverride All Require all granted </Directory>
// Step 4 — Create Sites & Restart
mkdir -p ~/Sites echo "<h1>Hello from ~/Sites</h1>" > ~/Sites/index.html sudo apachectl graceful # Visit in browser: http://localhost/~YOUR_USERNAME/
Virtual Hosts
Virtual Hosts allow multiple local domain names to resolve to different directories on the same machine — e.g., myapp.test pointing to a specific project folder.
// Step 1 — Enable Virtual Hosts in httpd.conf
Include /private/etc/apache2/extra/httpd-vhosts.conf
// Step 2 — Edit httpd-vhosts.conf
sudo nano /etc/apache2/extra/httpd-vhosts.conf
# Always keep a default catch-all first <VirtualHost *:80> ServerName localhost DocumentRoot "/Library/WebServer/Documents" </VirtualHost> # Your custom local project <VirtualHost *:80> ServerName myapp.test DocumentRoot "/Users/YOUR_USERNAME/Sites/myapp" ErrorLog "/private/var/log/apache2/myapp-error.log" CustomLog "/private/var/log/apache2/myapp-access.log" combined <Directory "/Users/YOUR_USERNAME/Sites/myapp"> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>
// Step 3 — Add to /etc/hosts
sudo nano /etc/hosts # Add at the bottom of the file: 127.0.0.1 myapp.test
// Step 4 — Flush DNS Cache & Restart
sudo dscacheutil -flushcache sudo killall -HUP mDNSResponder sudo apachectl graceful # Now visit: http://myapp.test
Logs & Diagnostics
// Real-Time Log Tailing
# Watch error log live tail -f /private/var/log/apache2/error_log # Watch access log live tail -f /private/var/log/apache2/access_log # View last 50 errors tail -n 50 /private/var/log/apache2/error_log
// Useful Diagnostic Commands
# Check config syntax sudo apachectl configtest # View Apache version and compile settings httpd -V # List all loaded modules httpd -M # Print the full parsed config (all includes merged) sudo httpd -t -D DUMP_CONFIG 2>&1 # Force kill all httpd processes sudo pkill -9 httpd # Restore original config from backup sudo cp /etc/apache2/httpd.conf.bak /etc/apache2/httpd.conf
SIP Restrictions
System Integrity Protection (SIP) on Apple Silicon Macs prevents modification of system-owned files. Here's what you can and cannot do:
| Action | Allowed? |
|---|---|
Edit /etc/apache2/httpd.conf | ✅ Yes — with sudo |
Edit /etc/apache2/extra/*.conf | ✅ Yes — with sudo |
Edit /etc/hosts | ✅ Yes — with sudo |
| Edit LaunchDaemon plist | 🔒 No — SIP protected |
Replace /usr/sbin/httpd | 🔒 No — SIP protected |
Write to /Library/WebServer/Documents/ | ✅ Yes — with sudo |
Write to ~/Sites/ | ✅ Yes — no sudo needed |
If you need features blocked by SIP — or a newer Apache version — use the Homebrew-installed Apache (brew install httpd) which installs entirely to /opt/homebrew/ and is fully under your control.