Node.js + Nginx - What now?

后端 未结 12 1630
抹茶落季
抹茶落季 2020-11-22 00:26

I\'ve set up Node.js and Nginx on my server. Now I want to use it, but, before I start there are 2 questions:

  1. How should they work together? How should I handl
相关标签:
12条回答
  • 2020-11-22 00:51

    You can also setup multiple domain with nginx, forwarding to multiple node.js processes.

    For example to achieve these:

    • domain1.com -> to Node.js process running locally http://127.0.0.1:4000
    • domain2.com -> to Node.js process running locally http://127.0.0.1:5000

    These ports (4000 and 5000) should be used to listen the app requests in your app code.

    /etc/nginx/sites-enabled/domain1

    server {
        listen 80;
        listen [::]:80;
        server_name domain1.com;
        access_log /var/log/nginx/domain1.access.log;
        location / {
            proxy_pass    http://127.0.0.1:4000/;
        }
    }
    

    In /etc/nginx/sites-enabled/domain2

    server {
        listen 80;
        listen [::]:80;
        server_name domain2.com;
        access_log /var/log/nginx/domain2.access.log;
        location / {
            proxy_pass    http://127.0.0.1:5000/;
        }
    }
    
    0 讨论(0)
  • 2020-11-22 00:51

    I made a repository in Github which you can clone, vagrant-node-nginx-boilerplate

    basically the node.js app at /var/www/nodeapp is

    var http = require('http');
    http.createServer(function (req, res) {
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end('Hello World\n');
    }).listen(4570, '127.0.0.1');
    
    console.log('Node Server running at 127.0.0.1:4570/');
    

    and the nginx config at /etc/nginx/sites-available/ is

    server {
            listen 80 default_server;
            listen [::]:80 default_server;
    
            root /var/www/nodeapp;
            index index.html index.htm;
    
            server_name localhost;
    
            location / {
              proxy_pass http://127.0.0.1:4570;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
            }
    }
    
    0 讨论(0)
  • 2020-11-22 00:52

    Nginx works as a front end server, which in this case proxies the requests to a node.js server. Therefore you need to setup an nginx config file for node.

    This is what I have done in my Ubuntu box:

    Create the file yourdomain.com at /etc/nginx/sites-available/:

    vim /etc/nginx/sites-available/yourdomain.com
    

    In it you should have something like:

    # the IP(s) on which your node server is running. I chose port 3000.
    upstream app_yourdomain {
        server 127.0.0.1:3000;
        keepalive 8;
    }
    
    # the nginx server instance
    server {
        listen 80;
        listen [::]:80;
        server_name yourdomain.com www.yourdomain.com;
        access_log /var/log/nginx/yourdomain.com.log;
    
        # pass the request to the node.js server with the correct headers
        # and much more can be added, see nginx config options
        location / {
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_set_header X-NginX-Proxy true;
    
          proxy_pass http://app_yourdomain/;
          proxy_redirect off;
        }
     }
    

    If you want nginx (>= 1.3.13) to handle websocket requests as well, add the following lines in the location / section:

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    

    Once you have this setup you must enable the site defined in the config file above:

    cd /etc/nginx/sites-enabled/ 
    ln -s /etc/nginx/sites-available/yourdomain.com yourdomain.com
    

    Create your node server app at /var/www/yourdomain/app.js and run it at localhost:3000

    var http = require('http');
    
    http.createServer(function (req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('Hello World\n');
    }).listen(3000, "127.0.0.1");
    console.log('Server running at http://127.0.0.1:3000/');
    

    Test for syntax mistakes:

    nginx -t
    

    Restart nginx:

    sudo /etc/init.d/nginx restart
    

    Lastly start the node server:

    cd /var/www/yourdomain/ && node app.js
    

    Now you should see "Hello World" at yourdomain.com

    One last note with regards to starting the node server: you should use some kind of monitoring system for the node daemon. There is an awesome tutorial on node with upstart and monit.

    0 讨论(0)
  • 2020-11-22 00:52

    Nginx can act as a reverse proxy server which works just like a project manager. When it gets a request it analyses it and forwards the request to upstream(project members) or handles itself. Nginx has two ways of handling a request based on how its configured.

    • serve the request
    • forward the request to another server

      server{
       server_name mydomain.com sub.mydomain.com;
      
       location /{ 
        proxy_pass http://127.0.0.1:8000;  
        proxy_set_header Host $host;
        proxy_pass_request_headers on;  
       }
      
       location /static/{
         alias /my/static/files/path;
       }
      

      }

    Server the request

    With this configuration, when the request url is mydomain.com/static/myjs.js it returns the myjs.js file in /my/static/files/path folder. When you configure nginx to serve static files, it handles the request itself.

    forward the request to another server

    When the request url is mydomain.com/dothis nginx will forwards the request to http://127.0.0.1:8000. The service which is running on the localhost 8000 port will receive the request and returns the response to nginx and nginx returns the response to the client.

    When you run node.js server on the port 8000 nginx will forward the request to node.js. Write node.js logic and handle the request. That's it you have your nodejs server running behind the nginx server.

    If you wish to run any other services other than nodejs just run another service like Django, flask, php on different ports and config it in nginx.

    0 讨论(0)
  • 2020-11-22 00:56

    You can run nodejs using pm2 if you want to manage each microservice means and run it. Node will be running in a port right just configure that port in nginx(/etc/nginx/sites-enabled/domain.com)

    server{
        listen 80;
        server_name domain.com www.domain.com;
    
      location / {
         return 403;
      }
        location /url {
            proxy_pass http://localhost:51967/info;
        }
    }
    

    Check whether localhost is running or not by using ping.

    And

    Create one single Node.js server which handles all Node.js requests. This reads the requested files and evals their contents. So the files are interpreted on each request, but the server logic is much simpler.
    

    This is best and as you said easier too

    0 讨论(0)
  • 2020-11-22 01:02

    The best and simpler setup with Nginx and Nodejs is to use Nginx as an HTTP and TCP load balancer with proxy_protocol enabled. In this context, Nginx will be able to proxy incoming requests to nodejs, and also terminate SSL connections to the backend Nginx server(s), and not to the proxy server itself. (SSL-PassThrough)

    In my opinion, there is no point in giving non-SSL examples, since all web apps are (or should be) using secure environments.

    Example config for the proxy server, in /etc/nginx/nginx.conf

    user  nginx;
    worker_processes  1;
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    events {
        worker_connections  1024;
    }
    http {
      upstream webserver-http {
        server 192.168.1.4; #use a host port instead if using docker
        server 192.168.1.5; #use a host port instead if using docker
      }
      upstream nodejs-http {
        server 192.168.1.4:8080; #nodejs listening port
        server 192.168.1.5:8080; #nodejs listening port
      }
      server {
        server_name example.com;
        location / {
          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_set_header Host $http_host;
          proxy_set_header X-Forwarded-Host $server_name;
          proxy_set_header Connection "";
          add_header       X-Upstream $upstream_addr;
          proxy_redirect     off;
          proxy_connect_timeout  300;
          proxy_http_version 1.1;
          proxy_buffers 16 16k;
          proxy_buffer_size 16k;
          proxy_cache_background_update on;
          proxy_pass http://webserver-http$request_uri;
        }
      }
      server {
        server_name node.example.com;
        location / {
          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_set_header Host $http_host;
          proxy_set_header X-Forwarded-Host $server_name;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "Upgrade";
          add_header       X-Upstream $upstream_addr;
          proxy_redirect     off;
          proxy_connect_timeout  300;
          proxy_http_version 1.1;
          proxy_buffers 16 16k;
          proxy_buffer_size 16k;
          proxy_cache_background_update on;
          proxy_pass http://nodejs-http$request_uri;
        }
      }
    }
    stream {
      upstream webserver-https {
        server 192.168.1.4:443; #use a host port instead if using docker
        server 192.168.1.5:443; #use a host port instead if using docker
      }
    
      server {
        proxy_protocol on;
        tcp_nodelay on;
        listen 443;
        proxy_pass webserver-https;
      }
      log_format proxy 'Protocol: $protocol - $status $bytes_sent $bytes_received $session_time';
      access_log  /var/log/nginx/access.log proxy;
      error_log /var/log/nginx/error.log debug;
    }
    

    Now, let's handle the backend webserver. /etc/nginx/nginx.conf:

    user  nginx;
    worker_processes  1;
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    load_module /etc/nginx/modules/ngx_http_geoip2_module.so; # GeoIP2
    events {
        worker_connections  1024;
    }
    http {
        variables_hash_bucket_size 64;
        variables_hash_max_size 2048;
        server_tokens off;
        sendfile    on;
        tcp_nopush  on;
        tcp_nodelay on;
        autoindex off;
        keepalive_timeout  30;
        types_hash_bucket_size 256;
        client_max_body_size 100m;
        server_names_hash_bucket_size 256;
        include         mime.types;
        default_type    application/octet-stream;
        index  index.php index.html index.htm;
        # GeoIP2
        log_format  main    'Proxy Protocol Address: [$proxy_protocol_addr] '
                            '"$request" $remote_addr - $remote_user [$time_local] "$request" '
                            '$status $body_bytes_sent "$http_referer" '
                            '"$http_user_agent" "$http_x_forwarded_for"';
    
        # GeoIP2
        log_format  main_geo    'Original Client Address: [$realip_remote_addr]- Proxy Protocol Address: [$proxy_protocol_addr] '
                                'Proxy Protocol Server Address:$proxy_protocol_server_addr - '
                                '"$request" $remote_addr - $remote_user [$time_local] "$request" '
                                '$status $body_bytes_sent "$http_referer" '
                                '$geoip2_data_country_iso $geoip2_data_country_name';
    
        access_log  /var/log/nginx/access.log  main_geo; # GeoIP2
    #===================== GEOIP2 =====================#
        geoip2 /usr/share/geoip/GeoLite2-Country.mmdb {
            $geoip2_metadata_country_build  metadata build_epoch;
            $geoip2_data_country_geonameid  country geoname_id;
            $geoip2_data_country_iso        country iso_code;
            $geoip2_data_country_name       country names en;
            $geoip2_data_country_is_eu      country is_in_european_union;
        }
        #geoip2 /usr/share/geoip/GeoLite2-City.mmdb {
        #   $geoip2_data_city_name city names en;
        #   $geoip2_data_city_geonameid city geoname_id;
        #   $geoip2_data_continent_code continent code;
        #   $geoip2_data_continent_geonameid continent geoname_id;
        #   $geoip2_data_continent_name continent names en;
        #   $geoip2_data_location_accuracyradius location accuracy_radius;
        #   $geoip2_data_location_latitude location latitude;
        #   $geoip2_data_location_longitude location longitude;
        #   $geoip2_data_location_metrocode location metro_code;
        #   $geoip2_data_location_timezone location time_zone;
        #   $geoip2_data_postal_code postal code;
        #   $geoip2_data_rcountry_geonameid registered_country geoname_id;
        #   $geoip2_data_rcountry_iso registered_country iso_code;
        #   $geoip2_data_rcountry_name registered_country names en;
        #   $geoip2_data_rcountry_is_eu registered_country is_in_european_union;
        #   $geoip2_data_region_geonameid subdivisions 0 geoname_id;
        #   $geoip2_data_region_iso subdivisions 0 iso_code;
        #   $geoip2_data_region_name subdivisions 0 names en;
       #}
    
    #=================Basic Compression=================#
        gzip on;
        gzip_disable "msie6";
        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_buffers 16 8k;
        gzip_http_version 1.1;
        gzip_types text/css text/xml text/plain application/javascript image/jpeg image/png image/gif image/x-icon image/svg+xml image/webp application/font-woff application/json application/vnd.ms-fontobject application/vnd.ms-powerpoint;
        gzip_static on;
        
        include /etc/nginx/sites-enabled/example.com-https.conf;
    }
    

    Now, let's configure the virtual host with this SSL and proxy_protocol enabled config at /etc/nginx/sites-available/example.com-https.conf:

    server {
        real_ip_header proxy_protocol;
        set_real_ip_from 192.168.1.1; #proxy server ip address
        #set_real_ip_from proxy; #proxy container hostname if you are using docker
        server_name 192.168.1.4; #Your current server ip address. It will redirect to the domain name.
        listen 80;
        listen 443 ssl http2;
        listen [::]:80;
        listen [::]:443 ssl http2;
        ssl_certificate     /etc/nginx/certs/example.com.crt;
        ssl_certificate_key /etc/nginx/certs/example.com.key;
        ssl_dhparam /etc/nginx/ssl/dhparam.pem;
        return 301 https://example.com$request_uri;
    }
    server {
        real_ip_header proxy_protocol;
        set_real_ip_from 192.168.1.1; #proxy server ip address
        #set_real_ip_from proxy; #proxy container hostname if you are using docker
        server_name  example.com;
        listen       *:80;
        return 301   https://example.com$request_uri;
    }
    server {
        real_ip_header proxy_protocol;
        set_real_ip_from 192.168.1.1; #proxy server ip address
        #set_real_ip_from proxy; #proxy container hostname if you are using docker
        server_name www.example.com;
        listen 80;
        listen 443 http2;
        listen [::]:80;
        listen [::]:443 ssl http2 ;
        ssl_certificate     /etc/nginx/certs/example.com.crt;
        ssl_certificate_key /etc/nginx/certs/example.com.key;
        ssl_dhparam /etc/nginx/ssl/dhparam.pem;
        return 301 https://example.com$request_uri;
    }
    server {
        real_ip_header proxy_protocol;
        set_real_ip_from 192.168.1.1; #proxy server ip address
        #set_real_ip_from proxy; #proxy container hostname if you are using docker
        server_name example.com;
        listen 443 proxy_protocol ssl http2;
        listen [::]:443 proxy_protocol ssl http2;
        root /var/www/html;
        charset UTF-8;
        add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header Referrer-Policy no-referrer;
        ssl_prefer_server_ciphers on;
        ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
        ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
        ssl_session_cache   shared:SSL:10m;
        ssl_session_timeout 10m;
        keepalive_timeout   70;
        ssl_buffer_size 1400;
        ssl_dhparam /etc/nginx/ssl/dhparam.pem;
        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 8.8.8.8 8.8.4.4 valid=86400;
        resolver_timeout 10;
        ssl_certificate     /etc/nginx/certs/example.com.crt;
        ssl_certificate_key /etc/nginx/certs/example.com.key;
        ssl_trusted_certificate /etc/nginx/certs/example.com.crt;
    location ~* \.(jpg|jpe?g|gif|png|ico|cur|gz|svgz|mp4|ogg|ogv|webm|htc|css|js|otf|eot|svg|ttf|woff|woff2)(\?ver=[0-9.]+)?$ {
        expires modified 1M;
        add_header Access-Control-Allow-Origin '*';
        add_header Pragma public;
        add_header Cache-Control "public, must-revalidate, proxy-revalidate";
        access_log off;
        }
        location ~ /.well-known { #For issuing LetsEncrypt Certificates
            allow all;
        }
    location / {
        index index.php;
        try_files $uri $uri/ /index.php?$args;
        }
    error_page  404    /404.php;
    
    location ~ \.php$ {
        try_files       $uri =404;
        fastcgi_index   index.php;
        fastcgi_pass    unix:/tmp/php7-fpm.sock;
        #fastcgi_pass    php-container-hostname:9000; (if using docker)
        fastcgi_pass_request_headers on;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_param   SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on;
        fastcgi_ignore_client_abort off;
        fastcgi_connect_timeout 60;
        fastcgi_send_timeout 180;
        fastcgi_read_timeout 180;
        fastcgi_request_buffering on;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;
        include fastcgi_params;
    }
    location = /robots.txt {
        access_log off;
        log_not_found off;
        }
    location ~ /\. {
        deny  all;
        access_log off;
        log_not_found off;
        }
    }
    

    And lastly, a sample of 2 nodejs webservers: First server:

    var http = require('http');
    
    http.createServer(function (req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('Hello From Nodejs\n');
    }).listen(8080, "192.168.1.4");
    console.log('Server running at http://192.168.1.4:8080/');
    

    Second server:

    var http = require('http');
    
    http.createServer(function (req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('Hello From Nodejs\n');
    }).listen(8080, "192.168.1.5");
    console.log('Server running at http://192.168.1.5:8080/');
    

    Now everything should be perfectly working and load-balanced.

    A while back i wrote about How to set up Nginx as a TCP load balancer in Docker. Check it out if you are using Docker.

    0 讨论(0)
提交回复
热议问题