phpMyAdmin is a convenient web interface for MariaDB and MySQL, and also one of the most scanned URLs on the Internet. This guide shows two installations on your VPS Linux Infrawire, the apt package with Apache and a manual install behind Nginx, then the measures that keep it out of reach of bots.
📋 Prerequisites
- A VPS running Ubuntu 24.04 or Debian 12, with root or
sudoaccess (IP and root password are available in your client area) - A working LAMP stack (option A) or LEMP stack (option B) with MariaDB
- Your own public IP, referred to below as
ADMIN_IP
1. Option A: install the apt package with Apache
Bashapt update apt install -y phpmyadmin php-mbstring php-zip php-gd php-curl
In the installer, select apache2 with the space bar (an asterisk must appear), then answer "Yes" to configure the database with dbconfig-common and set a password for the internal phpMyAdmin account. Then reload Apache:
Bashphpenmod mbstring systemctl reload apache2
phpMyAdmin is now served at http://VPS_IP/phpmyadmin.
2. Create a dedicated database user
Never log in as root. On MariaDB under Ubuntu and Debian, root uses unix_socket authentication and phpMyAdmin will refuse it anyway: leave it that way and create a normal account.
Bashmariadb
SQLCREATE USER 'pmauser'@'localhost' IDENTIFIED BY 'STRONG_PASSWORD'; GRANT ALL PRIVILEGES ON appdb.* TO 'pmauser'@'localhost'; FLUSH PRIVILEGES; EXIT;
Grant rights only on the databases the user really manages. Do not enable AllowNoPassword in the configuration.
3. Hide the URL and add authentication (Apache)
Change the default alias to a random one, and create a password file:
BashSUFFIX=$(openssl rand -hex 6); echo "pma-$SUFFIX" sed -i "s#Alias /phpmyadmin#Alias /pma-$SUFFIX#" /etc/phpmyadmin/apache.conf htpasswd -c /etc/phpmyadmin/.htpasswd USER
Then add these lines inside the existing <Directory /usr/share/phpmyadmin> block of /etc/phpmyadmin/apache.conf:
Apache1AuthType Basic 2AuthName 'Restricted area' 3AuthUserFile /etc/phpmyadmin/.htpasswd 4<RequireAll> 5 Require valid-user 6 Require ip ADMIN_IP 7</RequireAll>
Without <RequireAll>, Apache would accept either condition; with it, both the password and the IP are required.
Bashapache2ctl configtest && systemctl reload apache2
4. Option B: manual install behind Nginx
Install the dependencies, then download the latest release from the official phpMyAdmin site (replace VERSION with the current number):
Bashapt install -y nginx php-fpm php-mysql php-mbstring php-xml php-zip php-gd php-curl apache2-utils cd /tmp wget https://files.phpmyadmin.net/phpMyAdmin/VERSION/phpMyAdmin-VERSION-all-languages.tar.gz tar xzf phpMyAdmin-VERSION-all-languages.tar.gz mkdir -p /var/www/pma mv phpMyAdmin-VERSION-all-languages /var/www/pma/pma-SECRET cd /var/www/pma/pma-SECRET cp config.sample.inc.php config.inc.php openssl rand -hex 16
Replace pma-SECRET with a random name. Edit config.inc.php and paste the generated value (32 characters) as the secret:
PHP$cfg['blowfish_secret'] = 'RANDOM_32_CHARS'; $cfg['TempDir'] = '/var/lib/phpmyadmin/tmp';
Bashmkdir -p /var/lib/phpmyadmin/tmp chown www-data:www-data /var/lib/phpmyadmin/tmp chmod 700 /var/lib/phpmyadmin/tmp chown -R root:www-data /var/www/pma chmod 640 /var/www/pma/pma-SECRET/config.inc.php htpasswd -c /etc/nginx/.htpasswd USER
Add this block inside the server { ... } of your site. On Debian 12 the socket is php8.2-fpm.sock instead of php8.3-fpm.sock:
Nginx1location ^~ /pma-SECRET/ { 2 allow ADMIN_IP; 3 deny all; 4 auth_basic 'Restricted area'; 5 auth_basic_user_file /etc/nginx/.htpasswd; 6 root /var/www/pma; 7 index index.php; 8 9 location ~ \.php$ { 10 include snippets/fastcgi-php.conf; 11 fastcgi_pass unix:/run/php/php8.3-fpm.sock; 12 } 13}
Bashnginx -t && systemctl reload nginx
5. The safest option: an SSH tunnel
If you do not want any public exposure, keep the interface reachable only from the VPS and open a tunnel from your computer:
Bashssh -L 8080:127.0.0.1:80 USER@VPS_IP
While the session is open, browse to http://127.0.0.1:8080/pma-SECRET/. On Apache, restrict the block to Require local instead of Require ip ADMIN_IP; on Nginx, use allow 127.0.0.1;. This also solves the problem of a changing home IP.
6. Verify the protection
Bashcurl -sI http://VPS_IP/phpmyadmin | head -n 1 curl -sI http://VPS_IP/pma-SECRET/ | head -n 1
The first request must return 404. The second returns 403 from any IP other than ADMIN_IP, and 401 from yours until you provide the basic auth password. Also serve phpMyAdmin over HTTPS only, otherwise the passwords travel in clear text.
🛠️ Troubleshooting
404 Not Found. The alias or location name does not match the URL you typed, or the web server was not reloaded.
403 Forbidden for you. Your public IP changed. Update ADMIN_IP, or switch to the SSH tunnel.
"The mbstring extension is missing" or a blank page. Install php-mbstring, then run phpenmod mbstring (Apache) or restart php8.3-fpm (Nginx).
Access denied for root. This is expected and desirable. Log in with the dedicated user created in step 2.
🎉 phpMyAdmin is installed, hidden and restricted: only you can reach your databases.