Skip to content

Instantly share code, notes, and snippets.

@kmanadkat
Created February 22, 2023 12:39
Show Gist options
  • Select an option

  • Save kmanadkat/10972106616773f43f813639f790ef1b to your computer and use it in GitHub Desktop.

Select an option

Save kmanadkat/10972106616773f43f813639f790ef1b to your computer and use it in GitHub Desktop.
Setting Up NGINX Reverse Proxy For Local Development

Setup Hosts File

This is very straight forward process and involves editing a single file. You will need sudo privileges for this.

  1. Open Terminal and execute below to open hosts file

    sudo nano /etc/hosts
  2. You will need to add 4 entries against 127.0.0.1 i.e. localhost. Just put a single space between IP and base url. Reference below

    ##
    # Host Database
    #
    # localhost is used to configure the loopback interface
    # when the system is booting.  Do not change this entry.
    ##
    127.0.0.1       localhost
    127.0.0.1 example.domain.com
    
    255.255.255.255 broadcasthost
    ::1             localhost
    # Write the file
    CTRL + O
    # Exit the file
    CTRL + X

Homebrew Installation

If you are on Mac M1 machine, then building things from source could be very difficult and you might hit a blank-wall. That's why homebrew is necessary for us while dealing with installations

# Install Homebrew if not done before
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Install wget if not done before
brew install wget

Creating SSL Certificate

