Skip to content

Nginx Basic Authentication: Adding Access Control to the Nuxt Staging Environment ​

Use cases

Before the official release, you need a Internal test environment or Canary preview environment, only team members or specific users are allowed to access, preventing search engine crawling or accidental access by external users.

💡 What is Nginx Basic Authentication

Nginx Basic Authentication (HTTP Basic Authentication) is a simple access control method that verifies user identity via username and password. Combined with Cloudflare or firewall rules, it can achieve "whitelist + password" double protection.

Precondition ​

1. Install the apache2-utils tool ​

htpasswd The command is contained in apache2-utils in the package, used to generate encrypted passwords:

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

Verify installation:

bash
htpasswd -h

2. Create a password file ​

Create a password file and add the first user. ​

bash
# Create password file (-c means create a new file)
sudo htpasswd -c /etc/nginx/.htpasswd your-username

# The system will prompt you to enter the password twice.

Add more users (no -c parameter required) ​

bash
# Append user to existing password file
sudo htpasswd /etc/nginx/.htpasswd another-username

View password file contents ​

bash
sudo cat /etc/nginx/.htpasswd
# Output example:
# your-username:$apr1$randomhash$xxxxxxxxxxxxx

Delete user ​

bash
# Use sed to delete the specified user
sudo sed -i '/username-to-delete/d' /etc/nginx/.htpasswd

3. Configure Nginx basic authentication ​

Option 1: Protect the entire site ​

Edit your Nginx configuration file (e.g./etc/nginx/sites-available/myapp):

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

    # Basic authentication configuration
    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;
    }
}

Option 2: Protect specific paths ​

If you only want to protect the admin backend or specific paths:

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

    location / {
        # public access
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
    }

    location /admin {
        # Authentication required
        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 {
        # Authentication required
        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;
    }
}

Option 3: Staging environment + IP whitelist dual protection ​

Combine with an IP whitelist to achieve more granular access control:

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

    location / {
        # Allow specific IPs to access directly (no password required)
        allow 192.168.1.0/24;      # Company intranet
        allow 10.0.0.0/8;          # enterprise intranet
        allow 203.0.113.100;       # Specific public IP

        # Other IPs require password authentication
        auth_basic "Restricted Access";
        auth_basic_user_file /etc/nginx/.htpasswd;

        # Reject all unmatched IPs (this is very important)
        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. Complete configuration example (staging environment) ​

The following is a complete configuration example for the pre-release environment:

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

    # Logging
    access_log /var/log/nginx/preview-access.log;
    error_log /var/log/nginx/preview-error.log;

    # Basic Authentication
    auth_basic "Preview Environment - Internal Access Only";
    auth_basic_user_file /etc/nginx/.htpasswd;

    # Custom authentication prompt (optional)
    auth_basic_user_file /etc/nginx/.htpasswd;

    # Timeout configuration (convenient for debugging in the pre-release environment)
    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;
    }

    # Static resources (still require authentication, but can be cached)
    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 (avoid leaking information)
    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. Enable the configuration and restart ​

bash
# Test configuration syntax
sudo nginx -t

# Restart Nginx
sudo systemctl restart nginx

6. Test access ​

Browser access ​

Visit in the browser http://preview.your-domain.com, a login box will pop up:

  • Username: The username you created

  • Password: the password you set

Command-line test ​

bash
# Access without authentication (should return 401 Unauthorized)
curl -i http://preview.your-domain.com

# Authenticated access
curl -u username:password http://preview.your-domain.com

# Should return 200 OK

7. Using with Cloudflare (HTTPS + Authentication) ​

If you use Cloudflare, you can enable both HTTPS and Basic Authentication:

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

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

    # Cloudflare Origin CA certificate
    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;

    # Basic Authentication
    auth_basic "Preview Environment - Internal Only";
    auth_basic_user_file /etc/nginx/.htpasswd;

    # Cloudflare real IP
    set_real_ip_from 173.245.48.0/20;
    # ... other Cloudflare IP ranges ...
    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. Advanced Configuration Tips ​

Configure authentication timeout ​

By default, the browser caches authentication information until it is closed. This can be controlled in the following ways:

nginx
# Add authentication expiration time (browser support)
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/.htpasswd;

