Skip to content

Instantly share code, notes, and snippets.

@zloynemec
Created April 15, 2015 12:29
Show Gist options
  • Save zloynemec/1e4680c4c9aa9cee8a6e to your computer and use it in GitHub Desktop.
Save zloynemec/1e4680c4c9aa9cee8a6e to your computer and use it in GitHub Desktop.
Secure adminer nginx setup
# Secure adminer setup
# Author Taras Kozlov
# download adminer to separate directory
mkdir -p /var/www/admin
cd /var/www/admin
wget http://www.adminer.org/latest.php -O adminer.php
echo '<?php phpinfo(); >' > info.php
sudo -i
# Generate self-signed certificate
mkdir -p /etc/nginx/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/admin.key -out /etc/nginx/ssl/admin.crt
# Generate htpasswd
apt-get install apache2-utils
mkdir -p /etc/nginx/.htpasswd
htpasswd -c /etc/nginx/.htpasswd/admin admin
# setup site to this directorty
# example site http://admin.example.com
nano /etc/nginx/sites-available/admin
server {
listen 80;
server_name admin.example.com;
return 301 https://$server_name$request_uri;
}
server {
server_name admin.example.com;
listen 443 ssl;
access_log /var/log/nginx/admin.access.log;
error_log /var/log/nginx/admin.error.log;
ssl_certificate /etc/nginx/ssl/admin.crt;
ssl_certificate_key /etc/nginx/ssl/admin.key;
root /var/www/admin;
index index.php;
# Get file here https://codex.wordpress.org/Nginx
include global/restrictions.conf;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd/admin;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
# enabling this site
cd /etc/nginx/sites-enabled
ln -s ../sites-available/admin admin
service nginx reload
@GerBreOwn
Copy link

Just followed this post and when I browse "localhost/adminer" I get a 404 error. What have I missed, as I thought I went through all steps.
Thanks

@ezriharmusial
Copy link

ezriharmusial commented Jul 18, 2018

The index file this Config file is refering to is named adminer.php not index.php. So either Change the /var/www/admin/adminer.php to /var/www/admin/index.php or replace the index.php notations in the config file to adminer.php and it will work.

@larrynalzaro
Copy link

Dang ... it works like a dream.

@LucioSaldivar
Copy link

This keeps failing for me. Is there any way to share a screen shot of the server block?

@larrynalzaro
Copy link

This keeps failing for me. Is there any way to share a screen shot of the server block?

Failing? Here's a screenshot:

scr

@LucioSaldivar
Copy link

where did you put the first Serve{}?? the one with the listen 80 and the return?

@larrynalzaro
Copy link

right above it ... here:

scr2

If you followed the setup described above there's no way it wouldn't work.

@ifthakharriyad
Copy link

Since nano /etc/nginx/sites-available/admin creates a directiory named admin in which file do I have to write the code below:

server {
    listen         80;
    server_name    admin.example.com;
    return         301 https://$server_name$request_uri;
}

server {
    server_name	   admin.example.com;
    listen	       443 ssl;
    access_log     /var/log/nginx/admin.access.log;
    error_log      /var/log/nginx/admin.error.log;

    ssl_certificate /etc/nginx/ssl/admin.crt;
    ssl_certificate_key /etc/nginx/ssl/admin.key;

    root           /var/www/admin;
    index          index.php;

    # Get file here https://codex.wordpress.org/Nginx
    include        global/restrictions.conf;

    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd/admin;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
    	try_files $uri =404;
    	fastcgi_split_path_info ^(.+\.php)(/.+)$;
    	fastcgi_pass php;
    	fastcgi_index index.php;
    	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    	include fastcgi_params;
    }
}

@ifthakharriyad
Copy link

Since nano /etc/nginx/sites-available/admin creates a directiory named admin in which file do I have to write the code below:

server {
    listen         80;
    server_name    admin.example.com;
    return         301 https://$server_name$request_uri;
}

