Skip to content

Instantly share code, notes, and snippets.

@tmkasun
Last active April 8, 2024 17:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tmkasun/10c4412b6ef4f13b878f490a9b11242e to your computer and use it in GitHub Desktop.
Save tmkasun/10c4412b6ef4f13b878f490a9b11242e to your computer and use it in GitHub Desktop.
How to configure Nginx to add CORS

This document explain how to

  • Generate SSL self sign certificate with subject alternative names using openssl tool
  • Configure nginx to add CORS OPTION call handler for none-cors endpoints

This gist is mostly for my future references 😄

  • First you need to have openssl configuration file to tell the tool what kind of certificate do you need, Following is a sample certificate file containing two SAN domains
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = LK
ST = WE
L = MyLocation
O = MyOrg
OU = MyOrgUnit
CN = sample.common.name.com
emailAddress = test@email.address
[v3_req]
keyUsage = digitalSignature,keyEncipherment, dataEncipherment
authorityKeyIdentifier=keyid,issuer
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = my.domain.one.com
DNS.2 = another.domain.com
  • Copy above content and save it as req.conf
  • Open terminal and type following command to generate private.key and public.crt public certificate
openssl req -x509 -sha256 -nodes -days 730 -newkey rsa:4096 -keyout private.key -out public.crt -config req.conf
  • if you want to know about the details of the parameters above read this article

    • openssl: This is the basic command line tool for creating and managing OpenSSL certificates, keys, and other files. req: This subcommand specifies that we want to use X.509 certificate signing request (CSR) management. The “X.509” is a public key infrastructure standard that SSL and TLS adheres to for its key and certificate management. We want to create a new X.509 cert, so we are using this subcommand.
    • x509: This further modifies the previous subcommand by telling the utility that we want to make a self-signed certificate instead of generating a certificate signing request, as would normally happen.
    • nodes: This tells OpenSSL to skip the option to secure our certificate with a passphrase. We need Nginx to be able to read the file, without user intervention, when the server starts up. A passphrase would prevent this from happening because we would have to enter it after every restart.
    • days 365: This option sets the length of time that the certificate will be considered valid. We set it for one year here.
    • newkey rsa:4096: This specifies that we want to generate a new certificate and a new key at the same time. We did not create the key that is required to sign the certificate in a previous step, so we need to create it along with the certificate. The rsa:4096 portion tells it to make an RSA key that is 4096 bits long.
    • keyout: This line tells OpenSSL where to place the generated private key file that we are creating.
    • out: This tells OpenSSL where to place the certificate that we are creating.
  • Now use the following nginx configuration to return 204 for CORS OPTIONS request (preflight) sent from browsers

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name sample.knnect.com;
    access_log /var/log/nginx/proxy.log;

    ssl_certificate /Users/user/testing/nginx/public.crt;
    ssl_certificate_key /Users/user/testing/nginx/private.key;
    ssl_session_timeout 5m;
    # ssl_protocols  SSLv2 SSLv3 TLSv1; # Old protocols
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    location / {
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '$http_origin';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            #
            # Custom headers and headers various browsers *should* be OK with but aren't
            #
            add_header 'Access-Control-Allow-Headers' '*';
            #
            # Tell client that this pre-flight info is valid for 20 days
            #
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }
        add_header 'Access-Control-Allow-Origin' '$http_origin' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
        proxy_pass https://localhost:9443/;
    }
}

  • Note the proxy_pass directive, There you have to provide the original service origin which does not have CORS capabilities
  • For nginx >= 1.7.5 always will work even with error response codes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment