Setting Nginx as a reverse proxy for Node.js

by Lance Gold

Yes, Node.js can run behind Nginx

Return to index
Here are some of the references used for this:

Google A.I.

debian nginx configure two static routes

can nginx have multiple symlinks in sites-enabled

nginx using multiple server directives

Yes, NGINX can have multiple symbolic links in the sites-enabled directory

This is the standard and recommended way to manage multiple virtual hosts (server blocks) in NGINX, especially in Debian-based distributions.

How it Works
The sites-enabled/sites-available convention is used to easily manage which sites are active without deleting configuration files.

•sites-available directory: This directory stores all of your NGINX server block configuration files, whether they are currently active or not.

•sites-enabled directory: This directory contains symbolic links to the configuration files in sites-available. NGINX is configured (usually in the main nginx.conf file) to include all files or symlinks within this directory when it loads its configuration.

Key Benefits

•Easy Management: To enable a site, you simply create a symbolic link from sites-available to sites-enabled. To disable a site, you just remove the symlink.

•Organization: It keeps all potential configuration files in one place, even if they aren't active.

•No Duplication: The actual configuration is only written once in sites-available.

Important Note

For this structure to work, your main nginx.conf file must contain a line like:


include /etc/nginx/sites-enabled/*;

This line tells NGINX to process all the configuration files (or symlinks pointing to them) in the sites-enabled directory.

Multiple server directives

Nginx is designed to use multiple server directives (also known as server blocks or virtual hosts) within the main http context of its configuration file to host multiple websites or applications on a single server, often using the same IP address and port.
How Nginx Selects a Server Block:

When a request arrives, Nginx uses a two-step process to decide which server block will handle the connection:

1. Matching the listen directive: Nginx first identifies all server blocks that have compatible listen directives for the incoming IP address and port (e.g., port 80 or 443).

2. Matching the server_name directive: If multiple server blocks match the IP and port, Nginx compares the request's Host header to each block's server_name directive to find the best match. The matching order is:

a. Exact name match.

b. Longest leading wildcard match (e.g., *.example.com).

c. Longest trailing wildcard match (e.g., mail.*).

d. Regular expression match.

If no server_name matches, Nginx uses the default server for that IP and port combination.

Configuration Example

A typical Nginx configuration for multiple websites includes several server blocks within the http { ... } context.


http {
    # Include other common settings (MIME types, logging, etc.)
    include /etc/nginx/mime.types;
    
    # Optional: tune hash sizes if many server names are used
    # server_names_hash_bucket_size 64; 

    # Server block for the first domain
    server {
        listen 80;
        server_name example.com www.example.com;
        root /var/www/example.com/html;
        index index.html index.htm;
        
        location / {
            try_files $uri $uri/ =404;
        }
    }

    # Server block for the second domain
    server {
        listen 80;
        server_name domain2.com www.domain2.com;
        root /var/www/://domain2.com;
        index index.html index.htm;

        location / {
            try_files $uri $uri/ =404;
        }
    }

    # Default server block to handle unmatched requests (optional but recommended)
    server {
        listen 80 default_server;
        server_name ""; # Catches requests without a Host header or unmatched ones
        return 444; # Closes the connection for unrecognized hosts
    }
}

Best Practices

•Separate Files: For better management, it is a common practice to create separate configuration files for each server block in the /etc/nginx/sites-available/ directory and use symbolic links to enable them in the /etc/nginx/sites-enabled/ directory.

•SSL/TLS: For HTTPS, each secure server block requires a valid certificate configured within its own block.

Here is the final result, which does not take care of the http to https problem:


x@c7:~$ more /etc/nginx/sites-available/nginx-443.config
x@c7:~$ more /etc/nginx/sites-available/nginx-443.config
server {
        # listen 80; and listen [::]:80; tell Nginx to listen for iPv4 and IPv6
        listen 80 default_server;
        listen [::]:80 default_server;

        listen 443 ssl default_server; listen [::]:443 ssl default_server;
        server_name c7.xcvvc.com www.c7.xcvvc.com;
        ssl_certificate /etc/ssl/certs/c7.xcvvc.com.pem;
        ssl_certificate_key /etc/ssl/private/c7.xcvvc.com.key;

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        # SSL settings
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;

        # Route 1: location of static content added alongside app folders
        location / {
                root /opt/html;
                index index.html index.htm index.nginx-debian.html;
                try_files $uri $uri/ =404;
        }

        # Route 2: original placement of NginX banner after installation
        location /default/ {
tion blocks,
                # ensuring the path is mapped correctly without
                # appending the location name
                # Note: Both alias and the location path should have
                # a trailling '/'
                alias /var/www/html/;
                index index.html index.htm index.nginx-debian.html;
                try_files $uri $uri/ =404;
        }


        location /js/ {
                proxy_pass http://127.0.0.1:3000;
                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_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
        location /py/ {
                proxy_pass http://127.0.0.1:8000;
                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_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                # Add other necessary headers for Gunicorn
        }
        location /db/ {
                proxy_pass http://127.0.0.1:3306;
                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_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                # Add other necessary headers for MariaDB
        }
}
x@c7:~$

Test and reload configuration


sudo nginx -t
sudo systemctl reload nginx