Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
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
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
C = LK
L = MyLocation
O = MyOrg
OU = MyOrgUnit
CN =
emailAddress = test@email.address
keyUsage = digitalSignature,keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
DNS.1 =
DNS.2 =
  • 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;
    access_log  /var/log/nginx/proxy.log;

    ssl_certificate      /path/to/public/certificate.crt;
    ssl_certificate_key  /path/to/private/certificaet.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' '*';
        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' '*';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';


  • Note the proxy_pass directive, There you have to provide the original service origin which does not have CORS capabilities
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.