Nauris
LAMP Setup

Install LAMP Stack on Debian 12

Install Apache, MariaDB, PHP 8, PHP-FPM, and phpMyAdmin on Debian 12 with optional multi-PHP support and a dedicated Apache virtual host.

This guide walks through a full LAMP stack setup on Debian 12 using Apache, MariaDB, PHP 8, PHP-FPM, and phpMyAdmin.

By the end, you will have:

  • a sudo-enabled admin user
  • updated system packages
  • SSH on a custom port
  • UFW enabled
  • systemd-resolved configured
  • Apache, MariaDB, PHP, and phpMyAdmin installed
  • optional multi-PHP support
  • a dedicated PHP-FPM pool and virtual host for a site

Create a Sudo User

Skip this step if you already have a working sudo user.

Create a new user:

adduser newuser

Grant sudo access:

sudo usermod -aG sudo newuser

Switch to the new user and verify sudo works:

su - newuser
sudo whoami

If the command returns root, sudo is configured correctly.

Update Packages

Update package metadata and upgrade installed packages:

sudo apt update && sudo apt upgrade

Change the SSH Port

Edit the SSH server config:

sudo vim /etc/ssh/sshd_config

Set a custom port and disable root login:

Port 52225
PermitRootLogin no

Reload the SSH service:

sudo systemctl daemon-reload
sudo systemctl restart ssh

Enable the Firewall

Install UFW:

sudo apt install ufw

Allow HTTP, HTTPS, and your custom SSH port:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 52225/tcp

Enable the firewall:

sudo ufw enable

Check active rules:

sudo ufw status

Connect over the new SSH port:

ssh -p 52225 user@your_server_ip

Enabling the firewall can drop the current SSH session. Reconnect using the new port if needed.

Configure DNS Resolver

Install and enable systemd-resolved:

sudo apt install systemd-resolved
sudo systemctl enable systemd-resolved
sudo systemctl start systemd-resolved
sudo systemctl status systemd-resolved

Edit the resolver config:

sudo vim /etc/systemd/resolved.conf

Use Cloudflare and Quad9:

[Resolve]
DNS=1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001
FallbackDNS=9.9.9.9 149.112.112.112 2620:fe::fe 2620:fe::9
DNSOverTLS=opportunistic

Point resolv.conf at the stub resolver and restart:

sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved

Check resolver status:

resolvectl status

Generate an SSL Certificate

Create a self-signed certificate for local testing or internal use:

sudo openssl req -x509 -newkey rsa:2048 -nodes -keyout /etc/ssl/private/default.key -out /etc/ssl/certs/default.crt -days 3650

Install PHP 8 and PHP-FPM

Check available PHP packages:

sudo apt search php | egrep '^php[0-9]'

Install PHP 8.2 and common extensions:

sudo apt install php8.2 php8.2-cli php8.2-fpm php8.2-common php8.2-mysql php8.2-zip php8.2-gd php8.2-mbstring php8.2-curl php8.2-xml php8.2-bcmath php8.2-gmp libapache2-mod-php8.3

Those packages cover common dependencies for WordPress and similar PHP applications.

Optional: Install Multiple PHP Versions

If you want to run multiple PHP versions, add the Sury PHP repository:

sudo apt install -y apt-transport-https lsb-release ca-certificates gnupg gnupg2
sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/php.list
sudo apt update

Install both PHP 7.4 and PHP 8.3:

sudo apt install php7.4 php7.4-cli php7.4-fpm php7.4-common php7.4-mysql php7.4-zip php7.4-gd php7.4-mbstring php7.4-curl php7.4-xml php7.4-bcmath php7.4-gmp libapache2-mod-php7.4
sudo apt install php8.3 php8.3-cli php8.3-fpm php8.3-common php8.3-mysql php8.3-zip php8.3-gd php8.3-mbstring php8.3-curl php8.3-xml php8.3-bcmath php8.3-gmp libapache2-mod-php8.3

Configure PHP-FPM Pools

Edit the PHP 8.3 pool:

sudo vim /etc/php/8.3/fpm/pool.d/www.conf

Use:

[php-fpm-8.3]
user = www-data
group = www-data

listen = /run/php/php8.3-fpm.sock

listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Restart the service:

sudo systemctl restart php8.3-fpm

If you also installed PHP 7.4, edit its pool:

sudo vim /etc/php/7.4/fpm/pool.d/www.conf

Use:

[php-fpm-7.4]
user = www-data
group = www-data

listen = /run/php/php7.4-fpm.sock

listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Restart PHP 7.4 FPM:

sudo systemctl restart php7.4-fpm

Disable commonly abused functions:

sudo vim /etc/php/8.3/fpm/php.ini
sudo vim /etc/php/7.4/fpm/php.ini

Set:

