Dynamic Nginx Root Path Configuration Based on Hostname Patterns for Local Development


2 views

When setting up a local development environment, we often need to handle multiple projects under similar domain patterns. The traditional approach of creating separate server blocks for each subdomain becomes tedious. Here's how to implement dynamic root path resolution in Nginx based on hostname patterns.

The core solution involves using regular expressions in the server_name directive to capture and reuse parts of the domain name. Here's the improved configuration:

server {
    listen 80;
    server_name ~^(?.+)\.frameworks\.loc$;
    root /var/www/frameworks/$subdomain/public;
    
    index index.php index.html index.htm;
    
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass 127.0.0.1:9000;
        
        fastcgi_read_timeout 300;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
    }
}
  • Using named capture group (?.+) for better readability
  • Consolidated configuration within a single server block
  • Added proper PHP-FPM timeout settings for development
  • Simplified the fastcgi parameter passing

If you're still getting 404 errors, check these aspects:

# Verify directory structure exists
ls -la /var/www/frameworks/test-project/public/

# Check Nginx error logs
tail -f /var/log/nginx/error.log

# Test regex matching
nginx -T | grep -A5 "server_name"

For handling multiple domain patterns:

server {
    listen 80;
    server_name ~^(?.+)\.(frameworks|projects|dev)\.(loc|test)$;
    root /var/www/$2/$project/public;
    
    # Rest of configuration...
}

Ensure Nginx worker processes have proper access:

sudo chown -R $USER:www-data /var/www/frameworks
sudo chmod -R 775 /var/www/frameworks

Create a simple shell script to scaffold new projects:

#!/bin/bash
if [ -z "$1" ]; then
    echo "Usage: newproject "
    exit 1
fi

mkdir -p "/var/www/frameworks/$1/public"
echo "" > "/var/www/frameworks/$1/public/index.php"
echo "Added $1.frameworks.loc"

When setting up development environments, we often need to handle multiple projects under a common domain pattern. The goal is to dynamically route requests like project1.framework.loc to /var/www/frameworks/project1/public without creating separate server blocks for each subdomain.

The 404 error typically occurs because:

  1. Permission issues on the target directory
  2. Incorrect regex capture group reference
  3. Missing directory structure

Here's a working configuration that handles dynamic root paths:

server {
    listen 80;
    server_name ~^(?<subdomain>[^.]+)\.frameworks\.loc$;
    
    root /var/www/frameworks/$subdomain/public;
    
    index index.php index.html index.htm;
    
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
    }
}

Named capture groups (?<subdomain>) make the configuration more readable and maintainable compared to numeric references.

Directory structure verification: Before implementing this, ensure:

sudo mkdir -p /var/www/frameworks/{project1,project2}/public
sudo chown -R $USER:$USER /var/www/frameworks/
sudo chmod -R 755 /var/www/frameworks/

Add test entries to /etc/hosts:

127.0.0.1 project1.frameworks.loc
127.0.0.1 project2.frameworks.loc

Create test files:

echo "<?php phpinfo(); ?>" > /var/www/frameworks/project1/public/index.php
echo "Hello Project2" > /var/www/frameworks/project2/public/index.html
  • Verify nginx error logs: tail -f /var/log/nginx/error.log
  • Check directory permissions
  • Test with simple HTML files before PHP
  • Clear DNS cache if needed

For larger teams, consider adding auto-creation of project directories:

map $host $project_root {
    ~^(?<project>[^.]+)\.frameworks\.loc$ /var/www/frameworks/$project/public;
    default /var/www/default;
}

server {
    listen 80;
    server_name ~.frameworks.loc$;
    root $project_root;
    ...
}