Installing XAMPP is the easy part. The questions that follow are the ones that actually cost time: why Apache refuses to start when the distro already runs its own web server, how to bring the stack up automatically after a reboot, what the lampp security script really changes, and how to remove everything cleanly when a project ends. This guide covers the full day-2 workflow for XAMPP on Linux, with every command executed on a real machine and every error reproduced before its fix was written down.
If XAMPP is not on the box yet, start with the install guide for your distro: Ubuntu, Debian, Fedora, or Rocky Linux and AlmaLinux. Everything below applies to all of them, because XAMPP ships the same self-contained stack under /opt/lampp regardless of distribution.
Ran through all of this on a clean Ubuntu 24.04 VM with XAMPP 8.2.12 in August 2026, including the ProFTPD breakage covered near the end.
Where XAMPP Lives on a Linux System
The installer puts the entire stack, Apache, MariaDB, PHP, Perl and ProFTPD, under a single directory. Nothing registers with the package manager and nothing lands in /etc, which is why apt or dnf know nothing about it. The paths you will touch most:
| Path | What it holds |
|---|---|
/opt/lampp/lampp | The control script for the whole stack |
/opt/lampp/htdocs | Web root, where your PHP projects go |
/opt/lampp/etc | Config files (httpd.conf, my.cnf, proftpd.conf, php.ini) |
/opt/lampp/var/mysql | MariaDB data directory |
/opt/lampp/logs | Apache error and access logs |
/opt/lampp/bin | Bundled binaries (mysql, php, ftpasswd and friends) |
Because the stack is self-contained, none of the usual systemctl start apache2 or systemctl start mariadb commands apply. The lampp script is the only interface, until you wire it into systemd yourself further down.
Start, Stop and Check XAMPP on Linux
Bring the whole stack up with one command:
sudo /opt/lampp/lampp start
Each component reports individually as it comes up:
Starting XAMPP for Linux 8.2.12-0...
XAMPP: Starting Apache...ok.
XAMPP: Starting MySQL...ok.
XAMPP: Starting ProFTPD...ok.
A live run looks like this. Here the installer had already left ProFTPD up, so it reports already running instead:

The counterparts are stop, restart and status. Status is worth memorising because it names exactly which component is down instead of leaving you to guess:
sudo /opt/lampp/lampp status
A healthy stack reports all three services running:
Version: XAMPP for Linux 8.2.12-0
Apache is running.
MySQL is running.
ProFTPD is running.
Then confirm the web tier answers. Opening http://localhost in a browser redirects to the XAMPP dashboard at /dashboard/:

The dashboard page itself states that XAMPP is meant only for development. Take that seriously: the defaults trade security for convenience, which is exactly what the security section below exists to walk back.
Error: “xampplib: line 22: netstat: command not found”
XAMPP’s helper scripts still probe ports with netstat, which modern minimal Ubuntu and Debian installs no longer ship. When a script restarts a service you get this in the middle of otherwise normal output:
XAMPP: Starting MySQL.../opt/lampp/share/xampp/xampplib: line 22: netstat: command not found
ok.
The service still starts, but the port checks silently stop working. One package fixes it:
sudo apt install net-tools
On Fedora, Rocky or AlmaLinux the equivalent is sudo dnf install net-tools.
Control Apache, MySQL and ProFTPD Individually
You rarely need the whole stack. Working on a PHP app that only touches the database? There is no reason to run an FTP daemon. The lampp script accepts per-service actions, and running it with no arguments prints the full list:
Usage: lampp <action>
start Start XAMPP (Apache, MySQL and eventually others)
startapache Start only Apache
startmysql Start only MySQL
startftp Start only ProFTPD
stop Stop XAMPP (Apache, MySQL and eventually others)
stopapache Stop only Apache
stopmysql Stop only MySQL
stopftp Stop only ProFTPD
reload Reload XAMPP (Apache, MySQL and eventually others)
reloadapache Reload only Apache
reloadmysql Reload only MySQL
reloadftp Reload only ProFTPD
restart Stop and start XAMPP
security Check XAMPP's security
enablessl Enable SSL support for Apache
disablessl Disable SSL support for Apache
backup Make backup file of your XAMPP config, log and data files
So a config change to httpd.conf needs only:
sudo /opt/lampp/lampp reloadapache
And the bundled MariaDB client connects over the local socket without any service names to remember:
/opt/lampp/bin/mysql -u root -e "SELECT VERSION();"
Which returns the MariaDB build XAMPP actually ships, not whatever your distro packages:
VERSION()
10.4.32-MariaDB
Fix “XAMPP: Another web server is already running”
This is the most common XAMPP failure on Linux, and it means exactly what it says: something else already owns port 80. Usually it is the distribution’s own Apache or Nginx, installed as a dependency of some other package and enabled at boot. The failure looks like this:
XAMPP: Starting Apache...fail.
XAMPP: Another web server is already running.
Note that only Apache fails; MySQL and ProFTPD carry on starting normally around it:

Before killing anything, confirm who actually holds the port:
sudo ss -ltnp | grep ":80 "
Here the system Apache owns it, with three worker processes listed:
LISTEN 0 511 *:80 *:* users:(("apache2",pid=19523,fd=4),("apache2",pid=19522,fd=4),("apache2",pid=19520,fd=4))
Stop the conflicting server and prevent it from returning on the next boot. For the distro Apache:
sudo systemctl disable --now apache2
If ss showed Nginx instead, the command is sudo systemctl disable --now nginx. On RHEL-family distros the Apache unit is named httpd. Then start XAMPP’s Apache again:
sudo /opt/lampp/lampp startapache
This time it binds cleanly:
XAMPP: Starting Apache...ok.
Start XAMPP Automatically at Boot with systemd
XAMPP installs no service unit, so after every reboot the stack is down until someone runs lampp start by hand. A small oneshot unit fixes that. Create it:
sudo vim /etc/systemd/system/xampp.service
Add the following unit definition:
[Unit]
Description=XAMPP for Linux
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/opt/lampp/lampp start
ExecStop=/opt/lampp/lampp stop
[Install]
WantedBy=multi-user.target
Reload systemd, then enable and start the unit in one step:
sudo systemctl daemon-reload
sudo systemctl enable --now xampp.service
The unit shows active (exited), which is correct for a oneshot service whose job is to launch other processes:
● xampp.service - XAMPP for Linux
Loaded: loaded (/etc/systemd/system/xampp.service; enabled; preset: enabled)
Active: active (exited) since Mon 2026-08-17 11:18:48 UTC; 2s ago
Process: 682 ExecStart=/opt/lampp/lampp start (code=exited, status=0/SUCCESS)
A reboot test confirmed the whole stack came back on its own, with Apache answering on port 80 seconds after login. One caveat from that testing: systemd marks the unit failed if lampp start exits non-zero, and it exits non-zero when any single component fails to start. So if ProFTPD is broken (see the section below), your Apache and MariaDB still start but the unit reports failed. Fix the failing component rather than papering over the exit code.
Serve Your Own PHP Project from htdocs
Anything under /opt/lampp/htdocs is served by Apache immediately. Quick proof:
sudo vim /opt/lampp/htdocs/test.php
With one line of PHP inside:
<?php echo "XAMPP on Linux: PHP " . PHP_VERSION . " is working\n"; ?>
Fetch it and the bundled PHP interpreter answers:
curl http://localhost/test.php
The response comes from XAMPP’s own PHP build:
XAMPP on Linux: PHP 8.2.12 is working
The web root belongs to root, so rather than editing everything through sudo, give your own user a project directory:
sudo mkdir -p /opt/lampp/htdocs/myapp
sudo chown -R $USER:$USER /opt/lampp/htdocs/myapp
From here your editor, git and build tools work in /opt/lampp/htdocs/myapp without permission errors, and the app is live at http://localhost/myapp/.
Secure XAMPP with the lampp security Script
A fresh XAMPP install has no MariaDB root password, a passwordless pma account for phpMyAdmin, MariaDB listening on the network, and an FTP account with the default password xampp. The bundled audit script walks through all of it interactively:
sudo /opt/lampp/lampp security
Answer yes to each prompt and give real passwords. The transcript from the test box, trimmed of the password prompt lines (the spelling mistakes are XAMPP’s own):
XAMPP: Quick security check...
XAMPP: MySQL is accessable via network.
XAMPP: Normaly that's not recommended. Do you want me to turn it off? [yes]
XAMPP: Turned off.
XAMPP: The MySQL/phpMyAdmin user pma has no password set!!!
XAMPP: Do you want to set a password? [yes]
XAMPP: Setting new MySQL pma password.
XAMPP: MySQL has no root passwort set!!!
XAMPP: Do you want to set a password? [yes]
XAMPP: Setting new MySQL root password.
XAMPP: Change phpMyAdmin's authentication method.
XAMPP: The FTP password for user 'daemon' is still set to 'xampp'.
XAMPP: Do you want to change the password? [yes]
XAMPP: Done.
On a later run, anything already fixed reports clean and only the remaining items prompt again, which doubles as a quick audit of the instance:

Two of these answers change daily behaviour. Turning off network access adds skip-networking, so MariaDB stops listening on TCP 3306 and is reachable only through the local socket, which is what the bundled client and PHP use anyway. And once root has a password, connections need the -p flag:
/opt/lampp/bin/mysql -u root -p
Even secured, this stack skips the hardening a distro package gets. Keep it bound to localhost and never port-forward it to the internet.
Fix ProFTPD: “unknown configuration directive ‘function'”
Here is the bug the security script does not warn you about. On the current XAMPP for Linux build, letting lampp security change the FTP password corrupts the ProFTPD config. The next start fails like this:
XAMPP: Starting ProFTPD...fail.
Contents of "/opt/lampp/var/proftpd/start.err":
proftpd[20289]: fatal: unknown configuration directive 'function' on line 44 of '/opt/lampp/etc/proftpd.conf'
The cause is visible in the config file: the script tried to generate a password hash with a PHP helper, the helper did not execute, and the raw PHP source code got written into proftpd.conf where the hash should be. ProFTPD then chokes on the word function. The fix is to generate a valid hash yourself and replace the garbage. First create the hash:
openssl passwd -1 'YourFtpPassword'
Copy the output, which looks like this:
$1$.i5bmO/J$LHZrUhc5k6b12zbNhFE2A0
Then open the config:
sudo vim /opt/lampp/etc/proftpd.conf
Delete everything from the line UserPassword daemon <? down to the closing ?>, and put a single clean directive in its place with your hash:
UserPassword daemon $1$.i5bmO/J$LHZrUhc5k6b12zbNhFE2A0
Start the FTP service again:
sudo /opt/lampp/lampp startftp
It reports XAMPP: Starting ProFTPD...ok. this time, and an FTP login as daemon with the new password lists the contents of htdocs, which is what that account serves. With ProFTPD healthy again, lampp start returns to exit code 0 and the systemd unit from earlier stops reporting failures. If you never use FTP to reach htdocs, the simpler path is skipping the FTP password prompt in the security script entirely and just not starting the service.
Uninstall XAMPP Completely
XAMPP ships its own uninstaller binary. Stop the stack, remove the systemd unit if you created one, then run it:
sudo systemctl disable --now xampp.service
sudo rm -f /etc/systemd/system/xampp.service
sudo systemctl daemon-reload
sudo /opt/lampp/uninstall
Add --mode unattended to the uninstall command to skip the confirmation dialog. Either way, the uninstaller deliberately leaves your data behind. After it finished on the test machine, this is what survived:
/opt/lampp/htdocs
/opt/lampp/htdocs/myapp
/opt/lampp/var/mysql
Your projects and the MariaDB data directory are preserved so a reinstall can pick them up. If you want the machine genuinely clean, back up anything worth keeping from htdocs, dump any databases you need, then remove the directory:
sudo rm -rf /opt/lampp
That is the entire footprint. No packages to purge, no stray configs in /etc. If you are removing XAMPP because a project graduated beyond it, the natural next step is a native stack with proper systemd units and unattended security updates: the LAMP setup guide for Ubuntu and its Debian equivalent cover that move end to end.