在 Ubuntu VPS 上安装与配置 Nginx:静态网站、反向代理与 SSL

Nginx(发音为"engine-x")是全球部署最广泛的网络服务器之一,Netflix、Airbnb、GitHub 等高流量网站都在使用它。其事件驱动、非阻塞架构使单个工作进程无需大量资源即可处理数万个并发连接。本教程将带你从零开始在 Ubuntu 22.04 VPS 上安装 Nginx,涵盖静态文件服务、虚拟主机、Node.js 反向代理、Let's Encrypt SSL、Gzip 压缩以及基础安全响应头等内容。

Nginx 是什么?与 Apache 有何不同?

Apache 和 Nginx 都是主流的网络服务器,但它们处理连接的方式从根本上有所不同。

Apache:基于进程 / 线程的模型

Apache 采用基于进程(或线程)的并发模型。每收到一个请求,就会新建一个进程或线程。当并发量较高时(例如 1,000 个同时连接),Apache 会创建 1,000 个进程或线程,消耗大量内存与 CPU。这种模型对动态内容和 .htaccess 灵活性支持较好,但在高负载下扩展效率较低。

Nginx:事件驱动、非阻塞

Nginx 采用事件驱动、非阻塞 I/O 模型。单个工作进程可通过事件队列同时管理数千个连接,而无需逐一阻塞等待。在相同流量负载下,Nginx 的内存占用通常远低于 Apache。

如何选择?如果你在 VPS 上运行 Node.js、Python(Django/Flask)或 PHP-FPM,并需要一个轻量级反向代理,Nginx 是更合适的选择。如果你依赖 DirectAdmin 面板或需要每目录 .htaccess 覆盖,Apache 可能更方便。

在 Ubuntu 22.04 上安装 Nginx

通过 SSH 连接到你的 VPS,然后运行以下命令安装并启动 Nginx。

第一步:更新软件包索引并安装

apt update && apt install nginx -y

第二步:启用并启动服务

systemctl enable nginx
systemctl start nginx

enable 命令确保 Nginx 在服务器重启后自动运行,start 命令则立即启动服务。

第三步:检查状态与 80 端口

# Check that Nginx is running
systemctl status nginx

# Confirm Port 80 is listening
ss -tlnp | grep :80

# If using UFW, open HTTP and HTTPS
ufw allow 'Nginx Full'
ufw status

打开浏览器,访问你的 VPS IP 地址,例如 http://123.456.789.0。如果看到"Welcome to nginx!"页面,说明安装成功。

Nginx 文件结构概览

在修改配置之前,了解文件布局能为你节省大量排查问题的时间。

/etc/nginx/
├── nginx.conf              # Main config file (global settings)
├── conf.d/                 # Auto-included configs (custom global settings)
├── sites-available/        # All virtual host definitions (stored but not yet active)
│   └── default             # Default virtual host
├── sites-enabled/          # Symlinks to active virtual hosts
│   └── default -> ../sites-available/default
├── modules-available/      # Available modules
├── modules-enabled/        # Loaded modules
└── snippets/               # Reusable config fragments (e.g. SSL params)

为静态网站配置虚拟主机

在 Nginx 术语中,"虚拟主机"称为 server block(服务器块)。它告知 Nginx 响应哪个域名、文件存放在哪里,以及如何处理请求。

创建网站根目录

# Create the document root
mkdir -p /var/www/mysite.com/html

# Set ownership to www-data (the user Nginx runs as)
chown -R www-data:www-data /var/www/mysite.com

# Set appropriate permissions
chmod -R 755 /var/www/mysite.com

创建服务器块配置文件

nano /etc/nginx/sites-available/mysite.conf

添加以下内容,将 mysite.com 替换为你的域名。

server {
    listen 80;
    listen [::]:80;

    server_name mysite.com www.mysite.com;

    root /var/www/mysite.com/html;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }

    # Block access to hidden files (e.g. .env, .git)
    location ~ /\. {
        deny all;
    }

    # Log files
    access_log /var/log/nginx/mysite.com.access.log;
    error_log  /var/log/nginx/mysite.com.error.log;
}

