Skip to content

使用 Nginx 基础认证保护 Nuxt 预发布环境

适用场景

在正式发布前,你需要一个内部测试环境灰度预览环境,只允许团队成员或特定用户访问,避免被搜索引擎抓取或被外部用户误入。

💡 什么是 Nginx 基础认证

Nginx 基础认证(HTTP Basic Authentication)是一种简单的访问控制方法,通过用户名和密码验证用户身份。搭配 Cloudflare 或防火墙规则,可以实现「白名单 + 密码」双重保护。

前置条件

1. 安装 apache2-utils 工具

htpasswd 命令包含在 apache2-utils 包中,用于生成加密密码:

bash
sudo apt-get update
sudo apt-get install -y apache2-utils

验证安装:

bash
htpasswd -h

2. 创建密码文件

创建密码文件并添加第一个用户

bash
# 创建密码文件(-c 表示创建新文件)
sudo htpasswd -c /etc/nginx/.htpasswd your-username

# 系统会提示输入密码两次

添加更多用户(不需要 -c 参数)

bash
# 追加用户到已有密码文件
sudo htpasswd /etc/nginx/.htpasswd another-username

查看密码文件内容

bash
sudo cat /etc/nginx/.htpasswd
# 输出示例:
# your-username:$apr1$randomhash$xxxxxxxxxxxxx

删除用户

bash
# 使用 sed 删除指定用户
sudo sed -i '/username-to-delete/d' /etc/nginx/.htpasswd

3. 配置 Nginx 基础认证

方案一:保护整个站点

编辑您的 Nginx 配置文件(如 /etc/nginx/sites-available/myapp):

nginx
server {
    listen 80;
    server_name pre.your-domain.com;

    # 基础认证配置
    auth_basic "Restricted Access - Internal Only";
    auth_basic_user_file /etc/nginx/.htpasswd;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        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;
    }
}

方案二:保护特定路径

如果只希望保护管理后台或特定路径:

nginx
server {
    listen 80;
    server_name your-domain.com;

    location / {
        # 公开访问
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
    }

    location /admin {
        # 需要认证
        auth_basic "Admin Area - Restricted";
        auth_basic_user_file /etc/nginx/.htpasswd;

        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
    }

    location /preview {
        # 需要认证
        auth_basic "Preview Area - Internal Only";
        auth_basic_user_file /etc/nginx/.htpasswd;

        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
    }
}

方案三:预发布环境 + IP 白名单双重保护

结合 IP 白名单,实现更精细的访问控制:

nginx
server {
    listen 80;
    server_name pre.your-domain.com;

    location / {
        # 允许特定 IP 直接访问(无需密码)
        allow 192.168.1.0/24;      # 公司内网
        allow 10.0.0.0/8;          # 企业内网
        allow 203.0.113.100;       # 特定公网 IP

        # 其他 IP 需要密码认证
        auth_basic "Restricted Access";
        auth_basic_user_file /etc/nginx/.htpasswd;

        # 拒绝所有未匹配的 IP(这条很重要)
        deny all;

        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

4. 完整配置示例(预发布环境)

以下是针对预发布环境的完整配置示例:

nginx
# /etc/nginx/sites-available/preview
server {
    listen 80;
    server_name preview.your-domain.com;

    # 日志记录
    access_log /var/log/nginx/preview-access.log;
    error_log /var/log/nginx/preview-error.log;

    # 基础认证
    auth_basic "Preview Environment - Internal Access Only";
    auth_basic_user_file /etc/nginx/.htpasswd;

    # 自定义认证提示信息(可选)
    auth_basic_user_file /etc/nginx/.htpasswd;

    # 超时配置(预发布环境方便调试)
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        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;
    }

    # 静态资源(仍需要认证,但可以缓存)
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf)$ {
        auth_basic "Restricted Access";
        auth_basic_user_file /etc/nginx/.htpasswd;

        proxy_pass http://127.0.0.1:3000;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # 错误页面(避免泄露信息)
    error_page 401 /401.html;
    location = /401.html {
        auth_basic off;
        return 401 '<html><body><h1>Authentication Required</h1><p>This is a private preview environment.</p></body></html>';
    }
}

5. 启用配置并重启

bash
# 测试配置语法
sudo nginx -t

# 重启 Nginx
sudo systemctl restart nginx

6. 测试访问

浏览器访问

在浏览器中访问 http://preview.your-domain.com,会弹出登录框:

  • 用户名:你创建的用户名
  • 密码:你设置的密码

命令行测试

bash
# 无认证访问(应返回 401 Unauthorized)
curl -i http://preview.your-domain.com

# 带认证访问
curl -u username:password http://preview.your-domain.com

# 应返回 200 OK

7. 配合 Cloudflare 使用(HTTPS + 认证)

如果您使用 Cloudflare,可以同时启用 HTTPS 和基础认证:

nginx
# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name preview.your-domain.com;
    return 301 https://$server_name$request_uri;
}

# HTTPS 配置
server {
    listen 443 ssl http2;
    server_name preview.your-domain.com;

    # Cloudflare Origin CA 证书
    ssl_certificate /etc/nginx/ssl/your-domain.pem;
    ssl_certificate_key /etc/nginx/ssl/your-domain.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_timeout 1d;

    # 基础认证
    auth_basic "Preview Environment - Internal Only";
    auth_basic_user_file /etc/nginx/.htpasswd;

    # Cloudflare 真实 IP
    set_real_ip_from 173.245.48.0/20;
    # ... 其他 Cloudflare IP 范围 ...
    real_ip_header CF-Connecting-IP;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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 https;
    }
}

8. 高级配置技巧

配置认证超时

默认情况下,浏览器会缓存认证信息直到关闭。可以通过以下方式控制:

nginx
# 添加认证过期时间(浏览器支持)
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/.htpasswd;

# 添加自定义响应头
add_header Cache-Control "no-store, must-revalidate";

自定义登录失败提示

nginx
# 自定义 401 错误页面
error_page 401 = @error401;
location @error401 {
    auth_basic off;
    add_header WWW-Authenticate 'Basic realm="Restricted Access"';
    return 401 '<html><body>
        <h1>Access Denied</h1>
        <p>This preview environment is restricted to internal users only.</p>
        <p>Please contact the development team for access.</p>
    </body></html>';
}

多层级认证

nginx
# 外层基础认证
auth_basic "Outer Protection";
auth_basic_user_file /etc/nginx/.htpasswd-outer;

location / {
    # 内层额外认证
    auth_basic "Inner Protection";
    auth_basic_user_file /etc/nginx/.htpasswd-inner;

    proxy_pass http://127.0.0.1:3000;
}

9. 密码管理最佳实践

生成强密码

bash
# 使用 openssl 生成随机密码(24位)
openssl rand -base64 24

# 使用 htpasswd 指定 bcrypt 加密(更安全)
htpasswd -B -c /etc/nginx/.htpasswd username

定期轮换密码

bash
#!/bin/bash
# update-htpasswd.sh
# 定期更新密码脚本

PASSWORD=$(openssl rand -base64 16)
echo "newuser:$(openssl passwd -6 $PASSWORD)" | sudo tee -a /etc/nginx/.htpasswd
echo "New password for newuser: $PASSWORD"

# 通知团队成员(通过 Slack、邮件等)
# curl -X POST -H 'Content-type: application/json' --data '{"text":"Preview password updated"}' your-webhook-url

sudo nginx -t && sudo systemctl reload nginx

安全的密码文件权限

bash
# 确保密码文件权限正确
sudo chmod 640 /etc/nginx/.htpasswd
sudo chown root:www-data /etc/nginx/.htpasswd

# 验证权限
ls -la /etc/nginx/.htpasswd
# 应输出:-rw-r----- 1 root www-data ...

10. 与自动部署脚本集成

在之前文章的 deploy.sh 基础上,增加预发布环境的部署:

bash
#!/bin/bash
# deploy-preview.sh - 部署到预发布环境

SERVER="root@your-server-ip"
APP_PATH="/var/www/preview-app"
PM2_NAME="preview-app"

# 构建
echo "📦 Building preview..."
pnpm build

# 打包
echo "📁 Packaging..."
tar -czf deploy.tar.gz -C .output .

# 上传
echo "📤 Uploading..."
scp deploy.tar.gz $SERVER:$APP_PATH/

# 部署并确保基础认证配置生效
ssh $SERVER "cd $APP_PATH && \
    tar -xzf deploy.tar.gz && \
    pm2 reload $PM2_NAME && \
    rm deploy.tar.gz && \
    echo '✅ Preview deployment complete!'"

rm deploy.tar.gz

11. 常见问题处理

Q1: 浏览器不弹出登录框

原因:可能是认证配置语法错误或密码文件路径不对。

bash
# 检查 Nginx 配置
sudo nginx -t

# 检查密码文件
sudo cat /etc/nginx/.htpasswd

# 检查 Nginx 错误日志
sudo tail -f /var/log/nginx/error.log

Q2: 登录后仍然 401

原因:密码错误或加密方式不兼容。

bash
# 重新生成密码(使用 MD5 加密,兼容性最好)
sudo htpasswd -c /etc/nginx/.htpasswd username

# 重启 Nginx
sudo systemctl restart nginx

Q3: 静态资源也被认证拦截

解决方案:将静态资源路径配置为不需要认证:

nginx
location /_nuxt/ {
    auth_basic off;
    proxy_pass http://127.0.0.1:3000;
}

Q4: 如何临时禁用认证

nginx
# 注释掉认证相关配置即可
# auth_basic "Restricted Access";
# auth_basic_user_file /etc/nginx/.htpasswd;

# 重载配置
sudo nginx -s reload

12. 安全建议

建议说明
使用 HTTPS基础认证的密码是 Base64 编码,必须配合 HTTPS 使用
限制 IP结合 IP 白名单,减少密码暴露风险
定期轮换定期更换密码,特别是人员变动时
使用强密码密码至少 16 位,包含大小写字母、数字、特殊字符
日志监控监控 access.log,发现异常访问及时处理
不用于高敏感场景基础认证适合预发布环境,生产环境建议使用 OAuth/JWT

结语

通过 Nginx 基础认证,你可以快速搭建一个受保护的预发布环境,让团队成员在安全的环境中进行测试和验收。

这种方案的优势在于:

  • 零代码改动:无需修改 Nuxt 应用代码
  • 配置简单:几行 Nginx 配置即可完成
  • 即时生效:修改配置后 nginx -s reload 即可
  • 资源占用低:Nginx 原生支持,性能影响极小

配合上一篇文章的完整部署流程,你可以轻松实现:

  • 生产环境:公开访问 + Cloudflare CDN
  • 预发布环境:密码保护 + IP 白名单

延伸阅读