Resolving Apache HTTPD 403 Forbidden Errors for Symlinks and Aliases on macOS: Permission Requirements Explained


13 views

When configuring symlinks or aliases in Apache HTTPD on macOS, simply setting chmod 755 on the target directory isn't always sufficient. The error messages you're seeing:

[error] [client ::1] (13)Permission denied: access to /foo denied
Symbolic link not allowed or link target not accessible

indicate deeper permission issues in the directory hierarchy.

Apache's www user (typically _www on macOS) needs execute permissions on:

  • The target directory itself
  • Every parent directory in the path
  • The symlink if using that approach

For the Alias method to work:

# Fix permissions for the entire path
chmod 755 ~
chmod 755 ~/Documents
chmod 755 ~/Documents/foo
chmod 755 ~/Documents/foo/html

# Verify the permissions
ls -ld ~ ~/Documents ~/Documents/foo ~/Documents/foo/html

If using symlinks, ensure these Apache directives are set:

<Directory "/Library/WebServer/Documents">
    Options FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

And verify symlink permissions:

ln -s ~/Documents/foo/html /Library/WebServer/Documents/foo
chmod 755 /Library/WebServer/Documents/foo

If issues persist:

  1. Check Apache's user/group configuration:
    ps aux | grep httpd
    cat /etc/apache2/httpd.conf | grep User
  2. Verify directory ownership:
    sudo chown -R $(whoami):_www ~/Documents/foo
    chmod -R 775 ~/Documents/foo
  3. Check SELinux context (if applicable):
    ls -Z /Library/WebServer/Documents/foo

For more complex setups, consider:

# Virtual Host configuration
<VirtualHost *:80>
    DocumentRoot "/Users/someone/Documents/foo/html"
    ServerName foo.localhost
    <Directory "/Users/someone/Documents/foo/html">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Remember to add to /etc/hosts:

127.0.0.1 foo.localhost

When attempting to expose a user directory (like ~/Documents/foo/html) through Apache's Alias directive or symlinks, macOS presents unique permission hurdles. The key insight is that every parent directory in the path must be executable (searchable) by the _www user (Apache's default user on macOS).

# Verify current permissions
ls -ld ~/ ~/Documents/ ~/Documents/foo/ ~/Documents/foo/html/

# Apply recursive permissions (minimum)
chmod 755 ~/Documents
chmod -R 755 ~/Documents/foo/html

For the Alias approach, ensure your httpd.conf contains:

<VirtualHost *:80>
    ServerName localhost
    
    # Essential directives
    DocumentRoot "/Library/WebServer/Documents"
    <Directory "/Library/WebServer/Documents">
        Options +Indexes +FollowSymLinks +MultiViews
        AllowOverride All
        Require all granted
    </Directory>

    # Your custom alias
    Alias /foo "/Users/someone/Documents/foo/html"
    <Directory "/Users/someone/Documents/foo/html">
        Options +Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>

When using symlinks in /Library/WebServer/Documents:

# Create symlink properly
sudo ln -s ~/Documents/foo/html /Library/WebServer/Documents/foo

# Verify ownership
ls -l /Library/WebServer/Documents/foo
# Should show:
# lrwxr-xr-x  1 root  wheel  39B Jan 1 12:00 foo -> /Users/someone/Documents/foo/html
  1. Check Apache error log: tail -f /var/log/apache2/error_log
  2. Verify directory traversal: sudo -u _www ls /Users/someone/Documents/foo/html
  3. Test basic access: curl -I http://localhost/foo/

For newer macOS versions with stricter security:

# Check if SIP is interfering
csrutil status

# Temporary test (not recommended for production)
sudo chmod -R a+rx ~/Documents