启用虚拟主机并重新加载

# Create a symlink from sites-available to sites-enabled
ln -s /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/

# Test the config for syntax errors (very important!)
nginx -t

# If the test passes, reload gracefully (no downtime)
systemctl reload nginx

重要提示:每次执行 systemctl reload nginx 之前,务必先运行 nginx -t。若配置文件存在语法错误而直接重载,Nginx 可能无法启动,导致网站宕机。

静态文件服务:root、index、try_files 与 location 块

以下几个关键指令控制 Nginx 如何提供静态内容。这里是一个扩展示例,为静态资源添加了缓存响应头。

server {
    listen 80;
    server_name mysite.com www.mysite.com;

    root /var/www/mysite.com/html;

    # Files to serve when the request path is a directory
    index index.html index.htm;

    # Primary location: try exact file, then directory, then 404
    location / {
        try_files $uri $uri/ =404;
    }

    # Cache images and static assets for 30 days
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    # Block hidden files
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

Nginx 作为 Node.js / PHP-FPM 的反向代理

Nginx 最常见的用途之一是充当反向代理——位于应用服务器(Node.js、Python、PHP-FPM)前端,转发请求并处理 TLS 终止、缓存和压缩。

Node.js 反向代理

server {
    listen 80;
    server_name myapp.com www.myapp.com;

    location / {
        proxy_pass http://localhost:3000;

        # Forward original headers to the application
        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;

        # Timeout settings
        proxy_connect_timeout 60s;
        proxy_send_timeout    60s;
        proxy_read_timeout    60s;
    }
}

负载均衡的 Upstream 块

若你运行多个应用实例(例如 Node.js 集群或多台应用服务器),可使用 upstream 块在它们之间分发流量。

# Define the upstream group before the server block
upstream myapp_backend {
    # Round-robin by default
    server localhost:3000;
    server localhost:3001;
    server localhost:3002;

    # Reuse connections with keepalive
    keepalive 16;
}

server {
    listen 80;
    server_name myapp.com www.myapp.com;

    location / {
        proxy_pass http://myapp_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";  # Required for keepalive upstream
        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;
    }
}

PHP-FPM 反向代理

server {
    listen 80;
    server_name myphp.com www.myphp.com;

    root /var/www/myphp.com/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Pass PHP files to PHP-FPM
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}

使用 Let's Encrypt 和 Certbot 配置 SSL

Let's Encrypt 是一家免费的证书颁发机构,可自动签发 SSL 证书。Certbot 是官方客户端,能够与 Nginx 直接集成,通过一条命令完成证书的申请与安装。

第一步:安装 Certbot

apt install certbot python3-certbot-nginx -y

第二步:申请证书并自动配置 Nginx

# Replace example.com with your domain
# Certbot will update nginx config automatically and redirect HTTP to HTTPS
certbot --nginx -d example.com -d www.example.com

Certbot 会提示输入邮箱地址(用于证书到期通知),并询问是否将所有 HTTP 流量重定向至 HTTPS。强烈建议选择重定向。

第三步:验证自动续签

Certbot 会安装一个 systemd 定时器(或 cron 任务),在证书到期前自动续签。通过模拟续签(dry run)验证其正常运行。

# Test renewal without actually renewing
certbot renew --dry-run

# Check the systemd timer status
systemctl status certbot.timer

# Or check the cron entry (depending on your system)
cat /etc/cron.d/certbot

Let's Encrypt 证书有效期为 90 天。当剩余有效期不足 30 天时,Certbot 会自动续签。

前提条件:运行 Certbot 之前,域名的 DNS A 记录必须已指向你的 VPS IP 地址。若域名未解析到该服务器,Certbot 的域名所有权验证(ACME challenge)将会失败。

Nginx 的 Gzip 压缩

启用 Gzip 压缩可将传输文件大小缩减 60–80%,显著提升 HTML、CSS、JS 和 JSON 响应的页面加载速度。

将以下内容添加到 /etc/nginx/nginx.confhttp 块中,或在 /etc/nginx/conf.d/gzip.conf 创建专用配置文件。

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types
    text/plain
    text/css
    text/xml
    text/javascript
    application/json
    application/javascript
    application/x-javascript
    application/xml
    application/xml+rss
    application/xhtml+xml
    image/svg+xml
    font/woff
    font/woff2;

Nginx 的安全响应头

添加安全相关的响应头可防御常见攻击向量,如点击劫持、MIME 类型嗅探和信息泄露。将以下内容添加到 server 块内。

server {
    # ... other config ...

    # Prevent clickjacking (disallow embedding in iframes from other origins)
    add_header X-Frame-Options "SAMEORIGIN" always;

    # Prevent MIME type sniffing
    add_header X-Content-Type-Options "nosniff" always;

    # Control the referrer sent to third-party sites
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Legacy XSS protection for older browsers
    add_header X-XSS-Protection "1; mode=block" always;

    # Force HTTPS for the duration of max-age (requires SSL to be working first)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Hide the Nginx version number from response headers
    server_tokens off;
}

注意:仅在确认 HTTPS 配置正常运行后,再添加 Strict-Transport-Security(HSTS)。一旦设置,浏览器将在整个 max-age 期间拒绝 HTTP 连接——若 SSL 出现问题,用户将无法访问网站。

测试配置与安全重载

Nginx 内置配置测试功能,在每次重载或重启前务必运行,以防止因配置错误导致服务中断。

# Test config syntax without touching the running server
nginx -t

# Expected output on success:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

# Graceful reload (zero downtime — serves in-flight requests until complete)
systemctl reload nginx

# Full restart (brief downtime — use only when necessary)
systemctl restart nginx

# Tail the error log in real time
tail -f /var/log/nginx/error.log

# Tail the access log in real time
tail -f /var/log/nginx/access.log

重载 vs 重启:systemctl reload nginx 执行优雅重载——Nginx 以更新后的配置 fork 出新的工作进程,同时旧进程继续处理进行中的请求,实现零停机。而 restart 会完全停止并重新启动 Nginx,可能中断活跃连接。

常见问题与解决方法

502 Bad Gateway

此错误表示 Nginx 无法连接到后端(Node.js 或 PHP-FPM 已停止,或端口配置错误)。

# Check that the backend service is running
systemctl status php8.2-fpm
# Or for Node.js
ps aux | grep node

# Confirm the backend is listening on the expected port
ss -tlnp | grep 3000

# Review Nginx error logs
tail -100 /var/log/nginx/error.log

# Restart the backend
systemctl restart php8.2-fpm

权限被拒绝(403 Forbidden)

通常由文件或目录权限不正确引起,也可能是 AppArmor/SELinux 阻止了访问。

# Check ownership of files in the document root
ls -la /var/www/mysite.com/

# Fix ownership for www-data
chown -R www-data:www-data /var/www/mysite.com/

# Set correct permissions: directories 755, files 644
find /var/www/mysite.com/ -type d -exec chmod 755 {} \;
find /var/www/mysite.com/ -type f -exec chmod 644 {} \;

配置语法错误

编辑出错后会发生此问题。nginx -t 将失败,Nginx 会拒绝重载。

# Run to see the exact error and line number
nginx -t

# Common error messages:
# nginx: [emerg] unexpected "}" — missing semicolon on a previous line
# nginx: [emerg] "server" directive is not allowed here — block is in the wrong place
# nginx: [emerg] host not found in upstream — upstream name or port is wrong

# If Nginx stopped entirely, restore the last known-good config
# then fix the error and start again

Nginx 显示默认页面而非你的网站

# Check that the symlink exists in sites-enabled
ls -la /etc/nginx/sites-enabled/

# Verify the server_name matches your domain
grep server_name /etc/nginx/sites-available/mysite.conf

# Remove the default site if it is interfering
rm /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx

准备好在自己的 VPS 上运行 Nginx 了吗?

AsiaGB VPS 提供完整的 root 权限,几分钟内即可安装 Nginx、Node.js 或 PHP-FPM。Linux VPS 套餐起价 750 泰铢/月,数据中心位于泰国和新加坡。

查看 AsiaGB VPS 套餐