Nauris
LAMP Setup

Install LAMP Stack on Arch Linux

Install Apache, MariaDB, PHP 8, PHP-FPM, and phpMyAdmin on Arch Linux with a dedicated PHP-FPM pool and Apache virtual host setup.

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

By the end, you will have:

  • an updated Arch Linux server
  • a non-root sudo user
  • SSH on a custom port
  • UFW enabled
  • systemd-resolved configured
  • Apache, MariaDB, PHP, and phpMyAdmin installed
  • a dedicated PHP-FPM pool and virtual host for a site

Update Packages

Update package metadata, upgrade installed packages, and install a few basic tools:

pacman -Syyu && pacman -S sudo vim

Create a New User

Create a regular user and add it to the users and wheel groups:

sudo useradd -m -G users,wheel -s /bin/bash username

Set a password for the new user:

sudo passwd username

Open the sudoers file:

EDITOR=vim sudo visudo

Uncomment this line:

%wheel ALL=(ALL:ALL) ALL

Switch to the new user and verify sudo access:

su - newuser
sudo whoami

If the command returns root, sudo is configured correctly.

Change the SSH Port

Open the SSH server configuration:

sudo vim /etc/ssh/sshd_config

Set a custom SSH port and disable root login:

Port 52225
PermitRootLogin no

Reload the service:

sudo systemctl daemon-reload
sudo systemctl restart sshd

Enable the Firewall

Install UFW:

sudo pacman -S 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 the active rules:

sudo ufw status

Use the new SSH port when connecting:

ssh -p 52225 user@your_server_ip

Starting the firewall can interrupt the current SSH session. Reconnect using the new port if needed.

Configure DNS Resolver

Enable systemd-resolved and make sure it starts automatically:

sudo systemctl enable systemd-resolved --now
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

Recreate resolv.conf and restart the resolver:

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

Check resolver status:

resolvectl status

Install PHP 8 and PHP-FPM

Install PHP, PHP-FPM, and the GD extension:

sudo pacman -S php php-fpm php-gd

Open the main PHP config:

sudo vim /etc/php/php.ini

Uncomment the required extensions:

sudo sed -i 's/;extension=\(bcmath\|bz2\|curl\|exif\|gd\|gmp\|mysqli\|pdo_mysql\|zip\)/extension=\1/' /etc/php/php.ini
sudo sed -i 's/;zend_extension=\(opcache\)/zend_extension=\1/' /etc/php/php.ini

Verify the changes:

grep -E '^(;)?extension=' /etc/php/php.ini | grep -E 'bcmath|bz2|curl|exif|gd|gmp|mysqli|pdo_mysql|zip'
grep -E '^(;)?zend_extension=' /etc/php/php.ini | grep -E 'opcache'

If you prefer to edit the file manually, enable:

extension=bcmath
extension=bz2
extension=curl
extension=exif
extension=gd
extension=gmp
extension=mysqli
extension=pdo_mysql
extension=zip
zend_extension=opcache

Configure the default PHP-FPM pool:

sudo vim /etc/php/php-fpm.d/www.conf

Use these values:

[www]
user = http
group = http

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

listen.owner = http
listen.group = http
listen.mode = 0660

Restart PHP-FPM:

sudo systemctl restart php-fpm

Disable commonly abused functions:

sudo vim /etc/php/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 PHP-FPM again:

sudo systemctl restart php-fpm

Install Apache

Install Apache:

sudo pacman -S apache

Enable and start the service:

sudo systemctl enable httpd --now
sudo systemctl status httpd

Generate a self-signed SSL certificate:

sudo openssl req -x509 -newkey rsa:2048 -nodes -keyout /etc/httpd/conf/server.key -out /etc/httpd/conf/server.crt -days 3650

Set the global ServerName:

sudo sed -i 's/^#ServerName www\.example\.com:80/ServerName localhost/' /etc/httpd/conf/httpd.conf
grep 'ServerName' /etc/httpd/conf/httpd.conf

Enable the required Apache modules:

sudo sed -i 's/^#\(LoadModule rewrite_module.*\)/\1/' /etc/httpd/conf/httpd.conf
sudo sed -i 's/^#\(LoadModule ssl_module.*\)/\1/' /etc/httpd/conf/httpd.conf
sudo sed -i 's/^#\(LoadModule proxy_fcgi_module.*\)/\1/' /etc/httpd/conf/httpd.conf
sudo sed -i 's/^#\(LoadModule headers_module.*\)/\1/' /etc/httpd/conf/httpd.conf
sudo sed -i 's/^#\(LoadModule proxy_module.*\)/\1/' /etc/httpd/conf/httpd.conf
sudo sed -i 's/^#\(LoadModule setenvif_module.*\)/\1/' /etc/httpd/conf/httpd.conf
sudo sed -i 's/^#\(LoadModule socache_shmcb_module.*\)/\1/' /etc/httpd/conf/httpd.conf

