Securing Websites With Nginx And Client-Side Certificate Authentication On Linux

Security in applications is usually a must have requirement—even when we’re considering a minimum viable product. Datastore backed authentication (think: every user with a username and password) takes time to setup and deploy. And that chews into the time you should be spending building your app and its features. There are many alternative solutions to this problem; however, not many of them are very secure. I’m looking at you static username and password! That’s why I’m going to provide a quick overview of a strategy for securing an app in a simplistic fashion without all of the overhead of using a datastore, setting up users, and facilitating their authentication.

Secrets and More Secrets

On the surface, website/server security is a complex topic dealing with a variety of standards, protocols, governing bodies and organizations. It can be a tricky subject for even the most experienced of engineers and technically-minded individuals. Although covering the background and foundation of website/server security is beyond the scope of this post, there are many excellent resources out there that will give you a good primer on the topic, including this video:

Want to sharpen your product acumen? Sign up for Product Hacks, a free monthly email that gives you exclusive, actionable product insights from the Arcweb Technologies team and around the web.

When To Use Client Side Certificate Authentication

Every so often, a company will find itself needing to limit server access to specific users in a way that is more secure than a simple username and password. For the majority of these cases, companies will create an Access Control List (ACL) that helps to identify who has access. Many ACL schemes work based on the IP address of the device accessing the server. This mechanism is great when you have a network where IP addresses don’t change, such as a corporate network or VPN. However, the minute that IP addresses start changing, an IP-based ACL becomes a nightmare for both administration and maintenance.

The scheme that we’re addressing here uses client-side SSL certificates to authenticate user access to a server resource. The certificates are managed on a per-user basis by a central Certification Authority (CA) and can be revoked at any time. In the following paragraphs, I’ll walk you through the basics of setting up your own CA, issuing user certificates, and setting up Nginx to validate the client certificates.

(On a side note, this article would not be possible without the work of Ryan Pendergast.)


To make this demo work, you’ll need the following:

A Linux Server Instance with…

1. OpenSSL (latest version to ensure that you have all of the patches available)

2. Nginx (> v1.8.7)

Setting Up a Certificate Authority (CA)

To get started, we’ll first need to setup a CA on the server. This is a pretty simple proposition. Whenever you install OpenSSL on the server, a default CA is already configured and ready to go. The easiest path forward is to modify this configuration. The following sample configuration can be implemented in the OpenSSL configuration:

One of the biggest points of confusion that I had when setting this up is that a lot of examples use the CA to issue a certificate for the Nginx server. It makes it seem like there is a necessary relationship between the CA and Nginx. Beyond Nginx needing to know that the CA is supposed to validate client certificates (more on that later), there is no need for a tie between the two.

Making the CA Configuration Legit

Now that we’ve got the configuration created, it’s time to add all of these files that we’ve told OpenSSL exist.

The first place to start is the directory structure. As the root user, you’ll create all of the directories mentioned above using the following command:

Next, we’ll create the reference files for the configuration. The database index file can be created empty. The CRL number file, on the other hand, will be expected by OpenSSL to have the first number in it:

Finally, we’ll create our server certificates and the certificate revocation list for the CA. We’ll set an expiration of one year in our example. Set yours as your corporate policy dictates.

Creating SSL Certificates For Users

If we’ve done everything correctly, then creating a certificate for a new user should work without a hitch. To create a new user, you’ll the following sequence of commands:

When running these commands, it is the recommended approach to use the full name of the user that the certificate is being issued to. Additionally, you should make use of the user’s e-mail address to create a more readily identifiable certificate for when people have the same name. Finally, be sure to replace “USERNAME” with the name of the user that you’re creating the certificate for.

I place these commands inside of a script as recommended by Ryan Pendergast (referenced in the article that I linked to at the beginning of this post). Doing so makes it much easier and faster to create new users. All you have to do is run the script, use SFTP to retrieve the *.P12 certificate from the server, and send the user their certificate for installation.

Configuring Nginx

Once you’ve generated a certificate (how else are you going to test site access if you don’t?), you’re ready to move on to configuring Nginx. The client verification is set in Nginx’s server section as part of a site’s SSL settings. My personal recommendation is always to use the most secure options possible when it comes to SSL. I frequently check my configs with SSL Labs excellent site checker ( The following example site configuration is based on a Unicorn/Nginx configuration that I built a while back with the aid of their tool:

The only changes that I needed to make to get Nginx to respect our CA were the specification of values for the “ssl_client_certificate”, “ssl_crl”, “ssl_verify_client” and “ssl_session_timeout” options. The remainder of the configuration was all part of the standard configuration that I would apply to any Unicorn site. Outside of the application’s server-specific requirements, your configuration should look very similar.

Pulling It All Together

Once you’ve completed configuration and installed your *.P12 certificate as your browser/OS dictate, you’re ready to start testing. If you’ve done everything correctly, you should be able to restart Nginx and browse to your website. Your browser will detect that SSL client verification is required and ask you to pick a certificate for authentication. If you do not pick the correct certificate, you will receive a 400 error from Nginx. If, however, you select the correct certificate, you will be granted access to the site and everything that lies within.

Revoking Certificates

On one final note, as with all exercises, it’s important to be practical and know that things change. Inevitably there will come a time when someone leaves your team and their certificate needs to be invalidated. Running the following script with the correct username will add the user’s certificate to the revocation list and ensure that they can no longer access the site:

2 Responses

  1. Tim

    Hi Jordan,

    From the NGINX configuration file above, you have the following settings:
    ssl_certificate /etc/ssl/certs/not_self_signed.crt;
    ssl_certificate_key /etc/ssl/private/not_self_signed.key;

    Do these “not_self_signed” files have any relation with the newly created Certificate Authority?
    Don’t the client and server files have to be signed by the same certificate authority? It doesn’t seem like you do this anywhere in the article.


Leave a Reply