Trace: nginx

Nginx

This is an old revision of the document!


Nginx

Usage with acme.sh

1. You need to create a blank site.

server {
    server_tokens off;
    listen 80;
    listen [::]:80;
    server_name example.com;
    
    location ^~ /.well-known/acme-challenge/ {
        default_type "text/plain";
        root /var/www/acme-challenge/;
    }
}

Don't forget to link and restart nginx.

2. Install acme.sh to get a cert.

curl  https://get.acme.sh | sh

3. Get a cert.

acme.sh --issue -d example.com -w /var/www/acme-challenge/

Note: if you plan to use wildcard, then do this:

acme.sh --issue -d example.com -d '*.example.com' --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please
acme.sh --renew -d example.com -d '*.example.com' --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please

4. Copy the cert to nginx folder.

acme.sh --install-cert -d example.com \
--key-file       /etc/nginx/ssl/example.com.key  \
--fullchain-file /etc/nginx/ssl/example.com.crt \
--reloadcmd     "service nginx force-reload"

5. Rewrite the site's config file.

Here is an example secure conf.

nginx.conf
# This file default locate at /etc/nginx/nginx.conf in Linux.
user www-data;
pid /run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;

events {
    multi_accept on;
    worker_connections 65535;
}

http {
    charset utf-8;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    server_tokens off;
    log_not_found off;
    types_hash_max_size 2048;
    client_max_body_size 16M;

    # MIME
    include mime.types;
    default_type application/octet-stream;

    # logging
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;

    # SSL
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;

    # Mozilla Modern configuration
    ssl_protocols TLSv1.3;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 1.0.0.1 valid=60s;
    resolver_timeout 2s;

    # load configs
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}
<code>

<code - example.com>
server {
    server_tokens off;
    listen 80;
    listen [::]:80;
    server_name example.com;
    
    location ^~ /.well-known/acme-challenge/ {
        default_type "text/plain";
        root /var/www/acme-challenge/;
    }

    return 301 https://$host$request_uri;
}
server {
    server_tokens off;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;
    
    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 "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ssl.google-analytics.com https://assets.zendesk.com https://connect.facebook.net; img-src 'self' https://ssl.google-analytics.com https://s-static.ak.facebook.com https://assets.zendesk.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://assets.zendesk.com; font-src 'self' https://themes.googleusercontent.com; frame-src https://assets.zendesk.com https://www.facebook.com https://s-static.ak.facebook.com https://tautt.zendesk.com; object-src 'none'";
    # Or
    add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;

    # enables server-side protection from BEAST attacks
    # http://blog.ivanristic.com/2013/09/is-beast-still-a-threat.html
    ssl_prefer_server_ciphers on;
    # disable SSLv3(enabled by default since nginx 0.8.19) since it's less secure then TLS http://en.wikipedia.org/wiki/Secure_Sockets_Layer#SSL_3.0
    # ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    # Update 2019-05-08: Uses TLSv1.3 only, this requires nginx >= 1.13.0 else use TLS1.2
    ssl_protocols TLSv1.3;
    # ciphers chosen for forward secrecy and compatibility
    # http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html
    ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
    # Or this:
    # ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
    ssl_ecdh_curve secp384r1;

    # enable ocsp stapling (mechanism by which a site can convey certificate revocation information to visitors in a privacy-preserving, scalable manner)
    # http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox/
    resolver 1.1.1.1 1.0.0.1 valid=60s;
    resolver_timeout 5s;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/nginx/ssl/example.com.crt;

    set $base /home/wwwroot/example.com;
    root $base;
    index index.php index.html;

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
        fastcgi_buffers 8 16k;
        fastcgi_buffer_size 32k;
        # fastcgi params
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param PHP_ADMIN_VALUE "open_basedir=$base/:/usr/lib/php/:/tmp/";
    }

    location ~ /\.ht {
       deny all;
    }
    
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }
    
    location = /robots.txt {
        log_not_found off;
        access_log off;
    }
    
    # assets, media
    location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
        expires 7d;
        access_log off;
    }

    # svg, fonts
    location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {
        add_header Access-Control-Allow-Origin "*";
        expires 7d;
        access_log off;
    }
    
    # gzip
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;

    ssl_certificate /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;

}

dhparam.pem

Diffie–Hellman key exchange (DH) is a method of securely exchanging cryptographic keys over a public channel and was one of the first public-key protocols as originally conceptualized by Ralph Merkle and named after Whitfield Diffie and Martin Hellman. DH is one of the earliest practical examples of public key exchange implemented within the field of cryptography. (Source: Wikipedia)

openssl dhparam -out dhparam.pem 4096

If your openssl or nginx still uses a lot of CPU after that, then use:

openssl dhparam -dsaparam -out dhparam.pem 4096

Things that might help you out: Cipherli.st & Mozilla SSL Configuration Generator

Cool stuff

Colorful OpenDirectory

    # You need to install nginx-extras on Debian / Ubuntu.
    location / {
        autoindex on;
        fancyindex on;
        fancyindex_exact_size off;
    }

Connectivity Detection

    # Apple CNA
    location /hotspot-detect.html {
        return 200 '<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>';
        add_header Content-Type text/html;
    }

    # Apple CNA
    location /library/test/success.html {
        return 200 '<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>';
        add_header Content-Type text/html;
    }

    # ChromeOS
    location /generate_204 {
        return 204;
    }

    # Windows connectivity detection (http://blog.superuser.com/2011/05/16/windows-7-network-awareness/)
    location /ncsi.txt {
        return 200 'Microsoft NCSI';
    }

Reverse Proxy

    location / {
        proxy_pass http://127.0.0.1:8080/;
        proxy_set_header Host $http_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 $scheme;
        client_max_body_size 0;
    }

log

    log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/example_com_access.log;
    error_log /var/log/nginx/example_com_error.log warn;

Ban direct access

1. Just modify default

default
server {
   listen 80 default_server;
   listen [::]:80 default_server;

   server_name _;

   return 304;
}

server {
    listen 443 default_server;
    listen [::]:443 default_server;
    server_name _;
    ssl on;
    ssl_certificate /etc/nginx/ssl/null/null.crt;
    ssl_certificate_key /etc/nginx/ssl/null/null.key;
    return 304;
}

2. Generate a self-signed certificate

openssl req -x509 -nodes -days 7305 -newkey rsa:2048 -keyout /etc/nginx/ssl/null/null.key -out /etc/nginx/ssl/null/null.crt