Enable the SSL config include:

sudo sed -i 's/^#\(Include conf\/extra\/httpd-ssl\.conf\)/\1/' /etc/httpd/conf/httpd.conf

Test the configuration and restart Apache:

sudo httpd -t
sudo systemctl start httpd
sudo systemctl status httpd

Install MariaDB

Install MariaDB:

sudo pacman -S mariadb

Initialize the database:

sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql

Enable the service:

sudo systemctl enable mariadb --now
sudo systemctl status mariadb

Verify that MariaDB is listening:

sudo netstat -tulnp | grep mariadb

Secure the installation:

sudo mariadb-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 server config is here:

sudo vim /etc/my.cnf.d/mariadb-server.cnf

Install phpMyAdmin

Install phpMyAdmin:

sudo pacman -S phpmyadmin

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

Edit the phpMyAdmin config:

sudo vim /etc/webapps/phpmyadmin/config.inc.php

Set the generated secret:

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

Add a temp directory and hide system databases:

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

Configure the control user:

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

Enable the 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 mariadb -u root -p phpmyadmin < /usr/share/webapps/phpMyAdmin/sql/create_tables.sql

Create an Apache basic auth password file for extra protection:

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

Create the Apache config:

sudo vim /etc/httpd/conf/extra/phpmyadmin.conf

Use this virtual host:

<VirtualHost *:443>
    ServerName pma.example.com
    DocumentRoot /usr/share/webapps/phpMyAdmin
    ErrorLog "/var/log/httpd/phpmyadmin-error.log"
    CustomLog "/var/log/httpd/phpmyadmin-access.log" combined

    SSLEngine on
    SSLCertificateFile /etc/httpd/conf/server.crt
    SSLCertificateKeyFile /etc/httpd/conf/server.key

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

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

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

        Options -Indexes
    </Directory>

    <Directory /usr/share/webapps/phpMyAdmin/setup/>
        Require all denied
    </Directory>

    <Directory /usr/share/webapps/phpMyAdmin/libraries/>
        Require all denied
    </Directory>

    <Directory /usr/share/webapps/phpMyAdmin/templates/>
        Require all denied
    </Directory>

    <Directory /usr/share/webapps/phpMyAdmin/setup/lib/>
        Require all denied
    </Directory>

    <Directory /usr/share/webapps/phpMyAdmin/sql/>
        Require all denied
    </Directory>

    <Directory /usr/share/webapps/phpMyAdmin/vendor/>
        Require all denied
    </Directory>
</VirtualHost>

Replace pma.example.com with your actual subdomain.

Include the phpMyAdmin config in httpd.conf:

echo -e "\nInclude conf/extra/phpmyadmin.conf" | sudo tee -a /etc/httpd/conf/httpd.conf

Test and restart Apache:

sudo httpd -t
sudo systemctl restart httpd

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

Hosting a site under a dedicated non-sudo user is safer than running everything under your admin account.

Create a system user:

sudo useradd -m -s /bin/bash -p '!' dolphin

Create the site directory and fix ownership:

sudo mkdir -p /srv/http/dolphin/example.com
sudo chown -R dolphin:dolphin /srv/http/dolphin
sudo chmod 711 /srv/http/dolphin
sudo chmod -R 755 /srv/http/dolphin/example.com

Replace dolphin with your actual user and example.com with your domain.

Copy the PHP-FPM pool config:

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

Set:

[dolphin]
user = dolphin
group = dolphin

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

listen.owner = http
listen.group = http
listen.mode = 0660

Restart PHP-FPM:

sudo systemctl restart php-fpm

Enable Apache virtual hosts:

sudo sed -i 's/^#\(Include conf\/extra\/httpd-vhosts\.conf\)/\1/' /etc/httpd/conf/httpd.conf

Edit the virtual host config:

sudo vim /etc/httpd/conf/extra/httpd-vhosts.conf

Replace the existing content with:

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

    DocumentRoot /srv/http/dolphin/example.com

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

    ErrorLog /var/log/httpd/example.com_error.log
    CustomLog /var/log/httpd/example.com_access.log combined

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

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

    DocumentRoot /srv/http/dolphin/example.com

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

    SSLEngine on
    SSLCertificateFile /etc/httpd/conf/server.crt
    SSLCertificateKeyFile /etc/httpd/conf/server.key

    ErrorLog /var/log/httpd/example.com_ssl_error.log
    CustomLog /var/log/httpd/example.com_ssl_access.log combined

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

Test and restart Apache:

sudo httpd -t
sudo systemctl restart httpd

Install WordPress

Switch to the dedicated site user:

sudo su - dolphin

Download and extract WordPress:

cd /srv/http/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