We are not going to create SSL certificates using OpenSSL tool ourself because of high chances of error and browsers like Chrome, Firefox keep increasing their security standards even for local development!! Instead we will use an open source tool [mkcert](https://github.com/FiloSottile/mkcert)

It makes the process extremely simple. Before we start, make sure your Keychain Access mac app doesn't have any item under login > My Certificates. We don't want newly created certificates conflict with existing ones. If you tried creating certificates before for base urls present in hosts file then delete those.

  1. Install mkcert

    brew install mkcert
    
    # If you are planning to use Firefox ever (recommended)
    brew install nss
  2. Initialise mkcert

    mkcert -install

    It may ask permission to access Keychain / secure store of your machine. Use your system password or Touch Id.

  3. Generate a ssl certificate - key pair for example.domain.com

    mkcert example.domain.com

    This will create two .pem files in the directory where your terminal is pointing. One is certificate and another is Key. These are valid for all base urls we just mentioned.

    valid for the following names πŸ“œ
     - "example.domain.com"
    
  4. Generate a Diffie-Hellman group. This is used for perfect forward secrecy, which generates ephemeral session keys to ensure that past communications cannot be decrypted if the session key is compromised. This isn’t entirely necessary for internal communications, but if you want to be as secure as possible you shouldn’t skip this step.

    sudo openssl dhparam -out /opt/homebrew/etc/nginx/dhparam.pem 4096

    This does take a whileβ€”about an hour depending on how fast your system is. Grab some snacks πŸŸΒ πŸ”

Setting Up NGINX

This is little tricky business, especially for Mac M1s. Recommend to follow exactly and it will be done without breaking a sweat!

  1. Install NGINX with homebrew

    # Finally Install NGINX
    brew install nginx
  2. Start the NGINX server

    sudo nginx

    This should be quick and after it is done, you can test http://localhost:8080

  3. We got nginx installed and working. For Mac M1 the installation path is /opt/homebrew/etc/nginx Go to this folder and open it in Vs Code

    # Open NGINX Folder in your favorite editor
    cd /opt/homebrew/etc/nginx
    
    # Run below to open current terminal folder in Vs Code
    code .
  4. Add user. At the top of of nginx.conf file you will find #user nobody; change it to following:

    user <your_username> staff;

    where <your_username> is username which can be found by running whoami in terminal. Example:

    user krupeshanadkat staff;
  5. Next, add the following inside the http block at the very top inside {}

    # allow for many servers
    server_names_hash_bucket_size 512;

    Your nginx.conf file should look like below (only different thing will be username in line 1):

    user krupeshanadkat staff;
    worker_processes  1;
    
    #error_log  logs/error.log;
    #error_log  logs/error.log  notice;
    #error_log  logs/error.log  info;
    
    #pid        logs/nginx.pid;
    
    events {
        worker_connections  1024;
    }
    
    http {
        # allow for many servers
        server_names_hash_bucket_size 512;
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
    
        server {
            listen       8080;
            server_name  localhost;
            location / {
                root   html;
                index  index.html index.htm;
            }
    
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    
        include servers/*;
    }

    I have also removed most of the comments from the file - feel free to keep them if you want

  6. The above folder should already have dhparam.pem file we created in step 4 while creating SSL certificates. Add two directories in this /opt/homebrew/etc/nginx directory just to have some organisation.

    # To keep re-usable nginx snippets -> /opt/homebrew/etc/nginx/snippets
    mkdir snippets
    
    # To keep ssl certificate and key -> /opt/homebrew/etc/nginx/ssl
    mkdir ssl
  7. Go to /opt/homebrew/etc/nginx/snippets directory and create a file called self-signed.conf. Below is the content of file, copy as it is.

    ssl_protocols TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
    ssl_session_timeout 10m;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    
    ssl_dhparam /opt/homebrew/etc/nginx/dhparam.pem;
    ssl_ecdh_curve secp384r1;
  8. Move ssl certificate - key .pem files in /opt/homebrew/etc/nginx/ssl directory. For me the name of the files are localhost+4.pem and localhost+4-key.pem

    Following should be Tree structure after making changes from steps 6 to 8 above

    nginx
      β”œβ”€β”€ dhparam.pem
      ...
      ...
      β”œβ”€β”€ servers
      β”‚   └──
      β”œβ”€β”€ snippets
      β”‚   └── self-signed.conf
      β”œβ”€β”€ ssl
      β”‚   β”œβ”€β”€ localhost+4-key.pem
      β”‚   └── localhost+4.pem
  9. Last thing we need to do is add 4 server files inside servers directory (auto created during nginx installation). Each file has name exactly equal to base urls we defined in hosts file earlier (no file extensions)

    example.domain.com

    The content of every file is exactly same except difference in server_name, proxy_pass and proxy_redirect properties. File name and server_name must match.

    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name example.domain.com;
    
        ssl_certificate      /opt/homebrew/etc/nginx/ssl/example.domain.com.pem;
        ssl_certificate_key  /opt/homebrew/etc/nginx/ssl/example.domain.com-key.pem;
    
        include snippets/self-signed.conf;
    
        location / {
            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_pass          http://localhost:3000;
            proxy_read_timeout  90;
    
            proxy_redirect http://localhost:3000 https://example.domain.com;
        }
    }

    According to the file you are putting configuration, change line 4 (server_name), 17 (proxy_pass), 20 (proxy_redirect)

  10. Once all the server files are in place, validate nginx config (including all server files and snippets files) and restart nginx server

    # Ignore ssl_stappling warnings - you should see below two lines
    # ...syntax is ok
    # ...test is successful
    sudo nginx -t
    
    # Restart nginx - ignore warnings
    sudo nginx -s stop && sudo nginx

    Test http://locahost:8080 for nginx successful restart.

NGINX Commands

Description Command To Execute Brew Equivalent Commands
Start sudo nginx brew services start nginx
Reload sudo nginx -s reload brew services reload nginx
Stop sudo nginx -s stop brew services stop nginx
Restart sudo nginx -s stop && sudo nginx brew services restart nginx
Validate Conf Syntax sudo nginx -t

Setting Up Node Js

The required node version is v12.x I recommend using above version and not the latest version as npm install might fail when trying to install node-sass specified in package.json file of projects.

You could also use homebrew or dmg installer. I prefer installing it open source tool called [nvm (Node Version Manager)](https://github.com/nvm-sh/nvm) as it will help you quickly to change node versions as and when required.

Below snippet will install nvm and attempts to add the source lines from the snippet below to the correct profile file (~/.bash_profile, ~/.zshrc, ~/.profile, or ~/.bashrc).

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash

Confirm nvm Download, compile, and install the specific version of node:

# Check nvm version
nvm - v

# Install node
nvm install 12.13.0

# Check Node version
node -v

Setting Up Projects

After cloning git repositories, getting access to supporting node packages repositories & all above setups done; open each project (cloned repositories root directories) in separate terminal tabs/windows.

Get all packages:

# Ignore warnings and vulnerabilities - we can't fight with that
# npm version matching system is flawed in itself 
npm install

To run the project:

# This will exectute "start" script from package.json
npm run start

To run project on specific port, add prefix PORT=3002 in "start" script of package.json

// Example : Port 3002
"start": "PORT=3002 npm-run-all -p watch-css start-js",

When the project is successfully compiled, it will open http://localhost:PORT url in browser, replace with https://example.domain.com.


All Done 🎑

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment