Setting Up Nginx as a Reverse Proxy for Multiple Apps

What a reverse proxy does?

  • Sits in front of one or more backend apps/services, forwards incoming requests to the right one based on domain, path, or port
  • Client only ever talks to the proxy. Backend processes never need to be exposed directly to the internet

So why do we need reverse proxy?

  • Single entry point on port 80/443 instead of exposing each app on its own raw port
  • TLS/SSL termination handled in one place instead of configuring it per app
  • Can route multiple apps or services through one server, each reachable by its own domain or subdomain
  • Backend ports stay closed to the outside world, only reachable from the proxy itself (localhost)

Architecture

Each backend binds only to localhost/127.0.0.1, nginx is the only process exposed externally

Core config structure

  • One server block per domain/app, distinguished by server_name
  • location block(s) inside each, matching the paths to forward
  • proxy_pass directive pointing at the backend address (http://127.0.0.1:PORT)

Headers worth setting on proxied requests, and why

  • Host: passes the original requested domain through to the backend
  • X-Real-IP: preserves the actual client IP (otherwise every request looks like it came from the proxy itself)
  • X-Forwarded-For: chain of IPs if there are multiple proxies/hops
  • X-Forwarded-Proto: tells the backend whether the original request was http or https. Without this, an app can generate broken redirect URLs (redirecting to http even when the client is on https)

The problem

  • Symptom: everything works through the proxy except a feature relying on a persistent connection (live chat, real-time notifications, websockets). It loads fine, then silently stops updating
  • Why: nginx doesn’t forward the Upgrade and Connection headers by default, so the backend never sees the HTTP upgrade request that starts a WebSocket connection. The connection quietly falls back or fails
  • Fix: add these two lines inside the relevant location block
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

Example config file

server {
    listen 80;
    server_name app-two.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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_redirect off;
    }
}

What actually makes this a reverse proxy

Compare it to a plain nginx server block that just serves static files or hands off to PHP-FPM directly. What’s different here, and what each piece is doing:

  • proxy_pass http://127.0.0.1:8080;: this is the one line that defines it. Instead of nginx serving a file or handing off to a local process handler (like fastcgi_pass for PHP), it forwards the entire request to a separate running service and relays that service’s response back to the client. Nginx isn’t the thing answering the request, it’s relaying to something else that is.
  • proxy_set_header lines: not strictly required for the proxy to function (it would forward requests without them), but required for the backend app to behave correctly. Without them the backend sees every request as if it came from nginx itself, on the wrong protocol, with no idea what domain was actually requested.
  • No root or try_files directive: a static/PHP-serving block needs those to find files on disk. A reverse proxy block doesn’t touch the filesystem at all, everything after proxy_pass is the other service’s job.
  • The backend address is 127.0.0.1, not 0.0.0.0 or a public IP: the backend only needs to be reachable from nginx itself, not from the internet directly.

If a config has proxy_pass pointing at another address, that’s the defining trait. Everything else (headers, timeouts, buffering settings) is tuning around that core behavior, not what makes it a reverse proxy in the first place.

Takeaway

  • If a proxied app has any real-time feature and it stops working only through the proxy (not when hitting the backend directly), check the Upgrade/Connection headers before anything else

Book a Free Consultation

Haven’t found the right solution yet?
Tell us about your needs, and let’s discuss the best solution together.

Project description.

Built a private marketplace research and purchase planning platform for Shopee. The system tracks product performance over time, estimates sales velocity and gross revenue, analyzes demand across product variants, and turns the research into actionable purchasing plans. It also calculates supplier costs, shipping, platform fees, margins, planned investment, and estimated earnings to support data-driven sourcing decisions.

Skills and deliverables

Full-Stack Development, Web Application Development, Data Analysis, Business Process Automation, Business Intelligence

Shopee Marketplace Research & Purchase Planning Dashboard

We built this application to solve a common problem in marketplace sourcing: finding products is easy, but deciding what is actually worth buying, which variant to prioritize, and how much inventory to purchase requires much more analysis. Instead of relying on a single product snapshot, the system organizes products into research collections and tracks their marketplace performance over time.

Product research & tracking

Products can be added individually or collected from marketplace stores and organized into dedicated research collections. The system keeps historical observations so users can compare changes between captures instead of relying only on the latest marketplace data. This makes it possible to estimate metrics such as: – Sales velocity – Estimated daily gross revenue – Price changes – Product movement over time – Variant-level demand

Variant demand analysis

One of the most important parts of the system is identifying which variants are actually driving sales. Instead of treating a product as a single item, the application analyzes sales movement at variant level and shows each variant’s contribution to recent demand. This helps identify which sizes, models, or variations should be prioritized when purchasing inventory.

Purchase planning

Research data can then be converted directly into a purchasing plan. For every product and variant, the user can enter supplier pricing, shipping costs, purchase quantities, exchange rates, and other operational costs. The system automatically calculates: – Planned inventory investment – Shipping cost – Marketplace/platform fees – Net margin per unit – Net margin percentage – Estimated earnings – Total batch investment This allows purchasing decisions to be evaluated before committing capital.

Why We built it

The goal was to replace a workflow that would normally require multiple spreadsheets, manual marketplace checks, and repeated calculations. The resulting workflow became: Discover products → Track performance → Analyze demand → Select variants → Plan purchasing → Estimate margins Everything is kept in one application, making the research and sourcing process easier to review, repeat, and scale.

Result

The platform turns raw marketplace observations into actionable purchasing information. Instead of choosing products based only on intuition or current sales numbers, users can evaluate sales movement, variant demand, sourcing cost, expected margin, and required investment before making a purchasing decision. Built as an end-to-end internal tool, from data collection and analysis to the final purchasing workflow.

Project description.

Built a browser-based tool that converts Shopee/SPX order exports into clean, print-ready shipping labels. It supports multiple Excel/CSV files, combines orders into one preview, and automatically generates QR codes, barcodes, tracking numbers, and product information for 68 mm thermal printers. All order data is processed locally in the browser for better privacy, eliminating repetitive manual label formatting.

Skills and deliverables

Laravel, Business Automation, CSV, Microsoft Excel

Shopee SPX Order Label Maker for Thermal Printing

This tool was built to simplify the shipping label preparation process for Shopee SPX orders. The existing workflow required order data to be exported from Shopee and manually formatted before it could be printed on a thermal printer. This became repetitive and time-consuming, especially when processing multiple orders at once.

We built a browser-based label generator that reads Shopee Excel/CSV exports and automatically converts the order data into clean, print-ready SPX labels. The tool automatically handles: – Tracking numbers – QR codes – Barcodes – Product names and variants – Order quantities – Multiple order files at once – 68 mm thermal printer formatting Users can review all generated labels before printing, without having to manually copy or reorganize the order information.

The order files are processed directly inside the browser instead of being uploaded to a server. This keeps customer and shipment data private while also making the tool fast and simple to use.