
Understanding Linux File Permissions on Your VPS
Linux VPS file permission management controls who can read, write, or execute files on your server. A single misconfigured permission can expose sensitive data or break your entire hosting setup.
Traditional Unix permissions use a three-tier system: owner, group, and others. Each tier gets three permission types: read (4), write (2), and execute (1). These combine into familiar octal values like 755 or 644.
The ls -la command shows permissions in symbolic format:
-rw-r--r-- 1 www-data www-data 1024 Jan 15 10:30 index.html
drwxr-xr-x 2 root root 4096 Jan 15 09:15 logs/
The first character indicates file type (- for regular files, d for directories). The next nine characters show owner, group, and other permissions.
Essential chmod Commands for Web Hosting
The chmod command modifies file permissions using either octal notation or symbolic notation. For VPS administrators, certain patterns appear constantly.
Set standard web file permissions:
# Files readable by web server
chmod 644 /var/www/html/*.html
chmod 644 /var/www/html/*.css
chmod 644 /var/www/html/*.js
# Directories accessible by web server
chmod 755 /var/www/html/
chmod 755 /var/www/html/assets/
chmod 755 /var/www/html/images/
WordPress requires specific permissions to function correctly:
# WordPress files
chmod 644 wp-config.php
chmod 644 .htaccess
# WordPress directories
chmod 755 wp-content/
chmod 755 wp-content/themes/
chmod 755 wp-content/plugins/
# Upload directory needs write access
chmod 775 wp-content/uploads/
SSH keys demand strict permissions or they'll be rejected:
# Private keys must be owner-only readable
chmod 600 ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_ed25519
# Public keys can be group-readable
chmod 644 ~/.ssh/id_rsa.pub
chmod 644 ~/.ssh/authorized_keys
# SSH directory itself
chmod 700 ~/.ssh/
Symbolic notation offers more flexibility for complex changes:
# Add execute permission for owner
chmod u+x script.sh
# Remove write permission from group and others
chmod go-w sensitive-config.txt
# Set read-only for everyone
chmod a-w readonly-file.txt
Using chown for Ownership Management
The chown command changes file ownership. Web servers require specific ownership patterns to serve files correctly while maintaining security.
Change ownership to web server user:
# Apache on Ubuntu/Debian
chown www-data:www-data /var/www/html/ -R
# Nginx on most distributions
chown nginx:nginx /usr/share/nginx/html/ -R
# Generic web directory
chown $USER:www-data /var/www/mysite/ -R
For shared hosting or multiple sites, set group ownership to allow specific access:
# Create web group
sudo groupadd webdevs
# Add users to web group
sudo usermod -a -G webdevs alice
sudo usermod -a -G webdevs bob
# Set group ownership
chown :webdevs /var/www/client-sites/ -R
Log files need careful ownership management:
# Application logs writable by app user
chown myapp:myapp /var/log/myapp/ -R
# System logs readable by admin group
chown root:adm /var/log/auth.log
chown root:adm /var/log/syslog
Database files require specific ownership for security:
# MySQL data directory
chown mysql:mysql /var/lib/mysql/ -R
# PostgreSQL data directory
chown postgres:postgres /var/lib/postgresql/ -R
Advanced ACLs for Complex Permission Scenarios
Access Control Lists (ACLs) extend beyond traditional Unix permissions. They provide granular control over specific users and groups without changing base ownership.
Install ACL support on your VPS:
# Ubuntu/Debian
sudo apt install acl
# RHEL/AlmaLinux/Rocky
sudo dnf install acl
Most modern filesystems support ACLs by default. Verify with mount | grep acl or check /etc/fstab for the acl option.
Grant specific user access to a directory:
# Allow 'developer' read/write access to logs
setfacl -m u:developer:rw /var/log/application/
# Allow 'backup' read access to entire web directory
setfacl -m u:backup:r-x /var/www/ -R
# Grant group 'editors' write access to content
setfacl -m g:editors:rwx /var/www/html/content/
View current ACLs with getfacl:
getfacl /var/www/html/uploads/
# file: var/www/html/uploads/
# owner: www-data
# group: www-data
user::rwx
user:developer:rw-
group::r-x
mask::rwx
other::r-x
Remove ACL entries when access is no longer needed:
# Remove specific user ACL
setfacl -x u:developer /var/log/application/
# Remove all ACLs from file
setfacl -b /var/www/html/sensitive-file.txt
ACLs prove particularly useful for VPS hosting environments. Multiple developers can get different access levels to the same project directories.
Security-First Permissions for Web Directories
Web hosting security starts with proper directory permissions. Different content types need different access patterns to balance functionality with protection.
Public web content should follow these patterns:
# HTML, CSS, JS files - world readable
find /var/www/html/ -type f -name "*.html" -exec chmod 644 {} \;
find /var/www/html/ -type f -name "*.css" -exec chmod 644 {} \;
find /var/www/html/ -type f -name "*.js" -exec chmod 644 {} \;
# Images - world readable
find /var/www/html/ -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.gif" \) -exec chmod 644 {} \;
Configuration files need stricter permissions:
# Web server configs - owner readable only
chmod 600 /etc/nginx/sites-available/mysite.conf
chmod 600 /etc/apache2/sites-available/mysite.conf
# Database configs - owner readable only
chmod 600 /var/www/html/wp-config.php
chmod 600 /var/www/html/.env
Upload directories need careful handling:
# Create upload directory with proper permissions
mkdir -p /var/www/html/uploads/
chown www-data:www-data /var/www/html/uploads/
chmod 755 /var/www/html/uploads/
Prevent script execution in uploads:
echo "Options -ExecCGI" > /var/www/html/uploads/.htaccess
echo "AddHandler cgi-script .php .pl .py .jsp .asp .sh .cgi" >> /var/www/html/uploads/.htaccess
For WordPress multisite or complex CMS setups, consider our managed WordPress hosting. It handles these permission complexities automatically.
Troubleshooting Common Permission Problems
Permission errors often manifest as HTTP 403 Forbidden errors or application functionality breaking unexpectedly. Most issues stem from overly restrictive or overly permissive settings.
Debug permission issues systematically:
# Check web server error logs
tail -f /var/log/nginx/error.log
tail -f /var/log/apache2/error.log
# Verify file permissions
ls -la /var/www/html/problematic-file.php
# Check directory permissions up the chain
namei -om /var/www/html/subdirectory/file.php
The namei command traces permissions from root to your target file. This reveals where access breaks down.
Fix common WordPress permission problems:
# Reset WordPress permissions
find /var/www/html/ -type d -exec chmod 755 {} \;
find /var/www/html/ -type f -exec chmod 644 {} \;
# wp-config.php needs special handling
chmod 600 /var/www/html/wp-config.php
# Uploads directory needs write access
chmod 775 /var/www/html/wp-content/uploads/
SSH permission problems prevent key-based authentication:
# Fix SSH directory permissions
chmod 700 ~/.ssh/
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/id_*.pub
Database permission issues often show in application logs:
# Check MySQL data directory ownership
ls -la /var/lib/mysql/
# Fix if needed
chown mysql:mysql /var/lib/mysql/ -R
# Restart database service
sudo systemctl restart mysql
For detailed help, see our guide on troubleshooting VPS hosting issues.
Automating Permission Management
Manual permission management becomes unwieldy with multiple sites or frequent deployments. Automation ensures consistency and reduces human error.
Create a basic permission reset script:
#!/bin/bash
# reset-web-permissions.sh
WEB_ROOT="/var/www/html"
WEB_USER="www-data"
WEB_GROUP="www-data"
# Set ownership
chown -R $WEB_USER:$WEB_GROUP $WEB_ROOT
# Set directory permissions
find $WEB_ROOT -type d -exec chmod 755 {} \;
# Set file permissions
find $WEB_ROOT -type f -exec chmod 644 {} \;
# Special cases
chmod 600 $WEB_ROOT/wp-config.php 2>/dev/null
chmod 775 $WEB_ROOT/wp-content/uploads 2>/dev/null
echo "Permissions reset complete"
Make the script executable and run it:
chmod +x reset-web-permissions.sh
sudo ./reset-web-permissions.sh
For deployment automation, integrate permission setting into your CI/CD pipeline:
# In deployment script
git pull origin main
composer install --no-dev --optimize-autoloader
# Reset permissions after deployment
chown -R www-data:www-data /var/www/myapp/
find /var/www/myapp/ -type d -exec chmod 755 {} \;
find /var/www/myapp/ -type f -exec chmod 644 {} \;
# Set storage writable
chmod -R 775 /var/www/myapp/storage/
chmod -R 775 /var/www/myapp/bootstrap/cache/
Use cron for regular permission audits:
# Add to crontab
0 2 * * 0 /usr/local/bin/audit-permissions.sh | mail -s "Weekly Permission Audit" admin@example.com
The audit script can check for common permission problems. It alerts you to potential security issues before they cause problems.
Managing file permissions across multiple websites or complex hosting setups becomes time-consuming and error-prone. HostMyCode managed VPS hosting includes automated permission management, security hardening, and 24/7 monitoring. Focus on your applications rather than server administration.
Frequently Asked Questions
What file permissions should I use for WordPress?
WordPress directories should use 755 permissions, regular files should use 644, and wp-config.php should use 600. The wp-content/uploads directory needs 775 for file uploads to work properly.
Why does my SSH key authentication fail with correct permissions?
SSH is strict about permissions. Your ~/.ssh directory must be 700, private keys must be 600, and authorized_keys must be 600 or 644. Also check that your home directory isn't world-writable.
How do I give multiple users access to the same web directory?
Create a group for web developers, add users to that group, set group ownership on the directory, and use 775 permissions. Alternatively, use ACLs with setfacl for more granular control.
Should log files be readable by the web server?
Application logs should be writable by the application user but not readable by the web server unless specifically needed. System logs should be readable only by root and the adm group to prevent information disclosure.
What permissions do database files need?
MySQL data files should be owned by the mysql user with 660 permissions. PostgreSQL data should be owned by postgres with similar restrictions. Never make database files world-readable.