Happy people

Using Nginx for Local Development: Stitching Separate Web Apps Under the Same Domain with a Reverse Proxy

When working on web development projects, you often find yourself juggling multiple web applications that need to communicate seamlessly within the same domain. Consider an ecommerce website with separate web apps for: catalog, cart, payments, user profiles, support, etc. Managing these can become cumbersome, especially when each runs on a different port. Running all these apps from the same origin (scheme + hostname + port) is critical to be able to share session/local storage and avoid pesty CORS issues.

Nginx, a powerful web server and reverse proxy, can help streamline your development environment by stitching separate web apps under the same domain. This guide will walk you through using Nginx's reverse proxy capabilities to achieve this.

What is Nginx?

Nginx is a high-performance web server that also functions as a reverse proxy, load balancer, and HTTP cache. It's known for its stability, rich feature set, simple configuration, and low resource consumption.

What is a Reverse Proxy?

A reverse proxy acts as an intermediary for requests from clients seeking resources from servers. It forwards client requests to the appropriate backend server and returns the server's response to the client. This setup offers several benefits, including load balancing, enhanced security, and centralized authentication.

Why Use Nginx for Local Development?

Using Nginx for local development allows you to:

  • Simplify the management of multiple web apps.
  • Access different applications under a single domain.
  • Simulate production environments.
  • Handle cross-origin resource sharing (CORS) issues.

Step-by-Step Guide to Setting Up Nginx as a Reverse Proxy

We'll use Docker to run Nginx. This will make it easier for other team members to adopt. We'll stitch together two web apps that are configured to run on paths /app1 and /app2, all other traffic fallbacks to a test environment. The idea is to host locally the apps you are responsible for, while letting any other requests go to a test environment to get successful responses and have a fully functional local environment. We'll use our website https//www.makaihq.com as the test environment for demo purposes.

1. Configure Nginx

Create an nginx.conf in your app repo (we'll assume is in the repo root). We'll configure Nginx to act as a reverse proxy. For simplicity, let's assume you have two web apps running locally:

  • App 1 on http://localhost:3000
  • App 2 on http://localhost:4000

We want to access them under the same origin http://localhost:8080 with different paths:

  • http://localhost:8080/app1 for App 1
  • http://localhost:8080/app2 for App 2
  • http://localhost:8080/* fallback to https://example.com for anything else

Edit the nginx.conf file to look like this:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        proxy_cookie_domain www.makaihq.com localhost;

        location / {
            proxy_pass https://www.makaihq.com;
            proxy_ssl_server_name on;
        }

        location /app1 {
            proxy_set_header Host $http_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://host.docker.internal:3000;
        }

        location /app2 {
            proxy_set_header Host $http_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://host.docker.internal:4000;
        }
    }
}

2. Start Nginx

Open a terminal in the repo root. Start Nginx inside Docker by running:

docker run --name local-proxy \
  -v ./nginx.conf:/etc/nginx/nginx.conf:ro \
  -d -p 8080:80 nginx

Make sure to change the path to the nginx.conf if not in the root repo.

3. Access your apps

Open your web browser and navigate to:

  • http://localhost:8080/app1
  • http://localhost:8080/app2

Verify any other requests that do not start with /app1 or /app2 fallback to our website.

Additional Tips

  • SSL/TLS: For a more production-like environment, consider setting up SSL/TLS for your local domain.
  • Full demo available in Github.

Conclusion

Using Nginx as a reverse proxy in your local development environment can significantly simplify the management of multiple web apps. By configuring Nginx within a Docker container, you can create a consistent and isolated environment that mirrors production setups more closely. This approach not only helps in handling various development challenges more effectively but also ensures smooth communication between your applications. Happy coding!