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


3 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