# nginx reverse proxy for CalendarServer
# run command:
# sudo nginx -g "daemon off;" -p @CALENDARSERVERDIR@/Library/CalendarServer/logs -c @CALENDARSERVERDIR@/Library/CalendarServer/etc/nginx.conf

user  @CALENDARSERVERUSER@ _calendar;

worker_processes  auto;

error_log  ../logs/nginx_error.log;
#error_log  ../logs/error.log  notice;
#error_log  ../logs/error.log  info;

pid  ../run/nginx.pid;

events {
    worker_connections  1024;
}

# To use macOS Server v5.10 generated certificates:
#
# 0. Identify the file that looks like @host@.@domain@.@tld@.@CERTIFICATE_SHA1@.cert.pem
# and verify its issue date and issuer "* Intermediate CA" with:
#
# $ ls /etc/certificates
# $ openssl x509 -inform pem -in /etc/certificates/@host@.@domain@.@tld@.@CERTIFICATE_SHA1@.cert.pem -text -noout
# $ openssl x509 -noout -fingerprint -sha1 -inform pem -in openssl x509 -noout -fingerprint -sha1 -inform pem -in /etc/certificates/@host@.@domain@.@tld@.@CERTIFICATE_SHA1@.cert.pem | tr -d ':' | sed -e 's|^SHA1 Fingerprint=||' | tr -d ':' | sed -e 's|^SHA1 Fingerprint=||'
# 
# Use this SHA1 to obtain the passphraphse for this certificate's private key from:
#
# Keychain Access.app> System> Search for this SHA1>
#   Double-click "Mac OS X Server certificate management"> Show password
#
# 1. Create a secure storage for this passphrase and desctrypted key:
# 
# $ sudo mkdir -p @PREFIX@/etc/certificates/private
# $ sudo chmod 0700 @PREFIX@/etc/certificates/private
# $ sudo vi @PREFIX@/etc/certificates/private/@host@.@domain@.@tld@.@CERTIFICATE_SHA1@.key.pem.passphrase /etc/certificates/private
# $ sudo chmod -R go-rwx @PREFIX@/etc/certificates/private
# 
# `ssl_key_password` wasn't working on my install, so put the decrypted key in @PREFIX@/etc/certificates/private
# 
# $ sudo openssl rsa -in /etc/certificates/@host@.@domain@.@tld@.@CERTIFICATE_SHA1@.key.pem -out @PREFIX@/etc/certificates/private/@host@.@domain@.@tld@.@CERTIFICATE_SHA1@.key.pem.decrypted -passin file:@PREFIX@/etc/certificates/private/@host@.@domain@.@tld@.@CERTIFICATE_SHA1@.key.pem.passphrase
# $ sudo chmod -R go-rwx @PREFIX@/etc/certificates/private
# 
# 2. Link to the existing TLS chain.
#
# $ sudo ln -s /etc/certificates/@host@.@domain@.@tld@.@CERTIFICATE_SHA1@.cert.pem @PREFIX@/etc/certificates
# $ sudo ln -s /etc/certificates/@host@.@domain@.@tld@.@CERTIFICATE_SHA1@.key.pem @PREFIX@/etc/certificates
# $ sudo ln -s /etc/certificates/@host@.@domain@.@tld@.@CERTIFICATE_SHA1@.chain.pem @PREFIX@/etc/certificates
# $ sudo ln -s /etc/certificates/@host@.@domain@.@tld@.@CERTIFICATE_SHA1@.concat.pem @PREFIX@/etc/certificates
# 
# 3. Confirm restricted permissions:
#
# $ ls -l @PREFIX@/etc/certificates
# $ sudo ls -l @PREFIX@/etc/certificates/private
#
# 4. Finally, reconfigure dovecot's conf.d/10-ssl.conf, postfix's master.cf,
# and, if installed, calendar-contacts-server's proxy nginx.conf:
#
# $ sudo vi @PREFIX@/etc/dovecot/conf.d/10-ssl.conf
# $ sudo vi @PREFIX@/etc/postfix/main.cf
# $ sudo vi @PREFIX@/var/calendarserver/Library/CalendarServer/etc/nginx.conf

http {
    include       @PREFIX@/etc/nginx/mime.types;
    default_type  application/octet-stream;

    server_tokens  off;

    #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  ../logs/nginx_access.log;

    client_max_body_size 20M;

    upstream caldavd_secured {
        server unix:@CALENDARSERVERDIR@/Library/CalendarServer/run/caldavd_requests/secured.sock;
    }

    upstream caldavd_unsecured {
        server unix:@CALENDARSERVERDIR@/Library/CalendarServer/run/caldavd_requests/unsecured.sock;
    }

    # Reverse proxy for CalendarServer
    server {
        root nginx_root;  # empty except for (unused) default.html
        # TLS
        listen @host@.@domain@.@tld@:8443 ssl;  # calDAV
        listen @host@.@domain@.@tld@:8843 ssl;  # cardDAV
        server_name @host@.@domain@.@tld@;
        # ssl_certificate must contain the cert:intermed[:root CA] chain
        ssl_certificate      @PREFIX@/etc/certificates/@TLS_CERTIFICATE_NAME@.chain.pem;
        ssl_certificate_key  @PREFIX@/etc/certificates/private/@TLS_CERTIFICATE_NAME@.key.pem.decrypted;

        # use modern crypto
        # https://wiki.mozilla.org/Security/Server_Side_TLS
        # https://cipherli.st
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
        ssl_prefer_server_ciphers  on;
        ssl_dhparam          dhparam.pem;
        ssl_ecdh_curve       secp384r1;
        ssl_session_timeout  10m;
        ssl_session_cache    shared:SSL:10m;
        ssl_session_tickets  off;
        # nginx: [warn] "ssl_stapling" ignored, no OCSP responder URL in the certificate
        # ssl_stapling         on;
        # ssl_stapling_verify  on;

        location / {
            proxy_pass http://caldavd_secured;
            # proxy_pass https://localhost:8443;
            # caldav issues "Bad Request 404" without turning off "Connection: close" header and setting HTTP/1.1
            proxy_set_header Connection   "";
            proxy_http_version            1.1;
            # proxy_set_header Host         $host;
            # the proxy is a unix socket
            proxy_ssl_protocols           TLSv1 TLSv1.1 TLSv1.2;
            proxy_ssl_ciphers             HIGH:!aNULL:!MD5;
            # proxy_ssl_certificate      @CALENDARSERVERDIR@/Source/github/apple/ccs-calendarserver.build/twistedcaldav/test/data/cert.pem;
            # proxy_ssl_certificate_key  @CALENDARSERVERDIR@/Source/github/apple/ccs-calendarserver.build/twistedcaldav/test/data/server.pem;
            # proxy_ssl_trusted_certificate @CALENDARSERVERDIR@/Source/github/apple/ccs-calendarserver.build/twistedcaldav/test/data/cert.pem;
            proxy_ssl_server_name         on;
            # proxy_ssl_verify              on;
            # turn this off for expired test certificate
            proxy_ssl_verify              off;
            proxy_ssl_verify_depth        2;
            proxy_ssl_session_reuse       on;
        }
    }

    server {
        root nginx_root;  # empty except for (unused) default.html
        # HTTP
        listen @host@.@domain@.@tld@:8008;      # calDAV
        listen @host@.@domain@.@tld@:8800;      # cardDAV
        server_name @host@.@domain@.@tld@;

        # quick alternate test
        # ncat -vlk 8800 -c 'ncat -U /path/to/unix_socket.sock'

        location / {
            proxy_pass http://caldavd_unsecured;
            # proxy_pass http://localhost:8008;
            # caldav issues "Bad Request 404" without turning off "Connection: close" header and setting HTTP/1.1
            proxy_set_header Connection   "";
            proxy_http_version            1.1;
            # proxy_set_header Host         $host;
        }
    }
}