disable_functions = exec,passthru,shell_exec,system,proc_open,popen

Enable OPcache:

[opcache]
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.use_cwd=1
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.save_comments=1

Restart both FPM services if you configured both versions:

sudo systemctl restart php8.3-fpm
sudo systemctl restart php7.4-fpm

Install Apache

Install Apache:

sudo apt install apache2

Set a global ServerName:

sudo sed -i '/# Global configuration/a ServerName localhost' /etc/apache2/apache2.conf
grep "ServerName" /etc/apache2/apache2.conf

Enable and start the service:

sudo systemctl enable apache2
sudo systemctl start apache2
sudo systemctl status apache2

Enable the required Apache modules:

sudo a2enmod ssl
sudo a2enmod rewrite
sudo a2enmod headers
sudo a2enmod proxy_fcgi setenvif

Confirm Apache is serving the default page:

http://server_ip

Create a temporary PHP test file:

echo "<?php
phpinfo();
?>" | sudo tee /var/www/html/test.php

Open the test page:

http://server_ip/test.php

Remove the test file when finished:

sudo rm /var/www/html/test.php

Install MariaDB

Install MariaDB server and client:

sudo apt install mariadb-server mariadb-client

Enable the service:

sudo systemctl enable mariadb
sudo systemctl status mariadb

Verify MariaDB is listening:

sudo netstat -tulnp | grep mariadb

Secure the installation:

sudo mysql_secure_installation

Recommended answers:

  • press Enter to leave the root password empty if you want local-only development first
  • answer Y to switch to Unix socket authentication
  • answer Y to remove anonymous users
  • answer Y to disallow remote root login
  • answer Y to remove the test database
  • answer Y to reload privilege tables

The main MariaDB config file is:

sudo vim /etc/mysql/my.cnf

Install phpMyAdmin

Check the latest upstream release before downloading:

https://www.phpmyadmin.net/downloads

Download the release archive used in this guide:

cd /tmp
curl -O https://files.phpmyadmin.net/phpMyAdmin/5.2.2/phpMyAdmin-5.2.2-english.tar.gz

Extract it:

sudo tar -xvzf phpMyAdmin-5.2.2-english.tar.gz

Move it into place:

