Modern web applications rarely exist in isolation. Today’s digital infrastructure often consists of multiple interconnected services—APIs, databases, admin panels, monitoring tools, and more. Managing these services efficiently while maintaining security and performance can be challenging. This is where Nginx’s powerful reverse proxy capabilities shine, particularly when combined with subdomain-based routing.
The Challenge: Managing Multiple Services
Imagine you’re running a web application with several backend services:
- A main web application
- A RESTful API
- An analytics dashboard
- A file management system
- Various microservices that support your platform
Traditionally, you might expose these on different ports (:8080, :3000, :9000, etc.), but this approach has significant drawbacks:
- Users must remember port numbers
- Firewalls often block non-standard ports
- SSL certificate management becomes complicated
- The architecture looks unprofessional and is harder to maintain
The Solution: Subdomain-Based Routing with Nginx
A more elegant approach uses subdomain routing, where each service gets its own subdomain under your main domain. Instead of example.com:8080, you access api.example.com. This creates a clean, professional structure that’s easier to manage and more secure.
The Architecture Overview
The setup relies on three key components working together:
1. Wildcard DNS Configuration
First, configure a wildcard DNS record that points all subdomains to your server’s IP address:
*.example.com → 203.0.113.45
example.com → 203.0.113.45
This single DNS record means any subdomain—whether it’s api.example.com, admin.example.com, or newservice.example.com—automatically resolves to your server without additional DNS configuration.
2. Wildcard SSL Certificate
Security is non-negotiable in modern web infrastructure. A wildcard SSL certificate covers your root domain and all subdomains with a single certificate:
Certificate covers:
- example.com
- *.example.com
This means HTTPS works automatically for any subdomain you configure, eliminating the need to obtain and manage separate certificates for each service.
3. Nginx Reverse Proxy Configuration
Nginx sits at the front of your infrastructure, receiving all incoming requests and intelligently routing them to the appropriate backend service based on the subdomain.
Implementation: A Complete Nginx Configuration
Let’s break down a production-ready Nginx configuration that demonstrates these concepts:
Global Performance Optimization
# Enable compression for faster page loads
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types text/plain text/css text/javascript application/json;
Enabling gzip compression reduces bandwidth usage and improves load times, especially for text-based content like HTML, CSS, and JSON.
Defining Backend Services
# Define upstream servers
upstream api_backend {
server api_service:8080;
}
upstream analytics_backend {
server analytics_service:3000;
}
upstream admin_backend {
server admin_service:5000;
}
Upstream blocks define your backend services. These can be Docker containers, separate servers, or services running on different ports on the same machine. Nginx abstracts away these implementation details from your users.
Centralized SSL Configuration
# Common SSL configuration
ssl_certificate /etc/ssl/certs/wildcard.crt;
ssl_certificate_key /etc/ssl/private/wildcard.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
This configuration applies to all server blocks, ensuring consistent security across your entire infrastructure. Modern TLS protocols and cipher suites protect your data in transit.
Automatic HTTP to HTTPS Redirect
# HTTP to HTTPS redirect
server {
listen 80;
server_name _;
server_tokens off;
return 301 https://$host$request_uri;
}
This catch-all block ensures that any HTTP request is automatically redirected to HTTPS, enforcing encryption for all traffic.
Main Application Server
server {
listen 443 ssl;
http2 on;
server_name example.com;
server_tokens off;
# Performance tuning
client_max_body_size 100M;
client_header_buffer_size 64k;
large_client_header_buffers 4 64k;
# Serve static content
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
# Cache static assets aggressively
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
}
# Proxy API requests to backend
location /api/ {
proxy_pass http://api_backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}
This main server block handles your primary domain, serving static files directly while proxying API requests to backend services.
Subdomain Routing
Here’s where the real power comes in—dedicated server blocks for each subdomain:
# API subdomain
server {
listen 443 ssl;
http2 on;
server_name api.example.com;
server_tokens off;
location / {
proxy_pass http://api_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Performance tuning
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
}
}
# Analytics subdomain
server {
listen 443 ssl;
http2 on;
server_name analytics.example.com;
server_tokens off;
location / {
proxy_pass http://analytics_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Admin panel subdomain
server {
listen 443 ssl;
http2 on;
server_name admin.example.com;
server_tokens off;
location / {
proxy_pass http://admin_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Each subdomain gets its own server block, allowing you to customize proxy settings, timeouts, and headers specifically for that service’s needs.
Catch-All Protection
# Catch-all for unknown subdomains
server {
listen 443 ssl;
http2 on;
server_name *.example.com;
server_tokens off;
return 302 https://example.com;
}
This safety net redirects any undefined subdomain back to your main site, preventing errors and potential security issues from unmanaged subdomains.
Key Benefits of This Architecture
1. Simplified SSL Management
One wildcard certificate secures your entire infrastructure. No more juggling multiple certificates with different expiration dates.
2. Clean, Professional URLs
api.example.com is far more professional than example.com:8080 and easier for users to remember and share.
3. Easy Service Addition
Adding a new service requires only:
- Defining a new upstream block
- Creating a new server block
- Reloading Nginx configuration
No DNS changes needed—the wildcard DNS record already covers it.
4. Security Isolation
Each service can have different security policies, rate limiting, and access controls. Compromising one service doesn’t automatically expose others.
5. Flexible Backend Architecture
Backend services can be:
- Docker containers
- Separate physical servers
- Cloud instances
- Different ports on the same machine
Nginx abstracts this complexity from your users.
6. Performance Optimization
Nginx handles:
- SSL termination (freeing backend services from encryption overhead)
- HTTP/2 multiplexing
- Static file caching
- Response compression
- Connection pooling
7. Zero Downtime Deployments
You can update backend services independently without affecting the Nginx frontend. Users experience no interruption.
8. Advanced Features Ready
This foundation makes it easy to add:
- Load balancing across multiple backend instances
- Rate limiting per subdomain
- Geographic routing
- A/B testing
- WebSocket support
- Custom error pages
Real-World Example: Adding a New Service
Let’s say you want to add a monitoring dashboard. Here’s all you need to do:
- Deploy your monitoring service (e.g., on port 9090)
- Add to Nginx configuration:
upstream monitoring_backend {
server monitoring_service:9090;
}
server {
listen 443 ssl;
http2 on;
server_name monitoring.example.com;
server_tokens off;
location / {
proxy_pass http://monitoring_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
- Reload Nginx:
nginx -t && nginx -s reload
That’s it! https://monitoring.example.com is now live, secured with SSL, and accessible to users.
Best Practices and Considerations
Security Headers
Always include security headers in your configuration:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
Logging
Maintain separate access and error logs for each subdomain to simplify troubleshooting:
access_log /var/log/nginx/api.access.log;
error_log /var/log/nginx/api.error.log;
Rate Limiting
Protect your services from abuse with rate limiting:
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
location / {
limit_req zone=api_limit burst=20;
proxy_pass http://api_backend;
}
Health Checks
Configure proper upstream health checks to ensure traffic only goes to healthy backends:
upstream api_backend {
server api_service:8080 max_fails=3 fail_timeout=30s;
}
Conclusion
Subdomain-based routing with Nginx provides a robust, scalable foundation for modern multi-service architectures. By combining wildcard DNS, wildcard SSL certificates, and Nginx’s powerful reverse proxy capabilities, you create an infrastructure that’s:
- Professional: Clean URLs that inspire confidence
- Secure: Centralized SSL management and isolated services
- Scalable: Easy to add new services without infrastructure changes
- Performant: Nginx handles optimization at the edge
- Maintainable: Clear separation of concerns and configuration
Whether you’re running a small web application with a few microservices or a complex platform with dozens of interconnected services, this architecture pattern provides the flexibility and robustness you need to grow confidently.
The beauty of this approach is that it starts simple but scales infinitely. Begin with a few subdomains and expand as your needs grow—all without fundamental changes to your architecture.

