Better PAM Authentication on Nginx using MySQL

Written by: Bagus Facsi Aginsa
Published at: 17 Apr 2020


People usually use PAM(Pluggable Authentication Module) on Nginx for Basic Authentication using the OS account. While it is very straightforward, it is very not safe practice in terms of security practice if you use the same user & password for the application and the OS.

People can visit your site again and again until they can break the password. And What if they can break the password? They can log in freely to your OS. Of course, you didn’t want this to happen.

There is a better way of using PAM Authentication on Nginx. It is by using MySQL database for managing the user account instead of using OS account.

Let’s see how we can do it.

Check Prerequisite

Before we start, let’s check the prerequisite first to make sure you can follow this tutorial

  1. Nginx installed, if you don’t have the Nginx yet, you can install it using apt install nginx, or you can Install Nginx from Source if you want.
  2. Mysql installed, if you don’t have MySQL yet, you can install it using apt install mysql-server
  3. Sudo Privilege, make sure you execute sudo su first to make sure we have no permission issue on the installation & configuration.

Install Nginx PAM Dependencies

We need to install some dependencies to make Nginx able to use PAM module.

apt install nginx-extras libpam-mysql

Add Configuration on NGINX

Open your virtual host config file on the Nginx folder

nano /etc/nginx/sites-available/my-site

Add auth_pam and auth_pam_service_name configuration on your server block or location block level to using pam authentication on Nginx. For example, if I want to use it at location block level:

. . .

location /secure {
    auth_pam "Restricted Zone";
    auth_pam_service_name "secure-nginx";

    . . .

}

location /user {

    . . .

}

. . .

This configuration will secure the /secure location block, but not the other. If a request comes to the /secure location block, Nginx will read secure-nginx service on the PAM folder to perform a basic authentication first before serving the request.

Add Configuraion on PAM

Create a file on /etc/pam.d/ that match auth_pam_service_name directive on the Nginx configuration file. In my case, it is secure-nginx.

nano /etc/pam.d/secure-nginx

Add this config to the file:

auth required pam_mysql.so user=your_db_user passwd=your_db_pass host=127.0.0.1 db=mail table=users usercolumn=email passwdcolumn=password crypt=3
account sufficient pam_mysql.so user=your_db_user passwd=your_db_pass host=127.0.0.1 db=mail table=users usercolumn=email passwdcolumn=password crypt=3

Change the highlighted text to suit your MySQL setup:

  1. user is the MySQL username
  2. passwd is the MySQL password
  3. host is the ip address of the MySQL Server
  4. db is the database name
  5. table is the table name that contains the user and password
  6. usercolumn is the column name that contains the user
  7. passwdcolumn is the column name that contains the user’s password
  8. crypt is the encryption method used on the password. the 3 is using md5 encryption. It is the most recommended one. I suggest you still use this value.

Restart NGINX

After the configuration is done, you can restart the Nginx.

service nginx restart

That’s it! Now you can create MySQL authentication on Nginx using PAM, a better way to use PAM authentication.