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 infohttpd -v

Start, Stop & Restart

All apachectl commands require sudo because the built-in Apache binds to port 80, which needs root.

// Core Service Commands

Terminal — apachectl
# 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

Terminal
# 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)

Terminal — launchctl
sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist

// Disable Auto-Start

Terminal — launchctl
sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist

// Check Load Status

Terminal
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

Terminal
# 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:

httpd.conf
# Default (requires sudo to bind):
Listen 80

# Change to port 8080 (no sudo needed to start):
Listen 8080

// Set Server Name

httpd.conf
# Uncomment and set (suppresses the ServerName warning):
ServerName localhost:80

// Always Test Config After Editing

Terminal
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

httpd.conf — find and replace both lines
# 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:

httpd.conf — Directory block
<Directory "/Users/YOUR_USERNAME/Sites">
    Options      Indexes FollowSymLinks MultiViews
    AllowOverride All
    Require      all granted
</Directory>

// Create the Sites Folder & a Test Page

Terminal
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

httpd.conf — uncomment to enable
# 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

Terminal
# 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

httpd.conf — uncomment both lines
# 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

Terminal
sudo nano /etc/apache2/extra/httpd-userdir.conf
httpd-userdir.conf — uncomment this line
Include /private/etc/apache2/users/*.conf

// Step 3 — Create Your User Config

Terminal — replace YOUR_USERNAME
sudo nano /etc/apache2/users/YOUR_USERNAME.conf
/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

Terminal
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

httpd.conf — uncomment
Include /private/etc/apache2/extra/httpd-vhosts.conf

// Step 2 — Edit httpd-vhosts.conf

Terminal
sudo nano /etc/apache2/extra/httpd-vhosts.conf
httpd-vhosts.conf — example config
# 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

Terminal
sudo nano /etc/hosts

# Add at the bottom of the file:
127.0.0.1    myapp.test

// Step 4 — Flush DNS Cache & Restart

Terminal
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
sudo apachectl graceful

# Now visit: http://myapp.test

Logs & Diagnostics

// Real-Time Log Tailing

Terminal
# 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

Terminal
# 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.