sudo mkdir -p /usr/share/phpmyadmin
sudo mv /tmp/phpMyAdmin-5.2.2-english/* /usr/share/phpmyadmin
ls -l /usr/share/phpmyadmin

Create a temp directory for sessions:

sudo mkdir -p /usr/share/phpmyadmin/tmp
sudo chown -R www-data:www-data /usr/share/phpmyadmin/tmp

Create the phpMyAdmin database and control user:

sudo mariadb

Run:

CREATE DATABASE phpmyadmin;
CREATE USER 'pma'@'localhost' IDENTIFIED BY 'strong_password_here';
GRANT SELECT, INSERT, UPDATE, DELETE ON phpmyadmin.* TO 'pma'@'localhost';
FLUSH PRIVILEGES;
exit

Generate a random blowfish secret:

openssl rand -base64 24

Copy the sample config and edit it:

sudo cp /usr/share/phpmyadmin/config.sample.inc.php /usr/share/phpmyadmin/config.inc.php
sudo vim /usr/share/phpmyadmin/config.inc.php

Set the generated secret:

$cfg['blowfish_secret'] = 'your_code';

Add the temp directory and hide system databases:

$cfg['TempDir'] = '/usr/share/phpmyadmin/tmp';
$cfg['Servers'][$i]['hide_db'] = '^information_schema|mysql|phpmyadmin|performance_schema|sys$';

Set the control user credentials:

$cfg['Servers'][$i]['controluser'] = 'pma';
$cfg['Servers'][$i]['controlpass'] = 'strong_password_here';

Enable storage tables:

$cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
$cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
$cfg['Servers'][$i]['relation'] = 'pma__relation';
$cfg['Servers'][$i]['table_info'] = 'pma__table_info';
$cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
$cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
$cfg['Servers'][$i]['column_info'] = 'pma__column_info';
$cfg['Servers'][$i]['history'] = 'pma__history';
$cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';
$cfg['Servers'][$i]['tracking'] = 'pma__tracking';
$cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';
$cfg['Servers'][$i]['recent'] = 'pma__recent';
$cfg['Servers'][$i]['favorite'] = 'pma__favorite';
$cfg['Servers'][$i]['users'] = 'pma__users';
$cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
$cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
$cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
$cfg['Servers'][$i]['central_columns'] = 'pma__central_columns';
$cfg['Servers'][$i]['designer_settings'] = 'pma__designer_settings';
$cfg['Servers'][$i]['export_templates'] = 'pma__export_templates';

Create the phpMyAdmin tables:

sudo mysql -u root -p phpmyadmin < /usr/share/phpmyadmin/sql/create_tables.sql

Create an Apache basic auth password file:

sudo htpasswd -c /etc/apache2/.htpasswd pma

Create the phpMyAdmin virtual host:

sudo vim /etc/apache2/sites-available/phpmyadmin.conf

Use:

<VirtualHost *:443>
    ServerName pma.example.com
    DocumentRoot /usr/share/phpmyadmin

    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/default.crt
    SSLCertificateKeyFile /etc/ssl/private/default.key

    <FilesMatch "\.php$">
        SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
    </FilesMatch>

    <Directory /usr/share/phpmyadmin/>
        AddDefaultCharset UTF-8
        DirectoryIndex index.php

        AuthType Basic
        AuthName "Restricted Access"
        AuthUserFile /etc/apache2/.htpasswd
        Require valid-user

        Options -Indexes
    </Directory>

    <Directory /usr/share/phpmyadmin/setup/>
        Require all denied
    </Directory>

    <Directory /usr/share/phpmyadmin/libraries/>
        Require all denied
    </Directory>

    <Directory /usr/share/phpmyadmin/templates/>
        Require all denied
    </Directory>

    <Directory /usr/share/phpmyadmin/setup/lib/>
        Require all denied
    </Directory>

    <Directory /usr/share/phpmyadmin/sql/>
        Require all denied
    </Directory>

    <Directory /usr/share/phpmyadmin/vendor/>
        Require all denied
    </Directory>
</VirtualHost>

Replace pma.example.com with your actual subdomain and change php8.3 to the PHP version you want to use for phpMyAdmin if needed.

Enable the site:

sudo a2ensite phpmyadmin.conf

Test and reload Apache:

sudo apache2ctl configtest
sudo systemctl reload apache2

Create a database and user for your application:

sudo mariadb

Run:

CREATE DATABASE example_db;
CREATE USER 'example_user'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON example_db.* TO 'example_user'@'localhost';
FLUSH PRIVILEGES;
exit

You should now be able to sign in to phpMyAdmin at https://pma.example.com.

Create a Dedicated Site User

Create a non-sudo user for the hosted application:

sudo adduser --disabled-password dolphin

Create the document root and fix ownership:

sudo mkdir -p /var/www/dolphin/example.com
sudo chmod 711 /var/www/dolphin
sudo chown root:root /var/www
sudo chown -R dolphin:dolphin /var/www/dolphin
sudo chmod -R 755 /var/www/dolphin/example.com

Copy the PHP 8.3 pool config:

sudo cp /etc/php/8.3/fpm/pool.d/www.conf /etc/php/8.3/fpm/pool.d/dolphin.conf
sudo vim /etc/php/8.3/fpm/pool.d/dolphin.conf

Use:

[php8.3-fpm-dolphin]
user = dolphin
group = dolphin

listen = /run/php/php8.3-fpm-dolphin.sock

listen.owner = www
listen.group = www
listen.mode = 0660

Restart PHP-FPM:

sudo systemctl restart php8.3-fpm

Create the site virtual host:

sudo vim /etc/apache2/sites-available/example.com.conf

Use:

<VirtualHost *:80>
    ServerAdmin [email protected]
    ServerName example.com
    ServerAlias www.example.com

    DocumentRoot /var/www/dolphin/example.com

    <FilesMatch "\.php$">
        SetHandler "proxy:unix:/run/php/php8.3-fpm-dolphin.sock|fcgi://localhost/"
    </FilesMatch>

    ErrorLog ${APACHE_LOG_DIR}/example.com_error.log
    CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined

    Redirect permanent / https://example.com/
</VirtualHost>

<VirtualHost *:443>
    ServerAdmin [email protected]
    ServerName example.com
    ServerAlias www.example.com

    DocumentRoot /var/www/dolphin/example.com

    <FilesMatch "\.php$">
        SetHandler "proxy:unix:/run/php/php8.3-fpm-dolphin.sock|fcgi://localhost/"
    </FilesMatch>

    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/default.crt
    SSLCertificateKeyFile /etc/ssl/private/default.key

    ErrorLog ${APACHE_LOG_DIR}/example.com_ssl_error.log
    CustomLog ${APACHE_LOG_DIR}/example.com_ssl_access.log combined

    <Directory /var/www/dolphin/example.com>
        AddDefaultCharset UTF-8
        DirectoryIndex index.php
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Enable the site and reload Apache:

sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2

Install WordPress

Switch to the site user:

sudo su - dolphin

Download and extract WordPress:

cd /var/www/dolphin/example.com
curl -O https://wordpress.org/latest.tar.gz
tar -xvzf latest.tar.gz
mv wordpress/* .
rm latest.tar.gz && rm -fr wordpress

Open https://example.com in your browser to continue the WordPress installer.

On this page