Operations 16 min read

Nginx Core Configuration After Deploy: 3-Layer Structure, Static Hosting, Reverse Proxy & Multi-Site

This guide explains Nginx core configuration after one-click deployment, covering config file locations across OSes, the three-layer structure (global, events, HTTP), and three practical scenarios: static resource hosting with try_files for SPA routing, reverse proxy for CORS resolution and backend hiding, and multi-site deployment via multiple server blocks, plus troubleshooting tips for common errors.

Engineer Tang's Implementation Study Notes
Engineer Tang's Implementation Study Notes
Engineer Tang's Implementation Study Notes
Nginx Core Configuration After Deploy: 3-Layer Structure, Static Hosting, Reverse Proxy & Multi-Site

Locating the Nginx Configuration File

The main configuration file is nginx.conf. Its default location depends on the installation method:

Linux (manual or scripted): /usr/local/nginx/conf/nginx.conf macOS (Homebrew): $(brew --prefix)/etc/nginx/nginx.conf Windows (manual):

your_nginx_install_dir/conf/nginx.conf

Two Essential Operations

1. Edit the Configuration

vim /usr/local/nginx/conf/nginx.conf

Save and exit: press ESC, type :wq, press Enter.

2. Apply the Configuration (Required for Changes to Take Effect)

# Step 1: Validate syntax
nginx -t
# Step 2: Reload without downtime
nginx -s reload

Common Pitfall: Forgetting to run nginx -s reload after editing. The author recounts a real incident where two engineers spent two hours debugging a config that never reloaded because neither had executed the reload command.

Three-Layer Structure of nginx.conf

The file is organized into three hierarchical blocks. An analogy: a residential complex.

Layer 1: Global Block (Complex-Wide Rules)

worker_processes  1;          # Worker processes, set to CPU cores (2/4), default 1 is fine
error_log  logs/error.log;    # Error log path, first place to check on issues
pid        logs/nginx.pid;    # PID file, leave alone

Principle: Do not modify.

Layer 2: Events Block (Traffic Rules)

events {
    worker_connections  1024; # Max connections per worker, default 1024 suffices
    # High concurrency (hundreds of simultaneous users) can raise to 2048/4096, but avoid excess
}

Principle: Leave default; changing can cause instability.

Layer 3: HTTP Block (Core: Each Building = A Site/App)

http {
    include       mime.types;                 # Recognize html, css, js, images, etc.
    default_type  application/octet-stream;   # Unknown files served as binary

    # Performance optimizations, copy as-is
    sendfile        on;
    keepalive_timeout  65;

    # server block: each building = a site/application (focus here!)
    # Deploy 2 frontend projects → write 2 server blocks
    server {
        listen       8080;                    # Listen port (match deployment port)
        server_name  192.168.1.100;           # Server IP, use localhost for local test

        # location block: match request path, configure specific rules
        location / {
            root   html;                      # ⚠️ Core param: static resource root (main thing you change)
            index  index.html index.htm;      # Default index, leave alone
        }
    }
}

Summary: 80% of daily config changes happen inside the HTTP block's server and location blocks. Global and events blocks should stay untouched.

Three Common Configuration Patterns (Copy, Adjust Paths, Run)

1. Static Resource Hosting (Most Common: Deploy Frontend Projects, Images, Files)

