How to Properly Split Long Nginx Configuration Lines for Headers Like HPKP


2 views

When working with security headers like HTTP Public Key Pinning (HPKP) that require multiple pins, we often encounter extremely long configuration lines. These become difficult to maintain when they stretch beyond 200-300 characters in the nginx configuration.

# The problematic single-line approach
add_header Public-Key-Pins 'pin-sha256="X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg="; pin-sha256="MHJYVThihUrJcxW6wcqyOISTXIsInsdj3xK8QrZbHec="; pin-sha256="isi41AizREkLvvft0IRW4u3XMFR2Yg7bvrF7padyCJg="; pin-sha256="I/bAACUzdYEFNw2ZKRaypOyYvvOtqBzg21g9a5WVClg="; pin-sha256="Y4/Gxyck5JLLnC/zWHtSHfNljuMbOJi6dRQuRJTgYdo="; pin-sha256="/oCVQg3nP3DroGpFdAbaiYzenycUftqrH3LAyaIal2g=";';

1. The Concatenation Method

Nginx automatically concatenates strings when they are written consecutively in the configuration:

add_header Public-Key-Pins 
    'pin-sha256="X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg="; '
    'pin-sha256="MHJYVThihUrJcxW6wcqyOISTXIsInsdj3xK8QrZbHec="; '
    'pin-sha256="isi41AizREkLvvft0IRW4u3XMFR2Yg7bvrF7padyCJg="; '
    'pin-sha256="I/bAACUzdYEFNw2ZKRaypOyYvvOtqBzg21g9a5WVClg="; '
    'pin-sha256="Y4/Gxyck5JLLnC/zWHtSHfNljuMbOJi6dRQuRJTgYdo="; '
    'pin-sha256="/oCVQg3nP3DroGpFdAbaiYzenycUftqrH3LAyaIal2g=";';

2. Using Variables for Complex Configurations

For more complex scenarios or when you need to reuse parts of headers:

# Define variables for each pin
set $hpkp1 'pin-sha256="X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg="; ';
set $hpkp2 'pin-sha256="MHJYVThihUrJcxW6wcqyOISTXIsInsdj3xK8QrZbHec="; ';
set $hpkp3 'pin-sha256="isi41AizREkLvvft0IRW4u3XMFR2Yg7bvrF7padyCJg="; ';

# Combine them in the header
add_header Public-Key-Pins $hpkp1$hpkp2$hpkp3;

While nginx doesn't support inline comments in multi-line strings, you can document each part:

add_header Public-Key-Pins 
    # Current ECDSA key
    'pin-sha256="X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg="; '
    
    # Current RSA key
    'pin-sha256="MHJYVThihUrJcxW6wcqyOISTXIsInsdj3xK8QrZbHec="; '
    
    # Backup ECDSA key
    'pin-sha256="isi41AizREkLvvft0IRW4u3XMFR2Yg7bvrF7padyCJg="; '
    
    # More pins...
    'pin-sha256="I/bAACUzdYEFNw2ZKRaypOyYvvOtqBzg21g9a5WVClg="; '
    'pin-sha256="Y4/Gxyck5JLLnC/zWHtSHfNljuMbOJi6dRQuRJTgYdo="; '
    'pin-sha256="/oCVQg3nP3DroGpFdAbaiYzenycUftqrH3LAyaIal2g=";';

After implementing any of these solutions, verify the headers using curl:

curl -I https://yourdomain.com

The header should appear as a single line in the response, while remaining readable in your configuration file.


When configuring security headers like HPKP (HTTP Public Key Pinning) in Nginx, we often encounter extremely long header values that make config files hard to read and maintain. The ideal solution would allow:

# Human-readable multi-line format
pin-sha256="X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg=";
pin-sha256="MHJYVThihUrJcxW6wcqyOISTXIsInsdj3xK8QrZbHec=";
# While outputting as single line to browser

Common attempts that don't work properly:

1. Simple Line Breaks

add_header Public-Key-Pins '
pin-sha256="X3pGTS...";
pin-sha256="MHJYVT...";
';

Problem: Preserves newlines in the actual HTTP header

2. Backslash Escaping

add_header Public-Key-Pins ' \\
pin-sha256="X3pGTS..."; \\
pin-sha256="MHJYVT..."; \\
';

Problem: The backslashes appear in the output header

Nginx provides a clean way to handle this through variable concatenation:

set $hpkp_header "";
set $hpkp_header "${hpkp_header}pin-sha256=\"X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg=\"; ";
set $hpkp_header "${hpkp_header}pin-sha256=\"MHJYVThihUrJcxW6wcqyOISTXIsInsdj3xK8QrZbHec=\"; ";
# Add all other pins similarly

add_header Public-Key-Pins $hpkp_header;

For better documentation, we can organize with comments:

# Primary pins
set $hpkp_header "${hpkp_header}pin-sha256=\"X3pGTS...\"; "; # Current ECDSA
set $hpkp_header "${hpkp_header}pin-sha256=\"MHJYVT...\"; "; # Current RSA

# Backup pins
set $hpkp_header "${hpkp_header}pin-sha256=\"isi41A...\"; "; # Backup ECDSA 1
set $hpkp_header "${hpkp_header}pin-sha256=\"I/bAAC...\"; "; # Backup ECDSA 2

For complex configurations, consider splitting into separate files:

# In main nginx.conf
include /etc/nginx/hpkp.conf;

# In hpkp.conf
set $hpkp_header "pin-sha256=\"X3pGTS...\"; pin-sha256=\"MHJYVT...\";";
add_header Public-Key-Pins $hpkp_header;
  • Ensure no trailing whitespace in multi-line configs
  • Test with nginx -t after changes
  • Verify actual headers using curl -I
  • Remember HPKP is deprecated - consider using Expect-CT instead