server {
    server_name	   admin.example.com;
    listen	       443 ssl;
    access_log     /var/log/nginx/admin.access.log;
    error_log      /var/log/nginx/admin.error.log;

    ssl_certificate /etc/nginx/ssl/admin.crt;
    ssl_certificate_key /etc/nginx/ssl/admin.key;

    root           /var/www/admin;
    index          index.php;

    # Get file here https://codex.wordpress.org/Nginx
    include        global/restrictions.conf;

    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd/admin;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
    	try_files $uri =404;
    	fastcgi_split_path_info ^(.+\.php)(/.+)$;
    	fastcgi_pass php;
    	fastcgi_index index.php;
    	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    	include fastcgi_params;
    }
}

I have put this code to nginx.conf and followed everything mentioned and nginx is running but getting 404 error.
And localhost/adminer is redirecting to https://admin.example.com/adminer.

@larrynalzaro
Copy link

You got it wrong. It's not supposed to be a directory; it's a file and that's what its contents are supposed to be.

@ifthakharriyad
Copy link

It's supposed to be a file inside the /etc/nginx/sites-available/admin directory?
If so, what is the name of the file?

@larrynalzaro
Copy link

Noooo. It's just a file under /etc/nginx/sites-available.

@ifthakharriyad
Copy link

Okay. let me try with this. By the way, I have also changed the nginx.conf should I also undo the changes?

@ifthakharriyad
Copy link

ifthakharriyad commented Oct 29, 2021

Noooo. It's just a file under /etc/nginx/sites-available.

So, I can give the file name whatever I want to?
What extension the file need to have?

@larrynalzaro
Copy link

You can give it any name you want. No extension.

@ifthakharriyad
Copy link

Note: I am trying to set up adminer in my local machine.
@larrynalzaro Made the changes and nginx is running fine but still getting 404 error and redirected to https://admin.example.com/adminer:
image

@larrynalzaro
Copy link

Dude,

You're not getting it. Read the author's original post at the top of this thread. It's meant to be an example; you're supposed to modify it to conform to your needs. It's the same thing with the server block definition I posted: it's an example. You have to modify it according to your specific requirements.

@parmonov98
Copy link

I'm getting nginx 403 error!

@JaehaerysNL
Copy link

Thank you for this example configuration,

Literally only tweaked the adminer.conf provided with my own secure TLS setup.

I found that Adminer was much easier to install by reading this, since I already operate a Pterodactyl (Basically a Game Control Panel for game servers) instance I had things such as PHP (php 8.1 fpm) and the webserver (nginx) already.

For all the above who are failing to set it up, don't attempt this unless you already know how to operate a nginx webserver (with extensions)
The tutorial above does not work out of the box and requires you to already have knowledge outside the "box".

Certain requirements for Adminer are also used by Pterodactyl, you may visit their documentation at https://pterodactyl.io/panel/1.0/getting_started.html
(mostly regards the line below which includes Nginx, PHP v8.1 with extensions like FPM and MariaDB)
apt-get install php8.1 php8.1-{common,cli,gd,mysql,mbstring,bcmath,xml,fpm,curl,zip} mariadb-server nginx tar unzip git -y

