In web development, the front-end and back-end separation architecture has become mainstream. The front-end is responsible for page display, the back-end focuses on business logic and data processing, and the two communicate through API interfaces. However, how to make front-end pages and back-end services work harmoniously, avoid complex cross-domain issues, and make user access more convenient? At this time, Nginx’s reverse proxy function can be very useful.

1. What is a Reverse Proxy?

Let’s start with basic concepts. Let’s first recall forward proxy: For example, if you need to access a foreign website but can’t do it directly, you use a VPN (Virtual Private Network) to proxy your request. This is forward proxy. At this time, the VPN proxies the client, and you don’t know the real address of the target server.

In contrast, reverse proxy proxies the server. The user accesses the reverse proxy server (such as Nginx), but the reverse proxy server will forward the request to the real back-end server according to the request content. For the user, the reverse proxy server is like the back-end server itself, and the user does not need to know the specific address of the back-end service.

2. Why Reverse Proxy is Needed for Front-Back End Separation?

Suppose you have a front-end project (such as Vue or React) and a back-end API service (such as Node.js or Java), which may run on different servers or ports. Without a reverse proxy, users need to access the front-end and back-end addresses separately (e.g., http://frontend.com and http://backend.com/api), which brings several problems:

  1. Complex domain management: Users need to remember multiple domains.
  2. Cross-domain issues: Directly calling back-end interfaces from different domains will trigger browser cross-domain restrictions.
  3. Security risks: Exposing the back-end service address directly increases the risk of being attacked.

Reverse proxy can solve these problems:
- Unified domain name: Users only need to access one domain name (e.g., https://example.com).
- Hide back-end: User requests are intercepted by Nginx and forwarded to the back-end, so the back-end address is transparent to the user.
- Path proxy: Requests for different paths (e.g., / for front-end, /api for back-end) are automatically allocated by Nginx.

3. Nginx Installation and Basic Configuration

1. Install Nginx

For Ubuntu:

sudo apt update
sudo apt install nginx

For CentOS users:

sudo yum install nginx

Windows users can download the installation package from the Nginx official website and install it as prompted.

2. Start and Verify

After installation, start Nginx:

sudo systemctl start nginx

Check status:

sudo systemctl status nginx

At this time, accessing the server IP or domain name (e.g., http://localhost) should show Nginx’s default welcome page, indicating successful installation.

4. Reverse Proxy Practical: Front-End + Back-End Separation Configuration

Assume we have two services:
- Front-end service: Static HTML files (placed in Nginx’s /usr/share/nginx/html directory).
- Back-end service: A simple Node.js API service running on local port 3000 (returns {"message": "Hello from backend"}).

1. Prepare Front-End Static Files

Create a front-end page in Nginx’s default website directory (usually /usr/share/nginx/html for Ubuntu/CentOS):

sudo nano /usr/share/nginx/html/index.html

Write simple content:

<!DOCTYPE html>
<html>
<body>
  <h1>Frontend Page</h1>
  <p>Click the button to call the backend interface:</p>
  <button onclick="callBackend()">Call API</button>
  <script>
    function callBackend() {
      fetch('/api/user')
        .then(res => res.json())
        .then(data => alert(data.message));
    }
  </script>
</body>
</html>

2. Start Back-End Service

Create a simple back-end service with Node.js (Node.js needs to be installed first):

# Create project directory
mkdir backend && cd backend
# Initialize project
npm init -y
# Install Express
npm install express

Create app.js:

const express = require('express');
const app = express();
const port = 3000;

app.get('/user', (req, res) => {
  res.json({ message: 'Hello from backend!' });
});

app.listen(port, () => {
  console.log(`Backend service running at http://localhost:${port}`);
});

Start the back-end:

node app.js

3. Configure Nginx Reverse Proxy

Edit the Nginx configuration file to forward requests to front-end or back-end:

sudo nano /etc/nginx/sites-available/default

Add the following configuration in the server block (see the example below for the complete configuration):

server {
    listen 80;
    server_name localhost;  # Replace with your domain name or server IP

    # Front-end static resources: All paths (except /api) point to the front-end page
    location / {
        root /usr/share/nginx/html;  # Front-end file directory
        index index.html;            # Default homepage
        try_files $uri $uri/ /index.html;  # Support front-end routing (e.g., /#/about)
    }

    # Back-end API: All requests starting with /api are forwarded to the back-end service
    location /api {
        proxy_pass http://localhost:3000;  # Back-end service address
        proxy_set_header Host $host;       # Pass Host header to let the back-end know the request source
        proxy_set_header X-Real-IP $remote_addr;  # Pass real IP
    }
}

4. Verify Configuration and Restart Nginx

Test configuration for errors:

sudo nginx -t

If it prompts test is successful, restart Nginx:

sudo systemctl restart nginx

5. Test the Effect

  • Access http://localhost (or your domain name), and you can see the front-end page.
  • Click the “Call API” button on the page, which will trigger fetch('/api/user'). At this time, Nginx will forward the request to the back-end service http://localhost:3000/user and return the data.

5. Core Configuration Analysis

1. location Block

Nginx defines processing rules for different paths through location. Common matching methods:
- location /: Matches all paths (should be placed before other location blocks).
- location /api: Matches paths starting with /api.

2. proxy_pass

proxy_pass specifies the target address for forwarding, with the format http://target IP:port. For example:

location /api {
    proxy_pass http://127.0.0.1:3000;  # Can also be written as localhost:3000
}

3. proxy_set_header

Pass HTTP header information to the back-end, common scenarios:
- Host $host: The back-end gets the real request domain name.
- X-Real-IP $remote_addr: The back-end gets the user’s real IP (to avoid back-end logs showing Nginx’s IP).

6. Common Issues and Solutions

  1. Nginx fails to start:
    Use nginx -t to check configuration syntax. The error message usually points to the problematic line.

  2. Front-end resources 404:
    Ensure the root path and index file exist, for example:

   location / {
       root /usr/share/nginx/html;  # Path must be correct
       index index.html;            # File must exist
   }
  1. Back-end interface inaccessible:
    Check if the back-end service is running, if the port is occupied, and if proxy_pass has the correct address (e.g., http://localhost:3000 instead of localhost:3000).

7. Summary

Reverse proxy is one of Nginx’s core functions, especially in front-end and back-end separation architecture. It helps us:
- Hide the back-end service address to improve security.
- Unify domain names and paths to simplify user access.
- Centralize request forwarding for easier expansion (e.g., load balancing, caching).

Through the examples in this article, you can quickly start configuring the reverse proxy to make front-end and back-end services work seamlessly. Next, you can try replacing the back-end service with other technology stacks such as Java or Python, or further learn advanced Nginx features like caching and SSL configuration.

Xiaoye