Scenario: Serve a Vue/React dist folder or local image/document directories via Nginx (e.g., http://server-ip:8080 shows the frontend app).

server {
    listen       8080;  # Custom port to avoid conflicts (e.g., 80, 443)
    server_name  192.168.1.100;  # Replace with your server IP, localhost for local test

    # Frontend project (dist folder)
    location / {
        root   /usr/local/nginx/web/dist;  # Key: absolute path to your dist folder
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;  # Critical: solves SPA router refresh 404 (Vue history mode)
    }

    # Optional: separate image folder
    location /images/ {
        root   /usr/local/nginx/static;    # Actual path becomes /static/images/
        autoindex on;                      # Optional: enable directory listing
        expires 1d;                        # Optional: cache images 1 day
    }

    # Optional: separate document folder
    location /docs/ {
        root   /usr/local/nginx/static;    # Actual path becomes /static/docs/
        autoindex on;
        expires 7d;                        # Cache documents 7 days
    }
}

Three Beginner Traps:

Paths must be absolute (e.g., /usr/local/xxx), not relative ( ../dist), otherwise Nginx cannot locate files.

SPA router refresh 404: always include try_files $uri $uri/ /index.html;; omitting it causes blank pages.

After editing, run nginx -t to validate, then nginx -s reload to apply, then test access.

2. Reverse Proxy Configuration (Solves CORS, Hides Backend IP)

Scenario: Frontend calls backend APIs (e.g., http://127.0.0.1:8000/api) and hits CORS errors, or you want to hide the backend server IP for security.

Core Principle: Frontend requests Nginx; Nginx forwards to backend; backend responds to Nginx; Nginx returns to frontend. Nginx acts as a middleman.

server {
    listen       8080;  # Frontend access port (match frontend deployment port)
    server_name  localhost;  # Local test: localhost; production: IP/domain

    # Frontend static hosting (same as above)
    location / {
        root   /usr/local/nginx/web/dist;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    # Core: Reverse proxy backend APIs (all /api/* requests forwarded to backend)
    location /api/ {
        proxy_pass http://127.0.0.1:8000/;  # Key: replace with your backend address
        # Note: trailing / is mandatory, else path becomes /apiuser instead of /api/user
        proxy_set_header Host $host;                    # Pass request host
        proxy_set_header X-Real-IP $remote_addr;        # Pass real client IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # Pass proxy chain IPs
    }

    # Optional: proxy another backend (e.g., /backend/*)
    location /backend/ {
        proxy_pass http://192.168.1.101:9000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Two Reverse Proxy Gotchas: proxy_pass must end with / (e.g., http://127.0.0.1:8000/), otherwise the proxied path breaks.

CORS is resolved automatically: frontend now calls http://localhost:8080/api/xxx (no backend IP), eliminating cross-origin issues.

Test with curl http://localhost:8080/api/user; successful backend response confirms config works.

3. Multi-Site Configuration (Multiple Projects on One Server)

Scenario: One server hosts two frontend projects (e.g., personal blog + test project) or one frontend + one backend, without extra Nginx instances. Just add multiple server blocks inside the http block.

# First site: Personal blog (port 8081)
server {
    listen       8081;  # Unique port per site
    server_name  localhost;

    location / {
        root   /usr/local/nginx/web/blog;  # Blog project path
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
}

# Second site: Test project (port 8082)
server {
    listen       8082;  # Different port
    server_name  localhost;

    location / {
        root   /usr/local/nginx/web/test;  # Test project path
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    # Optional: second site's reverse proxy
    location /api/ {
        proxy_pass http://127.0.0.1:8001/;  # Second backend address
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Troubleshooting Configuration Errors (Covers 90% of Beginner Issues)

1. Validation Errors ( nginx -t Fails)

invalid number of arguments

→ Parameter syntax wrong (e.g., worker_processes typed as worker_process). unknown directive → Directive misspelled (e.g., proxy_passs). no such file or directory → Path incorrect (e.g., dist folder path wrong; verify absolute path).

General fix: Check the line number in the error message, compare with provided examples, correct spelling, paths, or missing semicolons.

2. Nginx Fails to Start ( nginx Command Errors)

# 1. Check error log (most effective, shows exact cause)
tail -f /usr/local/nginx/logs/error.log
# 2. Common causes and fixes:
# Cause 1: Port occupied → Kill occupying process or change server listen port
# Cause 2: Config file error → Re-run nginx -t, fix reported errors
# Cause 3: Permission denied → Linux: use sudo nginx; macOS: run without root

3. Browser Cannot Access (Nginx Runs but Returns 404/502/Timeout)

404: Either root path is wrong (Nginx can't find files) or missing try_files for SPA routing.

502: Reverse proxy misconfiguration; verify proxy_pass address is correct and backend service is running.

Timeout: Server firewall blocking the port; on Linux open with firewall-cmd --add-port=8080/tcp --permanent.

Closing Remarks

This second article fills the gaps from the previous one-click deployment guide. The three core configurations — static hosting, reverse proxy, multi-site — are copy-paste ready; just swap paths. Nginx configuration boils down to: remember the three-layer structure, apply the three patterns, and that covers daily needs.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

operationsDeploymentconfigurationtroubleshootingnginxreverse-proxystatic-hostingmulti-site
Engineer Tang's Implementation Study Notes
Written by

Engineer Tang's Implementation Study Notes

Old Tang | Pseudo-full-stack tech player: writes code without going bald, manages projects without going crazy, delivers without staying up late. No formal tutorials here, only a "slacking-off" practical manual that cures system pain points. Focuses on Shell, SQL, Java, and delivery, turning complexity into simplicity and making efficiency fun.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.