Install and configure NGINX with HTTP/3 and modern security headers

Intermediate 25 min Mar 31, 2026
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Set up NGINX with HTTP/3 and QUIC support for faster web performance. Configure SSL certificates, implement modern security headers like CSP and HSTS, and optimize for production workloads.

Prerequisites

  • Root access to server
  • Domain name with DNS configured
  • Ports 80 and 443 accessible

What this solves

HTTP/3 and QUIC protocol provide faster web performance by reducing connection latency and improving reliability over unstable networks. This tutorial shows you how to install NGINX with HTTP/3 support, configure SSL certificates, and implement modern security headers for production-grade web hosting.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest NGINX version with HTTP/3 support.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install required dependencies

Install build tools and dependencies needed for NGINX with HTTP/3 support.

sudo apt install -y curl gnupg2 ca-certificates lsb-release software-properties-common
sudo dnf install -y curl gnupg2 ca-certificates epel-release

Add NGINX official repository

Add the official NGINX repository to get the latest version with HTTP/3 support compiled with the necessary modules.

curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
sudo apt update
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo rpm --import -
sudo tee /etc/yum.repos.d/nginx.repo <

Install NGINX

Install NGINX from the official repository which includes HTTP/3 and QUIC support.

sudo apt install -y nginx
sudo dnf install -y nginx

Verify HTTP/3 support

Check that your NGINX installation includes HTTP/3 and QUIC support by examining the build configuration.

nginx -V 2>&1 | grep -o with-http_v3_module
nginx -V 2>&1 | grep -o with-http_quic_module

Install Certbot for SSL certificates

Install Certbot to automatically obtain and renew SSL certificates from Let's Encrypt.

sudo apt install -y certbot python3-certbot-nginx
sudo dnf install -y certbot python3-certbot-nginx

Configure firewall rules

Open the necessary ports for HTTP, HTTPS, and HTTP/3. HTTP/3 uses UDP port 443 instead of TCP.

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 443/udp
sudo ufw reload

Create initial server configuration

Create a basic server configuration file for your domain that will be enhanced with SSL and HTTP/3 support.

server {
    listen 80;
    server_name example.com www.example.com;
    
    location / {
        return 301 https://$server_name$request_uri;
    }
    
    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }
}

Create web root directory

Create the web root directory and set proper ownership for the web server to serve files.

sudo mkdir -p /var/www/html
sudo chown -R nginx:nginx /var/www/html
sudo chmod -R 755 /var/www/html
echo "

Welcome to NGINX with HTTP/3

" | sudo tee /var/www/html/index.html
Never use chmod 777. It gives every user on the system full access to your files. Instead, fix ownership with chown and use minimal permissions like 755 for directories and 644 for files.

Test and start NGINX

Test the configuration syntax and start NGINX service.

sudo nginx -t
sudo systemctl enable --now nginx
sudo systemctl status nginx

Obtain SSL certificate

Use Certbot to obtain SSL certificates from Let's Encrypt for your domain.

sudo certbot --nginx -d example.com -d www.example.com --non-interactive --agree-tos -m admin@example.com

Configure NGINX with HTTP/3 and security headers

Replace the Certbot-generated configuration with a production-ready setup including HTTP/3, QUIC, and modern security headers.

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen 443 quic reuseport;
    server_name example.com www.example.com;
    
    # SSL Configuration
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # HTTP/3 and QUIC Configuration
    add_header Alt-Svc 'h3=":443"; ma=86400' always;
    
    # Security Headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'self'" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always;
    
    # Performance Optimizations
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
    
    # Document Root
    root /var/www/html;
    index index.html index.htm;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    # Security: Deny access to hidden files
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

Configure main NGINX settings

Optimize the main NGINX configuration for better performance and HTTP/3 support.

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    # Logging
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time"';
    
    access_log /var/log/nginx/access.log main;
    
    # Performance Settings
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    keepalive_requests 100;
    client_max_body_size 20M;
    
    # Hide NGINX version
    server_tokens off;
    
    # Rate Limiting
    limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m;
    limit_req_zone $binary_remote_addr zone=general:10m rate=100r/m;
    
    include /etc/nginx/conf.d/*.conf;
}

Test and reload configuration

Validate the new configuration and reload NGINX to apply the changes.

sudo nginx -t
sudo systemctl reload nginx

Set up automatic certificate renewal

Configure automatic SSL certificate renewal to ensure your certificates stay valid.

sudo systemctl enable --now certbot.timer
sudo systemctl status certbot.timer
sudo certbot renew --dry-run

Verify your setup

Test that NGINX is working correctly with HTTP/3 support and security headers.

# Check NGINX status
sudo systemctl status nginx

Test HTTP/3 support with curl (if available)

curl -I --http3 https://example.com

Check security headers

curl -I https://example.com

Verify SSL certificate

ssl-cert-check -c /etc/letsencrypt/live/example.com/fullchain.pem

Test configuration syntax

sudo nginx -t

You can also use online tools like HTTP/3 Check (https://http3check.net) to verify HTTP/3 support and SSL Labs (https://www.ssllabs.com/ssltest/) to test your SSL configuration.

Performance optimization

Enable HTTP/3 prioritization

Configure HTTP/3 stream prioritization for better performance with multiple requests.

# HTTP/3 Optimization
http3_stream_buffer_size 64k;
http3_max_concurrent_pushes 20;
http3_push_preload on;

Configure caching headers

Add appropriate caching headers to improve performance for static assets.

    # Static file caching
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Vary "Accept-Encoding";
    }

Common issues

SymptomCauseFix
HTTP/3 not workingMissing QUIC/HTTP3 modulesCheck nginx -V for http_v3_module and reinstall from official repo
SSL certificate errorsFirewall blocking port 80Ensure ports 80 and 443 (TCP/UDP) are open: sudo ufw status
Configuration test failsSyntax errors in configRun sudo nginx -t and fix reported errors
Permission denied errorsIncorrect file ownershipsudo chown -R nginx:nginx /var/www/html && sudo chmod -R 755 /var/www/html
QUIC connection failsUDP port 443 blockedOpen UDP port 443: sudo ufw allow 443/udp
Security headers missingHeaders not appliedCheck add_header directives are in correct server block

Next steps

Automated install script

Run this to automate the entire setup

#nginx #http3 #quic #ssl #security-headers

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer