Automated Nginx User Directory Hosting: Dynamic Configuration for ~/www and Domain-Based Virtual Hosts


7 views

When managing multiple user accounts on a web server, there's often a need to:

  • Automatically configure user directories (like Apache's UserDir functionality)
  • Handle special username cases for domain hosting
  • Maintain these configurations during user creation/deletion

Here's a complete Bash script solution that hooks into adduser to achieve this:

#!/bin/bash
# File: /usr/local/bin/custom_adduser

# Create user with standard home directory
adduser "$@"

# Get the username (last argument)
USERNAME="${@: -1}"

# Nginx userdir configuration
NGINX_USERDIR="
location ~ ^/~(.+?)(/.*)?$ {
    alias /home/\$1/www\$2;
    index index.html index.htm;
    autoindex on;
}
"

# Check if username matches domain pattern (www.domain.com)
if [[ "$USERNAME" =~ ^www\..+$ ]]; then
    # Extract domain
    DOMAIN="${USERNAME#www.}"
    
    # Create nginx vhost config
    cat > /etc/nginx/conf.d/${USERNAME}.conf << EOF
server {
    listen 80;
    server_name ${DOMAIN} www.${DOMAIN};
    
    root /home/${USERNAME}/www;
    index index.html index.htm;
    
    location / {
        try_files \$uri \$uri/ =404;
    }
}
EOF
else
    # Add userdir config if not already present
    if ! grep -q "location ~ ^/~" /etc/nginx/nginx.conf; then
        sed -i "/http {/a ${NGINX_USERDIR}" /etc/nginx/nginx.conf
    fi
fi

# Create www directory and set permissions
mkdir -p /home/${USERNAME}/www
chown ${USERNAME}:${USERNAME} /home/${USERNAME}/www
chmod 755 /home/${USERNAME}/www

# Test and reload nginx
nginx -t && systemctl reload nginx

To make this work effectively:

  1. Save the script as /usr/local/bin/custom_adduser
  2. Make it executable: chmod +x /usr/local/bin/custom_adduser
  3. Create a symlink to override default adduser:
    ln -s /usr/local/bin/custom_adduser /usr/sbin/adduser
  4. Ensure proper SELinux/AppArmor permissions if applicable

When implementing automated web directory creation:

  • Set proper directory permissions (755 for directories, 644 for files)
  • Consider using chroot for user directories in production
  • Implement proper PHP-FPM pool isolation if running PHP applications
  • Add rate limiting to prevent abuse of user directories

For more sophisticated systems, consider using PAM hooks:

# /etc/pam.d/common-session
session optional pam_exec.so /usr/local/bin/userdir_setup.sh

Then create the setup script:

#!/bin/bash
# /usr/local/bin/userdir_setup.sh

if [ "$PAM_TYPE" = "open_session" ]; then
    USERNAME="$PAM_USER"
    # Add your nginx configuration logic here
fi
exit 0

If things don't work as expected:

  • Check nginx error logs: tail -f /var/log/nginx/error.log
  • Verify directory ownership: ls -la /home/USERNAME
  • Test nginx configuration: nginx -t
  • Ensure SELinux contexts are correct if using SELinux:
    chcon -R -t httpd_user_content_t /home/USERNAME/www

When managing web servers for multiple users, we often need to automatically configure Nginx to serve user directories (~/www) and handle custom domain mappings (like www.domain.com pointing to user's ~/www). This requires dynamic Nginx configuration during user creation.

We'll create a shell script that hooks into the adduser process to:

  1. Create standard ~/www directory for each user
  2. Generate proper Nginx configuration for user directory access
  3. Handle special username cases for domain mapping

Create /usr/local/bin/nginx-user-setup:

#!/bin/bash

USER=$1
HOME_DIR=$(getent passwd "$USER" | cut -d: -f6)

# Create www directory
mkdir -p "$HOME_DIR/www"
chown "$USER:$USER" "$HOME_DIR/www"

# Check for domain pattern in username
if [[ "$USER" =~ ^www\. ]]; then
    DOMAIN="${USER#www.}"
    NGINX_CONF="/etc/nginx/conf.d/${DOMAIN}.conf"
    
    cat << EOF > "$NGINX_CONF"
server {
    listen 80;
    server_name $DOMAIN www.$DOMAIN;
    
    root $HOME_DIR/www;
    index index.html index.htm;
    
    location / {
        try_files \$uri \$uri/ =404;
    }
}
EOF
else
    # Standard user directory configuration
    NGINX_USER_CONF="/etc/nginx/sites-available/user_$USER"
    
    cat << EOF > "$NGINX_USER_CONF"
location ~ ^/~$USER(/.*)?$ {
    alias $HOME_DIR/www\$1;
    index index.html index.htm;
    autoindex on;
    try_files \$uri \$uri/ =404;
}
EOF
    
    ln -s "$NGINX_USER_CONF" "/etc/nginx/sites-enabled/"
fi

# Test and reload Nginx
nginx -t && systemctl reload nginx

Configure the script to run automatically when users are added:

# For Debian/Ubuntu systems
echo '#!/bin/sh
if [ "$1" = "add" ]; then
    /usr/local/bin/nginx-user-setup "$2"
fi' > /etc/adduser.conf

When implementing this solution:

  • Set proper directory permissions (755 for directories, 644 for files)
  • Consider using userdir module with proper security restrictions
  • Implement rate limiting for user directories
  • Add proper logging for each virtual host

For more complex setups, you might want to:

# Add PHP support for user directories
location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

# Enable HTTPS for custom domains
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/$domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$domain/privkey.pem;