When trying to serve content from a user's home directory in Ubuntu (like /home/username
), even with correct file permissions, you might encounter the frustrating 403 Forbidden error. Here's why this happens and how to properly configure it.
Ubuntu's home directories have a default permission of 750 (drwxr-x---), meaning:
$ ls -ld /home/ubuntu
drwxr-x--- 24 ubuntu ubuntu 4096 Aug 12 14:30 /home/ubuntu
This means:
- Owner (ubuntu) has rwx
- Group has r-x
- Others have --- (no access)
Even if your files have correct permissions, the parent directory's permissions matter just as much. Nginx needs execute permission on all parent directories to traverse the path.
Here's how to verify the complete path:
$ namei -l /home/ubuntu/public_html/index.html
f: /home/ubuntu/public_html/index.html
drwxr-xr-x root root /
drwxr-xr-x root root home
drwxr-x--- ubuntu ubuntu ubuntu
drwxr-xr-x ubuntu ubuntu public_html
-rw-r--r-- ubuntu ubuntu index.html
Here's the proper way to configure this:
# 1. Set directory permissions (add execute for group)
sudo chmod 751 /home/ubuntu
# 2. Make sure nginx user is in ubuntu group
sudo usermod -a -G ubuntu nginx
# 3. Update nginx configuration
server {
listen 80;
server_name localhost;
root /home/ubuntu/public_html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
If modifying home directory permissions makes you uncomfortable, consider using symbolic links:
# Create a directory outside home
sudo mkdir /var/www/ubuntu_site
sudo chown ubuntu:www-data /var/www/ubuntu_site
# Create symlink from home directory
ln -s /var/www/ubuntu_site /home/ubuntu/public_html
# Then point nginx to /var/www/ubuntu_site
On systems with SELinux (like CentOS/RHEL), you might need to adjust the security context:
# Check current context
ls -Z /home/ubuntu
# Change context if needed
chcon -R -t httpd_sys_content_t /home/ubuntu/public_html
After making changes:
- Check nginx error logs:
tail -f /var/log/nginx/error.log
- Verify configuration:
sudo nginx -t
- Reload nginx:
sudo systemctl reload nginx
When configuring Nginx to serve files from a user's home directory on Ubuntu, you might encounter a persistent 403 Forbidden error even with correct file permissions. Let's examine a real-world scenario that demonstrates this issue:
# Initial working config (serving from /home)
server {
root /home;
index index.html;
server_name localhost;
location / {
try_files $uri $uri/ /index.html;
}
}
The puzzling aspect is that identical permission settings work when serving from /home but fail when serving from /home/username. Consider these observations:
# File permissions (both cases)
-rw-r--r-- 1 nginx www-data 183 Aug 12 13:13 index.html
# Directory permissions
/home: drwxr-xr-x 3 root root 4096 Aug 12 12:00
/home/ubuntu: drwx------ 5 ubuntu ubuntu 4096 Aug 12 12:30
The critical difference lies in the execute (x) permission on parent directories. Nginx needs execute permission on all parent directories to traverse the path:
- /home has drwxr-xr-x (world-executable)
- /home/ubuntu has drwx------ (user-only)
Here's the complete fix with security considerations:
# 1. Set appropriate directory permissions
sudo chmod 711 /home/ubuntu
# 2. Verify Nginx can access the directory
sudo -u www-data ls -la /home/ubuntu/
# 3. Recommended config for home directory hosting
server {
root /home/ubuntu/public_html;
index index.html;
server_name localhost;
location / {
try_files $uri $uri/ =404;
# Additional security measures
autoindex off;
disable_symlinks on;
}
}
For production systems, consider these more secure alternatives:
# Option 1: Symlink from standard web root
sudo ln -s /home/ubuntu/public_html /var/www/ubuntu_site
# Option 2: User directory module (if available)
location ~ ^/~(.+?)(/.*)?$ {
alias /home/$1/public_html$2;
autoindex off;
}
- Verify SELinux/AppArmor isn't blocking access (check /var/log/audit/audit.log)
- Ensure parent directories have +x permission
- Confirm Nginx worker process user has proper group membership
- Check for encrypted home directories (ecryptfs)
- Test with simplified configuration to isolate variables