How to Modularize Nginx Configurations for Multiple Ruby Apps Using Sub-directories


1 views

When trying to split Nginx configurations for multiple Ruby applications into separate files, the most common mistake is defining duplicate server blocks. The error message conflicting server name "example.com" on [::]:80, ignored occurs because Nginx doesn't allow multiple server blocks with identical listen and server_name directives.

The correct approach is to maintain one master server configuration that includes location-specific configurations from separate files. Here's how to structure it:

# Main nginx.conf (usually in /etc/nginx/nginx.conf)
http {
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

# /etc/nginx/sites-enabled/example.com.conf
server {
    listen [::]:80;
    listen 80;
    server_name example.com;
    
    include /home/user/app1/nginx-location.conf;
    include /home/user/app2/nginx-location.conf;
    include /home/user/app3/nginx-location.conf;
}

Each application directory can contain a location configuration file that only defines its specific routing:

# ~/app1/nginx-location.conf
location /app1 {
    proxy_pass http://app1;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Request-Start $msec;
}

You have two options for defining upstream servers:

# Option 1: Centralized upstream definitions
# /etc/nginx/conf.d/upstreams.conf
upstream app1 { server 127.0.0.1:4567; }
upstream app2 { server 127.0.0.1:4568; }
upstream app3 { server 127.0.0.1:4569; }

# Option 2: App-specific upstreams
# ~/app1/nginx-upstream.conf
upstream app1 { server 127.0.0.1:4567; }

For better scalability with many applications, use wildcard includes:

# Main server configuration
server {
    # ... other directives ...
    include /home/user/app*/nginx-location.conf;
}

After configuration changes, always test and reload:

sudo nginx -t
sudo systemctl reload nginx

When trying to split Nginx configurations for multiple Ruby applications into individual files, many developers encounter the "conflicting server name" error. This occurs because each configuration file attempts to define a complete server block for the same domain.

# This creates conflicts when used in multiple files
server {
  listen 80;
  server_name example.com;
  location /app1 { ... }
}

The proper way to organize these configurations is to use a main Nginx config file that includes location-specific configurations:

# /etc/nginx/conf.d/main.conf
server {
  listen 80;
  server_name example.com;
  
  include /home/user/app1/nginx-location.conf;
  include /home/user/app2/nginx-location.conf;
  include /home/user/app3/nginx-location.conf;
}

Each app can then maintain its own location configuration file:

# ~/app1/nginx-location.conf
location /app1 {
  proxy_pass http://app1;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  # Additional proxy settings...
}

Here's a full working example with three Ruby apps:

# Main Nginx configuration
server {
  listen 80;
  server_name example.com;
  root /var/www/html;
  
  include /home/user/app1/nginx.conf;
  include /home/user/app2/nginx.conf;
  include /home/user/app3/nginx.conf;
}

# ~/app1/nginx.conf
upstream app1 { server 127.0.0.1:3000; }
location /app1 {
  proxy_pass http://app1;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_set_header Host $http_host;
}

# ~/app2/nginx.conf
upstream app2 { server 127.0.0.1:3001; }
location /app2 {
  proxy_pass http://app2;
  # Additional proxy settings...
}

To make this configuration more maintainable:

  • Use consistent naming conventions for location blocks
  • Document each app's required Nginx settings in its README
  • Create a test script to verify configurations don't conflict
  • Consider using environment variables for port numbers

If you encounter problems, check:

  1. Nginx error logs (/var/log/nginx/error.log)
  2. Configuration syntax with nginx -t
  3. File permissions on included config files
  4. Upstream server availability