Install and Secure phpMyAdmin with Nginx on Debian 13
Managing your MySQL/MariaDB databases via the command line is powerful but not always practical. phpMyAdmin provides you with a web interface to view, modify, and administer your databases without typing SQL queries by hand. The problem is that if misconfigured, phpMyAdmin becomes a gateway for attacks.
This guide shows you how to properly install phpMyAdmin behind Nginx on Debian 13 (Trixie), with HTTPS, access restrictions, and protections against brute force attacks. A configuration designed for production, not just for a test lab.
What You Need Before You Start
- A Debian 13 (Trixie) server with sudo access
- Ports 80 and 443 open
- A domain name pointing to your server (recommended for HTTPS)
Debian 13 comes with PHP 8.3 by default. Check your version:
php -v
Note the version number, you will need it for the configuration file paths.
Update the System
We always start with this:
sudo apt update && sudo apt -y full-upgrade
sudo reboot
Install Nginx, PHP-FPM, and Necessary Extensions
sudo apt install -y nginx php-fpm php-cli php-mbstring php-xml php-zip php-curl php-mysql php-gd php-intl php-bcmath
sudo apt install -y php-imagick php-apcu
Check that the PHP-FPM socket exists:
ls -l /run/php/ | grep fpm
# You should see something like: php8.3-fpm.sock
Install and Secure MariaDB
sudo apt install -y mariadb-server mariadb-client
sudo mysql_secure_installation
During the security assistant:
- Set a strong SQL root password
- Remove anonymous users
- Disable remote root login
- Remove the test database
- Reload privileges
Create a Dedicated User for phpMyAdmin
Using the SQL root account for phpMyAdmin is a bad idea. Create a dedicated admin account:
sudo mysql
In the SQL shell:
CREATE USER 'pma_admin'@'localhost' IDENTIFIED BY 'YourStrongPassword!';
GRANT ALL PRIVILEGES ON *.* TO 'pma_admin'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EXIT;
This is the account you will use to log in to phpMyAdmin.
Install phpMyAdmin
Two options depending on your preferences.
Option A: via apt (simple and quick)
sudo apt install -y phpmyadmin
During the installation:
- When asked about the web server, do not check anything (we configure Nginx manually)
- Accept dbconfig-common and set a password for the internal user
pma
The files are installed in /usr/share/phpmyadmin.
Option B: via the official archive (newer version)
cd /var/www
sudo mkdir -p pma && cd pma
wget https://files.phpmyadmin.net/phpMyAdmin/5.2.1/phpMyAdmin-5.2.1-all-languages.tar.gz
sudo tar xzf phpMyAdmin-*-all-languages.tar.gz
sudo mv phpMyAdmin-*-all-languages phpmyadmin
sudo chown -R www-data:www-data /var/www/pma/phpmyadmin
Create the configuration file:
sudo -u www-data cp /var/www/pma/phpmyadmin/config.sample.inc.php /var/www/pma/phpmyadmin/config.inc.php
sudo -u www-data nano /var/www/pma/phpmyadmin/config.inc.php
Generate a secret key of at least 32 characters and add it:
$cfg['blowfish_secret'] = 'PutAUniqueAndLongSecretPhraseHere!!!!';
Configure Nginx
Two possible approaches: an alias /phpmyadmin on an existing vhost, or a dedicated subdomain pma.yourdomain.com. The latter is cleaner for managing access restrictions.
Option A: Alias on an existing vhost
Add these blocks to your existing Nginx configuration:
location /phpmyadmin {
alias /usr/share/phpmyadmin; # or /var/www/pma/phpmyadmin if using method B
index index.php;
try_files $uri $uri/ /phpmyadmin/index.php?$args;
}
location ~ ^/phpmyadmin/(.+\.php)$ {
alias /usr/share/phpmyadmin;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_read_timeout 120s;
}
location ~* ^/phpmyadmin/(.+\.(?:png|jpg|jpeg|gif|css|js|ico|svg))$ {
alias /usr/share/phpmyadmin;
access_log off;
expires 7d;
}
Option B: Dedicated subdomain (recommended)
Create /etc/nginx/sites-available/pma.conf:
server {
listen 80;
server_name pma.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name pma.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/pma.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pma.yourdomain.com/privkey.pem;
root /usr/share/phpmyadmin;
index index.php;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy no-referrer-when-downgrade always;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 120s;
}
location ~* \.(?:css|js|ico|gif|jpe?g|png|svg)$ {
access_log off;
expires 7d;
}
}
Enable the config and test:
sudo ln -s /etc/nginx/sites-available/pma.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Enable HTTPS with Let's Encrypt
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d pma.yourdomain.com
Check that automatic renewal is active:
systemctl status certbot.timer Secure phpMyAdmin
Block Access to /setup
location ^~ /phpmyadmin/setup { deny all; }
# or for a dedicated vhost:
location ^~ /setup { deny all; }
Disable AllowArbitraryServer
In config.inc.php, ensure this option is disabled to prevent SSRF attacks:
$cfg['AllowArbitraryServer'] = false;
Adjust PHP Limits
To be able to import large databases, edit /etc/php/8.3/fpm/php.ini:
upload_max_filesize = 512M
post_max_size = 512M
max_execution_time = 300
memory_limit = 512M
Restart PHP-FPM:
sudo systemctl restart php8.3-fpm
Restrict Access by IP and HTTP Password
IP Whitelist
location /phpmyadmin {
allow 203.0.113.10; # your fixed IP
deny all;
alias /usr/share/phpmyadmin;
index index.php;
}
HTTP Basic Authentication
Create the password file:
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd-pma admin
Add to the Nginx config:
location /phpmyadmin {
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/.htpasswd-pma;
alias /usr/share/phpmyadmin;
index index.php;
try_files $uri $uri/ /phpmyadmin/index.php?$args;
}
Tip: Combine IP whitelist + HTTP auth for a double layer of security.
Protect Against Brute Force with Fail2ban
Rate-limit Nginx
In /etc/nginx/nginx.conf, add in the http block:
limit_req_zone $binary_remote_addr zone=pma_limit:10m rate=5r/s;
In your server block:
location /phpmyadmin/ {
limit_req zone=pma_limit burst=20 nodelay;
}
Configure Fail2ban
sudo apt install -y fail2ban
Create the filter /etc/fail2ban/filter.d/nginx-phpmyadmin.conf:
[Definition]
failregex = ^<HOST> - .* "(GET|POST) /phpmyadmin.*" .* (401|403) .*$
ignoreregex =
Create the jail /etc/fail2ban/jail.d/nginx-phpmyadmin.local:
[nginx-phpmyadmin]
enabled = true
port = http,https
filter = nginx-phpmyadmin
logpath = /var/log/nginx/access.log
maxretry = 8
findtime = 10m
bantime = 1h
Restart Fail2ban:
sudo systemctl restart fail2ban
sudo fail2ban-client status nginx-phpmyadmin
Enable the UFW Firewall
sudo apt install -y ufw
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status
Common Troubleshooting
502 Bad Gateway Error
The PHP-FPM socket is not accessible. Check:
ls -l /run/php/php8.3-fpm.sock
sudo systemctl status php8.3-fpm
403 Forbidden Error
Permission or configuration issue with alias/root. Ensure the folder belongs to www-data:
sudo chown -R www-data:www-data /usr/share/phpmyadmin
Timeout on Large Imports
Increase client_max_body_size in the Nginx server block and fastcgi_read_timeout.
Invalid CSRF Token
Ensure that the blowfish_secret is set, that cookies are working, and that the system clock is synchronized (timedatectl).
Final Checklist
- Updated Debian 13 system
- Functional Nginx and PHP-FPM 8.3
- Secured MariaDB with
mysql_secure_installation - phpMyAdmin accessible via HTTPS
- Restricted access (IP and/or HTTP Auth)
- Rate-limit and Fail2ban active
- Configured UFW firewall
- Scheduled backups
In Summary
Installing phpMyAdmin on Debian 13 with Nginx is quite straightforward. The real added value of this guide is the security part: HTTPS, access restrictions, brute force protection. An exposed phpMyAdmin without protection is an easy target for bots that constantly scan the web.
Need a VPS to host all this? OuiHeberg offers Linux VPS with Debian pre-installed, ready to host your LEMP stack and phpMyAdmin in just a few minutes.

