Nginx Configuration: Force HTTPS for Specific Path While Keeping Others HTTP


2 views

When implementing security measures on a web application, we often need to enforce HTTPS for sensitive paths while keeping other sections accessible via HTTP. This is particularly common when:

  • Implementing user account sections (/user/*) with HTTPS
  • Maintaining public content sections with HTTP
  • Optimizing performance for non-sensitive content

Here's the recommended server block configuration that avoids conditional statements (if) and potential redirect loops:

server {
    listen 80;
    server_name example.com;
    
    # HTTPS enforcement for /user path
    location /user {
        return 301 https://$host$request_uri;
    }
    
    # All other paths remain HTTP
    location / {
        # Your regular HTTP configuration
        try_files $uri $uri/ =404;
    }
}

server {
    listen 443 ssl;
    server_name example.com;
    
    # SSL configuration here
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    # Only allow HTTPS for /user path
    location / {
        return 301 http://$host$request_uri;
    }
    
    location /user {
        # Your secure content configuration
        try_files $uri $uri/ =404;
    }
}

For more complex scenarios, consider these variations:

Multiple Protected Paths

location ~ ^/(user|account|settings) {
    return 301 https://$host$request_uri;
}

Preserving Query Strings

location /user {
    return 301 https://$host$request_uri$is_args$args;
}

The 301 redirect is cached by browsers, reducing subsequent redirect overhead. For production environments:

  • Always test redirect chains
  • Monitor for mixed content warnings
  • Consider HSTS headers for the secure paths

Watch out for these potential problems:

  1. Redirect loops - ensure your HTTPS server block doesn't redirect back
  2. Cookie security - set Secure flag for cookies in /user section
  3. Mixed content - ensure assets in /user section are loaded via HTTPS

When implementing security measures on a website, we often need granular control over SSL enforcement. A common scenario is requiring HTTPS only for sensitive sections (like /user paths) while allowing standard HTTP for other content. This approach balances security and performance.

Many developers initially try using if statements in Nginx configurations, but this can lead to:

  • Performance overhead
  • Unexpected behavior in complex scenarios
  • Potential redirect loops

Here's the recommended server block configuration that cleanly handles path-specific SSL requirements:

server {
    listen 80;
    server_name example.com;

    # Force SSL for /user paths
    location /user {
        return 301 https://$host$request_uri;
    }

    # All other paths remain HTTP
    location / {
        # Your regular HTTP configuration
        root /var/www/html;
        index index.html;
    }
}

server {
    listen 443 ssl;
    server_name example.com;

    # SSL configuration
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # Handle SSL-protected paths
    location /user {
        # Your secure content configuration
        root /var/www/secure;
        try_files $uri $uri/ =404;
    }

    # Redirect non-/user paths back to HTTP
    location / {
        return 301 http://$host$request_uri;
    }
}

1. Separate Server Blocks: Maintain distinct blocks for HTTP (port 80) and HTTPS (port 443) traffic

2. Path-Specific Directives: Use location blocks to target specific URL paths

3. Bidirectional Redirection:

  • HTTP → HTTPS for protected paths
  • HTTPS → HTTP for non-protected paths

For more complex setups with multiple protected paths:

# HTTP server block
server {
    listen 80;
    
    # Multiple protected paths
    location ~ ^/(user|account|checkout) {
        return 301 https://$host$request_uri;
    }
    
    # Static content exception
    location ~* \.(jpg|png|css|js)$ {
        expires 30d;
    }
}

# HTTPS server block
server {
    listen 443 ssl;
    
    location ~ ^/(user|account|checkout) {
        # Additional security headers
        add_header Strict-Transport-Security "max-age=31536000" always;
        # Application-specific configuration
        proxy_pass http://backend_app;
    }
}

1. Use return 301 instead of rewrite for permanent redirects

2. Consider caching static assets even on non-SSL paths

3. Implement proper HSTS headers only for SSL-protected paths

Redirect Loops: Ensure your SSL server block doesn't accidentally catch non-SSL paths

Mixed Content Warnings: Verify all resources in SSL-protected paths use HTTPS URLs

Cookie Security: Set Secure flag for cookies used in protected areas