# Add custom response headers
add_header Cache-Control "no-store, must-revalidate";

Custom login failure prompt ​

nginx
# Custom 401 error page
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>';
}

Multi-level authentication ​

nginx
# Outer basic authentication
auth_basic "Outer Protection";
auth_basic_user_file /etc/nginx/.htpasswd-outer;

location / {
    # Inner-layer additional authentication
    auth_basic "Inner Protection";
    auth_basic_user_file /etc/nginx/.htpasswd-inner;

    proxy_pass http://127.0.0.1:3000;
}

9. Password Management Best Practices ​

Generate a strong password ​

bash
# Use openssl to generate a random password (24 characters)
openssl rand -base64 24

# Use htpasswd to specify bcrypt encryption (more secure)
htpasswd -B -c /etc/nginx/.htpasswd username

Regular password rotation ​

bash
#!/bin/bash
# update-htpasswd.sh
# Script for regularly updating passwords

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

# Notify team members (via Slack, email, etc.)
# curl -X POST -H 'Content-type: application/json' --data '{"text":"Preview password updated"}' your-webhook-url

sudo nginx -t && sudo systemctl reload nginx

Secure password file permissions ​

bash
# Ensure the password file permissions are correct.
sudo chmod 640 /etc/nginx/.htpasswd
sudo chown root:www-data /etc/nginx/.htpasswd

# Verify permissions
ls -la /etc/nginx/.htpasswd
# Should output: -rw-r----- 1 root www-data ...

10. Integration with automated deployment scripts ​

In the previous article's deploy.sh On this basis, add pre-release environment deployment:

bash
#!/bin/bash
# deploy-preview.sh - Deploy to the pre-release environment

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

# Build
echo "📦 Building preview..."
pnpm build

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

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

# Deploy and ensure the basic authentication configuration takes effect
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. Common Troubleshooting ​

Q1: The browser does not pop up a login dialog box. ​

Reason: It may be a syntax error in the authentication configuration or the password file path is incorrect.

bash
# Check Nginx configuration
sudo nginx -t

# Check the password file
sudo cat /etc/nginx/.htpasswd

# Check the Nginx error log
sudo tail -f /var/log/nginx/error.log

Q2: Still 401 after login ​

Reason: Incorrect password or incompatible encryption method.

bash
# Regenerate password (using MD5 encryption, best compatibility)
sudo htpasswd -c /etc/nginx/.htpasswd username

# Restart Nginx
sudo systemctl restart nginx

Q3: Static resources are also intercepted by authentication. ​

Solution Configure static resource paths to not require authentication:

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

Q4: How to temporarily disable authentication ​

nginx
# Just comment out the authentication-related configuration.
# auth_basic "Restricted Access";
# auth_basic_user_file /etc/nginx/.htpasswd;

# Reload configuration
sudo nginx -s reload

12. Security Recommendations ​

SuggestionExplanation
Use HTTPSThe password for basic authentication is Base64-encoded and must be used with HTTPS.
Restrict IPCombine with an IP whitelist to reduce the risk of password exposure.
Periodic rotationChange passwords regularly, especially when there are personnel changes.
Use a strong passwordPassword must be at least 16 characters and include uppercase and lowercase letters, numbers, and special characters.
Log MonitoringMonitoring access.log, and promptly handle any abnormal access upon discovery
Not for highly sensitive scenariosBasic authentication is suitable for pre-release environments; for production environments, OAuth/JWT is recommended.

Conclusion ​

Using Nginx basic authentication, you can quickly set up a protected staging environment, allowing team members to conduct testing and acceptance in a secure environment.

The advantage of this approach lies in:

  • Zero code changes: No need to modify Nuxt application code

  • Simple configuration It can be done with just a few lines of Nginx configuration.

  • Effective immediately: After modifying the configuration nginx -s reload is enough

  • Low resource usage: Native Nginx support, minimal performance impact

Combined with the complete deployment process in the previous article, you can easily achieve:

  • Production environment: public access + Cloudflare CDN

  • Staging environment: password protection + IP whitelist

Further reading

Last updated on11/07/2026, 02:16 PM
@fishfinal | @fishfinals | [email protected]