How to configure virtual hosts in Nginx? What are the configuration methods?
Nginx virtual hosts allow multiple websites to run on the same server, distinguished by different domain names, ports, or IP addresses.
Domain-Based Virtual Hosts:
nginxserver { listen 80; server_name example.com www.example.com; root /var/www/example.com; index index.html index.php; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; location / { try_files $uri $uri/ =404; } } server { listen 80; server_name test.com www.test.com; root /var/www/test.com; index index.html index.php; access_log /var/log/nginx/test.com.access.log; error_log /var/log/nginx/test.com.error.log; location / { try_files $uri $uri/ =404; } }
Port-Based Virtual Hosts:
nginxserver { listen 80; server_name example.com; root /var/www/example.com; index index.html; location / { try_files $uri $uri/ =404; } } server { listen 8080; server_name example.com; root /var/www/example.com/admin; index index.html; location / { try_files $uri $uri/ =404; } } server { listen 8443 ssl; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; root /var/www/example.com/secure; index index.html; location / { try_files $uri $uri/ =404; } }
IP-Based Virtual Hosts:
nginxserver { listen 192.168.1.100:80; server_name example.com; root /var/www/example.com; index index.html; location / { try_files $uri $uri/ =404; } } server { listen 192.168.1.101:80; server_name example.com; root /var/www/example.com/mirror; index index.html; location / { try_files $uri $uri/ =404; } }
Wildcard Domains:
nginx# Match all subdomains server { listen 80; server_name *.example.com; root /var/www/subdomains; index index.html; location / { # Use subdomain as directory name set $subdomain $host; if ($subdomain ~* ^(.*)\.example\.com$) { set $subdomain $1; } root /var/www/subdomains/$subdomain; } } # Match all domains (default virtual host) server { listen 80 default_server; server_name _; root /var/www/default; index index.html; location / { return 404; } }
Regex Domains:
nginxserver { listen 80; server_name ~^(?<subdomain>.+)\.example\.com$; root /var/www/example.com/$subdomain; index index.html; location / { try_files $uri $uri/ =404; } } server { listen 80; server_name ~^(?<user>.+)\.users\.example\.com$; root /var/www/users/$user; index index.html; location / { try_files $uri $uri/ =404; } }
HTTPS Virtual Hosts:
nginxserver { listen 80; server_name example.com; # Redirect to HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; root /var/www/example.com; index index.html; location / { try_files $uri $uri/ =404; } }
Shared Configuration for Multiple Domains:
nginx# Define shared configuration map $host $root_path { example.com /var/www/example.com; test.com /var/www/test.com; default /var/www/default; } server { listen 80; server_name example.com test.com; root $root_path; index index.html; location / { try_files $uri $uri/ =404; } }
Reverse Proxy Virtual Hosts:
nginxupstream backend1 { server 192.168.1.100:8080; server 192.168.1.101:8080; } upstream backend2 { server 192.168.1.200:8080; server 192.168.1.201:8080; } server { listen 80; server_name api.example.com; location / { proxy_pass http://backend1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } server { listen 80; server_name admin.example.com; location / { proxy_pass http://backend2; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
PHP Virtual Hosts:
nginxserver { listen 80; server_name example.com; root /var/www/example.com; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; } }
Static Site Virtual Hosts:
nginxserver { listen 80; server_name static.example.com; root /var/www/static; index index.html; # Enable Gzip compression gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript; # Static resource caching location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; } location / { try_files $uri $uri/ =404; } }
Virtual Host Configuration File Separation:
nginx# /etc/nginx/nginx.conf http { include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } # /etc/nginx/sites-available/example.com server { listen 80; server_name example.com; root /var/www/example.com; index index.html; location / { try_files $uri $uri/ =404; } } # Create symbolic link to enable site # ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
Virtual Host Best Practices:
- Separate configuration files: Use independent configuration files for each virtual host
- Naming conventions: Use domain name as configuration file name
- Separate logs: Use independent log files for each virtual host
- Default host: Configure default_server to handle unknown requests
- SSL configuration: Use HTTPS for all production environments
- Error pages: Configure custom error pages for each virtual host
- Security headers: Add security-related HTTP headers
- Performance optimization: Enable Gzip compression and caching
Complete Virtual Host Configuration Example:
nginx# /etc/nginx/sites-available/example.com server { listen 80; server_name example.com www.example.com; # Redirect to HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name example.com www.example.com; # SSL configuration ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # Root directory root /var/www/example.com; index index.php index.html; # Logs access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # Gzip compression gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript; # Static resources location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; } # PHP processing location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } # Main routing location / { try_files $uri $uri/ /index.php?$query_string; } # Deny access to hidden files location ~ /\. { deny all; access_log off; log_not_found off; } }