Preparation
- VPS with Ubuntu 20.04/22.04/24.04 or Debian 11/12.
- User with sudo, SSH access.
- Domain (optional) and open port 80/443 in the provider’s panel.
Apache: installation, autostart, and verification
sudo apt update && sudo apt -y upgrade
sudo apt -y install apache2
sudo systemctl enable --now apache2
curl -I http://127.0.0.1
Expecting HTTP/1.1 200 OK headers. The default page is located in /var/www/html/.
UFW firewall for HTTP/HTTPS and service status
sudo systemctl status apache2 --no-pager
sudo ufw allow 'Apache Full' # opens 80 и 443
sudo ufw enable
sudo ufw status
If you are not using UFW, ensure that 80/443 are allowed in your provider’s cloud firewall.
MySQL Server: installation and basic protection
sudo apt -y install mysql-server
sudo systemctl enable --now mysql
sudo mysql_secure_installation
Respond securely:
- Enable password strength checking (Yes).
- Remove anonymous users (Yes).
- Disallow remote root login (Yes).
- Remove test database (Yes).
- Reload privileges (Yes).
Creating a database and user for the application
sudo mysql -u root -p
In the MySQL console:
CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'S3cureP@ss!';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;
For remote access, specify the host: “appuser”@‘%’ and configure the bind-address/firewall in isolation.
PHP: module installation and test page
sudo apt -y install php libapache2-mod-php php-mysql php-cli php-curl php-xml php-zip
php -v
echo '' | sudo tee /var/www/html/info.php
Open http://<IP>/info.php in your browser to see the phpinfo() page (then delete it).
Production directory and Apache virtual host
Let’s create the site structure and configuration file:
sudo mkdir -p /var/www/example.com/public_html
sudo chown -R $USER:$USER /var/www/example.com
sudo nano /var/www/example.com/public_html/index.php
index.php (verification PHP):
Create the configuration file /etc/apache2/sites-available/example.com.conf:
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
AllowOverride All
Require all granted
ErrorLog ${APACHE_LOG_DIR}/example_error.log
CustomLog ${APACHE_LOG_DIR}/example_access.log combined
AllowOverride All is needed if you use .htaccess (rewrites, caching, etc.).
Activate the site, mod_rewrite, and reread the config.
sudo a2ensite example.com.conf
sudo a2dissite 000-default.conf
sudo a2enmod rewrite
sudo apache2ctl configtest # Syntax OK
sudo systemctl reload apache2
Check the website by domain or IP: Hello from LAMP! should open.
Checking the PHP ↔ MySQL (PDO) connection
Create /var/www/example.com/public_html/dbtest.php:
PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
echo $pdo->query('SELECT 1')->fetchColumn();
} catch (Throwable $e) { echo $e->getMessage(); }
Open http://example.com/dbtest.php → you will see 1.
HTTPS in 2 minutes (bonus)
If the domain points to the server, we install a free certificate:
sudo apt -y install certbot python3-certbot-apache
sudo certbot --apache -d example.com -d www.example.com
Certbot will automatically enable HTTPS and auto-renewal.
Configuring PHP for production (briefly)
Edit /etc/php/*/apache2/php.ini:
- expose_php = Off
- memory_limit = 256M (depending on load)
- upload_max_filesize and post_max_size according to your CMS
- date.timezone = Europe/Kyiv
- Restart Apache: sudo systemctl reload apache2.
Analogues for AlmaLinux/Rocky/CentOS (RHEL)
sudo dnf -y install httpd mariadb-server php php-mysqlnd php-cli php-xml php-zip php-curl
sudo systemctl enable --now httpd mariadb
sudo mysql_secure_installation
# дальше — те же шаги: создать БД/пользователя, vhost в /etc/httpd/conf.d/site.conf,
# включить firewalld: sudo firewall-cmd --add-service=http --add-service=https --permanent && sudo firewall-cmd --reload
LAMP startup checklist
- Apache is running, 80/443 are open, mod_rewrite is enabled.
- MySQL is secured, appdb and appuser are created.
- PHP is installed with necessary modules, info.php is removed.
- Virtual host is enabled, AllowOverride All is set.
- dbtest.php returns 1 (PDO works).
- HTTPS is enabled (if there is a domain), cron/auto-renew is active.