How to install and configure XAMPP and phpMyAdmin on an Ubuntu VPS.
Set up a XAMPP-equivalent environment on a Linux VPS using Nginx, MariaDB, PHP-FPM, and phpMyAdmin — complete step-by-step guide for Ubuntu 24.04.
This guide is aimed at anyone setting up their first VPS. We go from a freshly provisioned server all the way to phpMyAdmin accessible in the browser with a working PHP page.
Prerequisites
Before starting, confirm you have the minimum environment in place.
You need a VPS running Ubuntu 24.04 LTS (Debian 12 also works with minor adjustments), SSH access as root or a user with sudo, and at least 1 GB of free RAM. Have the machine’s public IP address on hand and, optionally, a domain pointed to it.
Ubuntu 24.04 LTS 1 GB 22, 80, 443, 3306 SSH with sudo None of the packages in this guide require manual compilation. Everything comes from Ubuntu’s official repositories.
System Update
Start with a clean system state. Outdated repositories cause half the problems in tutorials like this one.
Update the package index and apply pending upgrades:
sudo apt update && sudo apt upgrade -yThis command reads the repositories configured in /etc/apt/sources.list, downloads updated manifests, and installs newer versions of already-installed packages. It can take anywhere from 30 seconds to a few minutes.
Install basic utilities we’ll use along the way:
sudo apt install -y curl wget unzip software-properties-commonInstalling Nginx
Nginx will play the role that Apache plays in a standard XAMPP setup — receiving HTTP requests and, when the file is PHP, forwarding it to PHP-FPM via socket.
Install the Nginx package:
sudo apt install -y nginxEnable and start the service:
sudo systemctl enable --now nginxNavigating to http://YOUR_IP in a browser should show the default “Welcome to nginx” page. If a firewall is blocking access, allow HTTP/HTTPS ports (80 and 443):
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enableAlways allow port 22 (OpenSSH) before enabling UFW. Missing that rule drops your current session and blocks all future connections. You would need the VPS panel’s emergency console to recover.
Installing MariaDB
MariaDB is a drop-in fork of MySQL and is the default database engine in current XAMPP releases. The mysql commands work identically.
Install the server:
sudo apt install -y mariadb-serverRun the security assistant to remove insecure defaults:
sudo mysql_secure_installationAnswer the prompts as follows:
Enter current password for root: leave blank (press Enter)Switch to unix_socket authentication: nChange the root password?: Y — set a strong password and save itRemove anonymous users?: YDisallow root login remotely?: YRemove test database?: YReload privilege tables now?: Y
Create a separate administrative user for phpMyAdmin (safer than using root):
sudo mysql -u root -pInside the MariaDB prompt:
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'REPLACE_THIS_PASSWORD';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EXIT;Installing PHP-FPM
PHP-FPM (FastCGI Process Manager) is the process Nginx calls to execute PHP scripts. In XAMPP this is handled inside Apache via mod_php; with Nginx we separate it into its own daemon.
Install PHP and the most common extensions:
sudo apt install -y php-fpm php-mysql php-mbstring php-zip php-gd \
php-curl php-xml php-bcmath php-intlOn Ubuntu 24.04 this installs PHP 8.3 by default. Confirm with:
php -vVerify that the PHP-FPM socket is active:
sudo systemctl status php8.3-fpmIt should show active (running). The socket lives at /run/php/php8.3-fpm.sock — that path is what Nginx will reference.
Configuring Nginx to Serve PHP
Now we wire the three components together. We’ll create a dedicated site configuration that replaces the default.
Create the web directory and set permissions:
sudo mkdir -p /var/www/local
sudo chown -R www-data:www-data /var/www/localCreate the site configuration file:
sudo nano /etc/nginx/sites-available/localPaste the content below (replace your_domain.com with your domain or the VPS IP):
server {
listen 80;
server_name your_domain.com;
root /var/www/local;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}Enable the site, disable the default, and reload Nginx:
sudo ln -s /etc/nginx/sites-available/local /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginxThe nginx -t command validates syntax before the reload. If it shows syntax is ok and test is successful, you’re good to go.
Create a test file to confirm PHP is being processed:
echo "<?php phpinfo(); ?>" | sudo tee /var/www/local/info.phpNavigate to http://YOUR_IP/info.php in a browser. You should see the colorful phpinfo() page with full version details. Once confirmed, delete the file — it exposes information that should not be public:
sudo rm /var/www/local/info.phpInstalling phpMyAdmin
With Nginx, PHP, and MariaDB running, we now add the database administration panel.
Install the package:
sudo apt install -y phpmyadminDuring installation:
- When asked
Web server to reconfigure automatically, select nothing (neither Apache nor Lighttpd) — press Tab and Enter to skip. Nginx is not on the list. - At
Configure database for phpmyadmin with dbconfig-common: Yes - Set a password for phpMyAdmin’s internal user
Create a symlink from phpMyAdmin into the web directory:
sudo ln -s /usr/share/phpmyadmin /var/www/local/phpmyadminNavigate to http://YOUR_IP/phpmyadmin in a browser. Log in with the admin user and the password set in Step 07.
Exposing /phpmyadmin publicly is a common brute-force attack vector. In production, add IP-based restrictions in the Nginx location block or protect it with HTTP basic authentication using auth_basic and an .htpasswd file.
Final Verification
A quick set of checks confirms everything is connected.
systemctl is-active nginx php8.3-fpm mariadb
Output should be three lines each reading active. If any shows inactive or failed, run systemctl status SERVICE_NAME to see the reason.
In the browser, validate both endpoints:
http://YOUR_IP/— blank page or directory listing (noindex.phpyet, that’s expected)http://YOUR_IP/phpmyadmin— phpMyAdmin login screen
Troubleshooting
502 Bad Gateway when accessing a PHP file
Almost always caused by a wrong PHP-FPM socket path. Check the actual installed version:
ls /run/php/
If the file is php8.2-fpm.sock instead of php8.3-fpm.sock, update the fastcgi_pass line in the Nginx configuration file and reload.
phpMyAdmin returns 404
The symlink was not created or the web directory differs. Check:
ls -la /var/www/local/phpmyadmin
It should show an arrow pointing to /usr/share/phpmyadmin. If not, redo the ln -s from Step 15.
Access denied when logging into phpMyAdmin
The admin user needs to exist in MariaDB. Log in as root:
sudo mysql -u root -p
Then run SELECT User, Host FROM mysql.user;. If admin is not listed, redo the CREATE USER statement from Step 07.
Next Steps
With the stack running, consider these follow-up points:
- HTTPS with Let’s Encrypt: install
certbotand generate a free certificate for your domain withsudo certbot --nginx. - Automated MariaDB backups: configure
mysqldumpin a daily cron job with weekly rotation. - PHP-FPM pool tuning: in
/etc/php/8.3/fpm/pool.d/www.conf, calibratepm.max_childrenbased on available RAM. - Per-site user isolation: run each project under a dedicated Linux user to isolate file permissions.
If you’re putting this stack into production, a Hostini VPS comes with kernel-level packet filtering to mitigate DDoS attacks — relevant when phpMyAdmin is exposed, even with IP restrictions in place.
Frequently asked questions
Can I install the original XAMPP on a Linux VPS instead of building the stack manually?
Technically yes — XAMPP provides a `.run` installer for Linux, but it is not recommended for servers. It runs as root by default, sits outside the package manager (no security updates via apt), ships its own binaries that conflict with system packages, and uses Apache. For any production environment, building Nginx + PHP-FPM + MariaDB natively is more secure and lighter.
Why doesn't Nginx appear in the web server list when installing phpMyAdmin?
The `phpmyadmin` package on Debian/Ubuntu only offers automatic configuration for Apache and Lighttpd. To use it with Nginx, you skip that step and manually create a symlink from the `/usr/share/phpmyadmin` directory into your web root, as shown in this tutorial.
What is the difference between PHP-FPM and Apache's mod_php?
`mod_php` runs inside the Apache process, so every request — even for static files — loads the PHP interpreter into memory. PHP-FPM is a separate daemon that only processes PHP requests, called via FastCGI by Nginx. The result is lower RAM usage and better isolation between the web server and the PHP runtime.
Do I need to restart PHP-FPM every time I change a PHP file?
No. PHP files are read on each request automatically. You only need to restart PHP-FPM (`sudo systemctl restart php8.3-fpm`) when changing PHP's own configuration — files under `/etc/php/8.3/fpm/` such as `php.ini` or the pool definitions.
Is it safe to leave phpMyAdmin accessible at /phpmyadmin?
Not in production. That path is constantly targeted by bots attempting brute-force logins. Common mitigations include moving it to a non-obvious URL (e.g., `/admin-db-x7k2`), restricting by IP in the Nginx location block (`allow IP; deny all;`), adding HTTP basic authentication in front of the phpMyAdmin login, or accessing it only through an SSH tunnel.
How do I know which PHP version was installed and how do I upgrade it?
Run `php -v` to see the current version. Ubuntu 24.04 ships PHP 8.3 by default. To use a newer version (e.g., 8.4) you need the `ondrej/php` PPA: `sudo add-apt-repository ppa:ondrej/php && sudo apt update && sudo apt install php8.4-fpm`. Remember to update the socket path in Nginx when switching versions.