My installation:
Ubuntu 20.04.4 LTS (Focal Fossa), but note it will probably work on 18.04 and 22.04 as well.
Nginx is in /etc/nginx/
Adminer Nginx config file is in /etc/nginx/sites-available/
Adminer Nginx config file is named adminer.conf (Full path = /etc/nginx/sites-available/adminer.conf
Adminer Nginx symlink is in /etc/nginx/sites-enabled/
Adminer Nginx symlink is also named adminer.conf and the symlinks points to /etc/nginx/sites-available/adminer.conf
If you do not know how to make a symlink, use a FTP client like FileZilla/WinSCP (with SFTP protocol) or look it up, I'm not gonna chew everything for ya.
Adminer's PHP file is located in /var/www/adminer/
Adminer's PHP file is simply named adminer.php (Full path = /var/www/adminer/adminer.php)

The configuration below is nearly identical to mine, except that I removed my domain name and added comments, BE SURE TO REPLACE IT WITH YOUR DOMAIN NAME! and make sure to point A and AAAA DNS records to whatever subdomain you will use for your Adminer interface, if you do not understand what this is, cancel installing this software now!

YOURDOMAIN.TLD is a PLACEHOLDER, replace it with your own domain blablabla.com example.ch whatever it is.
Also ignore that the TLS ciphersuites contain both TLS_ECDHE_ECDSA and TLS_ECDHE_RSA ciphers, I actually use both an ECC and RSA certificate so my webserver supports both types of ciphersuites (nginx will ignore the other type if you got an ECC or RSA TLS cert only!
For the not so techies, Do not use the term SSL, SSL was made obsolete two decades ago, call it by it's proper name, TLS.
SSL certificates => TLS certificates, or very techy term X.509 certificates (but you don't need to remember that)

# The section here enables HTTPS redirects on port 80, meaning all http:// is converted to https:// instead
server {
    listen 80;
    listen [::]:80;
    server_name adminer.YOURDOMAIN.TLD;
    return 301 https://$server_name$request_uri;
}

server {
    # listen on port 443 w/ TLS and enable HTTP/2
    listen 443 ssl http2;
    # Also listen on IPv6.
    listen [::]:443 ssl http2;
    server_name adminer.YOURDOMAIN.TLD;

    root /var/www/adminer;
    index adminer.php;
    access_log /var/log/nginx/adminer-access.log;
    error_log /var/log/nginx/adminer-error.log;

    # Your TLS certificate chain (chain is basically your cert + intermediate + root certificate, this can end up being a total of 3 or 4)
    # For Let's Encrypt this will be one of the following chains; CERT < R3 < ISRG Root X1 / CERT < R3 < ISRG Root X1 < DST Root CA X3 / CERT < E1 < ISRG Root X2 / CERT < E1 < ISRG Root X2 < ISRG Root X1
    ssl_certificate /etc/letsencrypt/live/YOURDOMAIN.TLD/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/YOURDOMAIN.TLD/privkey.pem;

    # This is for OCSP Stapling, HIGHLY recommended.
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/YOURDOMAIN.TLD/fullchain.pem;

    # Enable only TLS 1.2 and TLS 1.3, compatible and secure. do NOT ever enable the fundamentally insecure TLS 1.1 and 1.0 or even SSL 3.0!
    ssl_protocols TLSv1.2 TLSv1.3;
    # Turns off TLS 1.3's 0-RTT, which is weak against replay attacks.
    ssl_early_data off;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256";

    ssl_ecdh_curve X448:X25519:secp521r1:secp384r1;

    ssl_session_cache shared:MozSSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;

    gzip off;
    etag off;

    # NextDNS, if you do not have IPv6 support, comment the first resolver line and uncomment the second.
    resolver [2a07:a8c0::]:53 [2a07:a8c1::]:53 45.90.28.0:53 45.90.30.0:53;
    #resolver 45.90.28.0:53 45.90.30.0:53;
    resolver_timeout 600s;

    # See https://hstspreload.org/ before uncommenting the line below.
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
    #add_header Strict-Transport-Security "max-age=63072000;";
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Robots-Tag none;
    add_header Content-Security-Policy "frame-ancestors 'self'; upgrade-insecure-requests";
    # The line below is a fully secure CSP, but CSP is hard to configure properly without breaking anything, unless you know how to do it. You should not adjust the upper one.
    #add_header Content-Security-Policy "default-src 'self'; frame-src 'self'; frame-ancestors 'self'; script-src 'strict-dynamic'; style-src 'strict-dynamic'; frame-src 'img-src'; connect-src 'self'; font-src 'self'; object-src 'self'; media-src 'self'; upgrade-insecure-requests";
    add_header X-Frame-Options DENY;
    add_header Referrer-Policy no-referrer;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
    	try_files $uri =404;
    	fastcgi_split_path_info ^(.+\.php)(/.+)$;
    	fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    	fastcgi_index adminer.php;
    	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    	include fastcgi_params;
    }
}

Note that you can also find the same config file with clearer visibility at this pastebin:
https://bin.snopyta.org/?250941819203e2a6#HAMkJX7btYHmJxRjB3Ctf36ArgrHxQDBkkLTAFeScBiB

Always restart nginx after configuration changes with systemctl restart nginx
If a restart fails then diagnose the issue with systemctl status nginx
It should tell you what the problem is (eg wrong formatting in a nginx config, it will tell you which line and column)

It should be self explanatory that you need to install Certbot, acme.sh or anything of the like, in order to issue TLS certificates in the first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment