LAMP înseamnă Linux, Apache, MySQL și PHP: combinația pe care rulează WordPress, Laravel, PrestaShop și majoritatea aplicațiilor PHP. În ghidul ăsta pornești de la un server Ubuntu 24.04 curat și ajungi la un site servit pe HTTPS, cu o bază de date separată pentru aplicație și fără fișiere de test uitate pe server.
E scris pentru cine administrează singur un server: dezvoltatori, administratori, oricine are acces root la un VPS. Versiunile sunt cele din depozitele oficiale Ubuntu 24.04 la sfârșitul lui septembrie 2026: Apache 2.4.58, MySQL 8.0.46, PHP 8.3.6 și Certbot 2.9.0. La final găsești varianta cu Nginx (LEMP) și ce se schimbă pe Debian 12/13 și pe AlmaLinux sau Rocky Linux 9.
Ce îți trebuie
- Un server cu Ubuntu 24.04 LTS. Are suport standard până în mai 2029. Pe un VPS BTS alegi sistemul de operare la configurare. Cu varianta Self ai root complet și administrezi tu sistemul și aplicațiile, deci ghidul ăsta e pentru tine. Cu Managed, sistemul, actualizările și monitorizarea rămân la BTS.
- Un utilizator cu drepturi sudo, autentificare SSH cu cheie și UFW activ, cu OpenSSH permis. Dacă n-ai făcut încă asta, începe cu configurarea inițială a serverului Ubuntu.
- Un domeniu cu înregistrări A pentru
exemplu.roșiwww.exemplu.rospre IP-ul serverului. Fără ele nu poți obține certificatul HTTPS.
În exemple, exemplu.ro e domeniul tău, 203.0.113.10 e IP-ul serverului, iar utilizator e contul tău cu sudo. Le înlocuiești peste tot.
Pasul 1: actualizează sistemul
sudo apt update && sudo apt upgrade -y
Pasul 2: instalează Apache și deschide porturile web în UFW
sudo apt install -y apache2
Apache pornește singur după instalare. Pachetul adaugă în UFW profilurile Apache (doar portul 80), Apache Secure (doar 443) și Apache Full (ambele). Ai nevoie de ambele porturi, pentru că Certbot validează domeniul pe HTTP, iar site-ul va rula pe HTTPS:
sudo ufw app list
sudo ufw allow "Apache Full"
sudo ufw status
În lista de reguli trebuie să vezi OpenSSH și Apache Full. Dacă ufw status spune inactive, ordinea contează: permiți întâi SSH, abia apoi activezi firewallul. Altfel îți tai singur accesul la server.
sudo ufw allow OpenSSH
sudo ufw enable
Verifici că Apache răspunde:
curl -sI http://localhost | head -1
Răspunsul așteptat e HTTP/1.1 200 OK. Din browser, http://203.0.113.10 afișează pagina implicită „Apache2 Default Page”.
Pasul 3: instalează MySQL 8.0
sudo apt install -y mysql-server
sudo systemctl status mysql --no-pager
Ubuntu 24.04 livrează MySQL 8.0. Oracle a încheiat suportul pentru seria 8.0 în aprilie 2026, dar pe Ubuntu 24.04 pachetul primește în continuare corecturi de securitate de la echipa Ubuntu. Poți verifica singur data ultimei corecturi:
zcat /usr/share/doc/mysql-server-8.0/changelog.Debian.gz | head -3
Securizează instalarea cu mysql_secure_installation
sudo mysql_secure_installation
Scriptul pune câteva întrebări:
- VALIDATE PASSWORD component: răspunde
n. Componenta verifică parolele alese de oameni, dar în ghidul ăsta parolele le generezi aleator, cu 32 de caractere. În plus, cu ea activă instalarea phpMyAdmin din Pasul 8 eșuează cuERROR 1819, pentru că pachetul își creează utilizatorul întâi fără parolă. - Remove anonymous users:
y. - Disallow root login remotely:
y. - Remove test database:
y. - Reload privilege tables:
y.
Scriptul nu îți cere parolă pentru root: pe Ubuntu, contul root din MySQL se autentifică prin auth_socket, adică intri ca root în MySQL doar dacă ești root în sistem (sudo mysql). E o setare bună și o lași așa. Aplicațiile nu folosesc niciodată contul root.
Creează baza de date și utilizatorul aplicației
Fiecare aplicație primește baza ei și un utilizator care are drepturi doar pe acea bază. Generezi parola și o salvezi imediat în managerul de parole:
PAROLA_DB="$(openssl rand -base64 24)"
echo "$PAROLA_DB"
Creezi baza și utilizatorul. Parola intră din variabilă, deci nu rămâne scrisă în istoricul shellului:
sudo mysql <<SQL
CREATE DATABASE exemplu_db CHARACTER SET utf8mb4;
CREATE USER 'exemplu_user'@'localhost' IDENTIFIED BY '${PAROLA_DB}';
GRANT ALL PRIVILEGES ON exemplu_db.* TO 'exemplu_user'@'localhost';
SQL
unset PAROLA_DB
'localhost' înseamnă că utilizatorul se poate conecta doar de pe server. Nu folosi '%': ar accepta conexiuni de oriunde, iar aplicația rulează oricum pe aceeași mașină.
Verifici că utilizatorul vede doar baza lui:
mysql -u exemplu_user -p -e "SHOW DATABASES;"
După parolă, lista conține exemplu_db, information_schema și performance_schema, nimic altceva. Dacă aplicația încearcă să creeze altă bază, primește Access denied.
Alternativă: MariaDB
Dacă aplicația ta recomandă MariaDB, instalezi mariadb-server în locul lui mysql-server, nu alături de el. Ubuntu 24.04 are MariaDB 10.11:
sudo apt install -y mariadb-server
sudo mariadb-secure-installation
La prima întrebare apeși Enter (root nu are parolă), la „Switch to unix_socket authentication” și „Change the root password” răspunzi n, iar la restul y. Blocul SQL de mai sus merge neschimbat, rulat cu sudo mariadb sau sudo mysql.
Pasul 4: instalează PHP 8.3 și extensiile uzuale
sudo apt install -y php libapache2-mod-php php-mysql php-curl php-gd php-mbstring php-xml php-zip php-intl
libapache2-mod-php încarcă PHP direct în Apache, iar php-mysql aduce mysqli și pdo_mysql, prin care aplicația vorbește cu baza de date. Restul sunt extensiile cerute de majoritatea CMS-urilor: curl pentru cereri HTTP, gd pentru imagini, mbstring pentru text UTF-8, xml, zip pentru actualizări și intl pentru formatări locale.
php -v
php -m | grep -E "mysqli|pdo_mysql"
Prima comandă afișează PHP 8.3.6, a doua cele două extensii de MySQL.
Modulul PHP pentru Apache trece serverul pe mpm_prefork. Pentru un site sau câteva, e suficient. Dacă ai trafic mare, varianta cu PHP-FPM (vezi secțiunea despre Nginx) consumă mai puțină memorie.
Pasul 5: configurează un virtual host pentru domeniu
Un virtual host îi spune lui Apache ce director servește pentru un anumit domeniu. Așa poți ține mai multe site-uri pe același server.
Directorul site-ului și permisiunile
sudo mkdir -p /var/www/exemplu.ro/public
sudo chown -R "$USER":www-data /var/www/exemplu.ro
sudo chmod 2750 /var/www/exemplu.ro /var/www/exemplu.ro/public
Ce înseamnă 2750: tu (proprietarul) scrii, Apache (grupul www-data) doar citește, iar ceilalți utilizatori ai serverului nu văd nimic. Cifra 2 e bitul setgid: fișierele pe care le creezi în director primesc automat grupul www-data, deci Apache le poate citi fără alte ajustări.
Nu folosi chmod 777. Dacă aplicația trebuie să scrie într-un director (încărcări, cache), dai drept de scriere grupului doar pe acel director:
mkdir -p /var/www/exemplu.ro/public/uploads
sudo chmod 2770 /var/www/exemplu.ro/public/uploads
O pagină simplă, ca să vezi că site-ul răspunde:
echo '<h1>exemplu.ro funcționează</h1>' > /var/www/exemplu.ro/public/index.html
Fișierul virtual host
sudo tee /etc/apache2/sites-available/exemplu.ro.conf > /dev/null <<'CONF'
<VirtualHost *:80>
ServerName exemplu.ro
ServerAlias www.exemplu.ro
DocumentRoot /var/www/exemplu.ro/public
<Directory /var/www/exemplu.ro/public>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/exemplu.ro-error.log
CustomLog ${APACHE_LOG_DIR}/exemplu.ro-access.log combined
</VirtualHost>
CONF
Options -Indexes oprește listarea fișierelor când lipsește index. AllowOverride All permite fișiere .htaccess, de care au nevoie WordPress și majoritatea CMS-urilor pentru linkurile „frumoase”. Dacă aplicația ta nu folosește .htaccess, pune AllowOverride None.
Activează site-ul și dezactivează pagina implicită
sudo a2ensite exemplu.ro.conf
sudo a2dissite 000-default.conf
sudo a2enmod rewrite
sudo apache2ctl configtest
configtest trebuie să se încheie cu Syntax OK. Mesajul AH00558: Could not reliably determine the server's fully qualified domain name e doar un avertisment (îl rezolvi la „Probleme frecvente”). Pentru că ai activat un modul nou, repornești Apache, nu doar reîncarci configurația:
sudo systemctl restart apache2
Poți testa virtual hostul înainte să schimbi DNS-ul. De pe calculatorul tău:
curl --resolve exemplu.ro:80:203.0.113.10 http://exemplu.ro/
Răspunsul e pagina ta de test, nu pagina implicită Apache.
Pasul 6: testează PHP, apoi șterge fișierul de test
echo '<?php phpinfo();' > /var/www/exemplu.ro/public/info.php
curl -s -H "Host: exemplu.ro" http://127.0.0.1/info.php | grep -o "PHP Version [0-9.]*" | head -1
Dacă vezi PHP Version 8.3.6, Apache execută PHP. Poți deschide și http://exemplu.ro/info.php în browser, după ce DNS-ul arată spre server: vezi versiunea, extensiile încărcate și configurația.
Exact din acest motiv fișierul nu rămâne pe server. phpinfo() arată căi, versiuni și setări, informații utile oricui caută o vulnerabilitate. Îl ștergi imediat:
rm /var/www/exemplu.ro/public/info.php
Pasul 7: HTTPS gratuit cu Let’s Encrypt și Certbot
Înainte de acest pas, exemplu.ro și www.exemplu.ro trebuie să arate deja spre 203.0.113.10, iar portul 80 trebuie să fie deschis. Let’s Encrypt verifică domeniul printr-o cerere HTTP.
Instalezi Certbot și pluginul pentru Apache din depozitele Ubuntu:
sudo apt install -y certbot python3-certbot-apache
Ceri certificatul pentru ambele nume:
sudo certbot --apache -d exemplu.ro -d www.exemplu.ro
Certbot îți cere o adresă de email și acceptarea termenilor, obține certificatul, creează virtual hostul pentru portul 443 și adaugă redirecționarea de pe HTTP pe HTTPS. În Certbot 2.9, redirecționarea e activă implicit.
Reînnoirea automată
Certificatele Let’s Encrypt sunt valabile 90 de zile. Pachetul Certbot din Ubuntu instalează un timer systemd care încearcă reînnoirea de două ori pe zi și reînnoiește doar certificatele aproape de expirare. Verifici timerul și simulezi o reînnoire:
sudo systemctl list-timers certbot.timer
sudo certbot renew --dry-run
sudo certbot certificates
Atenție: de la 4 iunie 2025, Let’s Encrypt nu mai trimite emailuri de avertizare înainte de expirare. Dacă reînnoirea automată se strică, nu te mai anunță nimeni. Rulează certbot renew --dry-run după orice modificare de configurație Apache și, dacă poți, pune data de expirare a certificatului într-un sistem de monitorizare.
Pasul 8 (opțional): phpMyAdmin, accesibil doar prin tunel SSH
phpMyAdmin e o interfață web pentru MySQL. Lăsat public, /phpmyadmin e una dintre primele adrese încercate de boții care caută servere vulnerabile. Varianta sigură: îl instalezi, îl închizi pentru tot internetul și ajungi la el printr-un tunel SSH.
Dacă nu ai nevoie de interfață web, sari peste pas. Din linia de comandă (sudo mysql) poți face tot.
sudo apt install phpmyadmin
La instalare:
- Web server to reconfigure automatically: apeși Space pe
apache2, ca să apară*, apoi Enter. - Configure database for phpmyadmin with dbconfig-common:
Yes. - MySQL application password: lași gol și apeși Enter. Se generează o parolă aleatoare pentru utilizatorul intern
phpmyadmin.
Acum închizi accesul din afară. Un fișier separat de configurație permite doar cereri care vin de pe server:
sudo tee /etc/apache2/conf-available/phpmyadmin-local.conf > /dev/null <<'CONF'
<Directory /usr/share/phpmyadmin>
Require local
</Directory>
CONF
sudo a2enconf phpmyadmin-local
sudo apache2ctl configtest
sudo systemctl reload apache2
De pe calculatorul tău, verifici că accesul direct e blocat:
curl -s -o /dev/null -w "%{http_code}\n" http://203.0.113.10/phpmyadmin/
Răspunsul corect e 403. Apoi deschizi tunelul, tot de pe calculatorul tău:
ssh -N -L 8080:127.0.0.1:80 utilizator@203.0.113.10
Cât timp comanda rulează, deschizi în browser http://localhost:8080/phpmyadmin/. Pentru Apache, cererea vine de pe server, deci e permisă. Te autentifici cu exemplu_user și vezi doar exemplu_db, plus bazele de sistem information_schema și performance_schema. Cu root nu poți intra (phpMyAdmin răspunde cu Access denied for user 'root'@'localhost'), pentru că root se autentifică prin auth_socket, și e bine așa. Închizi tunelul cu Ctrl+C.
Varianta cu Nginx și PHP-FPM (LEMP)
Dacă preferi Nginx, pașii pentru MySQL rămân aceiași. Se schimbă serverul web și felul în care rulează PHP: Nginx nu încarcă PHP în proces, ci trimite cererile către PHP-FPM, un serviciu separat. Nu instala Apache și Nginx pe același server: ambele vor portul 80.
sudo apt install -y nginx php-fpm php-mysql
sudo ufw allow "Nginx Full"
Directorul site-ului îl creezi la fel ca la Pasul 5, cu aceleași permisiuni: și Nginx, și PHP-FPM rulează ca www-data. Configurația site-ului:
sudo tee /etc/nginx/sites-available/exemplu.ro > /dev/null <<'CONF'
server {
listen 80;
listen [::]:80;
server_name exemplu.ro www.exemplu.ro;
root /var/www/exemplu.ro/public;
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;
}
}
CONF
sudo ln -s /etc/nginx/sites-available/exemplu.ro /etc/nginx/sites-enabled/
sudo unlink /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
Diferențele care contează în practică:
- Nginx ignoră
.htaccess. Regulile de rescriere ale aplicației le muți în bloculserver. Pentru WordPress,try_files $uri $uri/ /index.php?$args;în locul liniei cu=404. - HTTPS: instalezi
python3-certbot-nginxși rulezicertbotcu--nginxîn loc de--apache. - phpMyAdmin se configurează automat doar pentru Apache. Pe Nginx îl legi manual.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d exemplu.ro -d www.exemplu.ro
Pe Debian 12/13 și pe AlmaLinux sau Rocky Linux 9
Debian 12 și 13. Pașii sunt aproape identici, cu trei diferențe. MySQL nu există în depozitele Debian, așa că folosești MariaDB (10.11 pe Debian 12, 11.8 pe Debian 13). PHP e 8.2 pe Debian 12 și 8.4 pe Debian 13, deci socketul PHP-FPM devine php8.2-fpm.sock, respectiv php8.4-fpm.sock. UFW nu e instalat implicit (după instalare îl activezi ca la Pasul 2, cu OpenSSH permis înainte), iar pe Debian 12 pachetul apache2 nu aduce profilul Apache Full. Folosești profilul WWW Full (porturile 80 și 443), care există pe ambele versiuni.
sudo apt install -y apache2 mariadb-server php libapache2-mod-php php-mysql ufw
sudo ufw allow "WWW Full"
sudo mariadb-secure-installation
AlmaLinux 9 și Rocky Linux 9. Implicit, dnf instalează PHP 8.0, o versiune fără suport din noiembrie 2023, și MySQL 8.0. Activezi întâi fluxurile de module pentru PHP 8.3 și MySQL 8.4, apoi instalezi:
sudo dnf module enable -y php:8.3 mysql:8.4
sudo dnf install -y httpd mysql-server php php-mysqlnd
sudo systemctl enable --now httpd php-fpm mysqld
sudo mysql_secure_installation
Aici contul root din MySQL nu folosește auth_socket: după instalare are parola goală, iar mysql_secure_installation îți cere să setezi una. Folosește tot o parolă generată și păstreaz-o în managerul de parole. Blocul SQL de la Pasul 3 îl rulezi cu mysql -u root -p în loc de sudo mysql.
Firewallul e firewalld. Unele imagini minimale nu îl au instalat; zona lui implicită permite deja SSH, deci nu îți pierzi accesul când îl pornești. Certbot vine din depozitul EPEL:
sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --reload
sudo dnf install -y epel-release
sudo dnf install -y certbot python3-certbot-apache
Ce mai diferă pe familia Red Hat: pachetul se numește httpd, nu apache2; virtual hostul îl pui direct în /etc/httpd/conf.d/exemplu.ro.conf (nu există a2ensite); Apache rulează ca utilizatorul apache, nu www-data, deci directorul site-ului primește grupul apache; PHP rulează implicit prin PHP-FPM; grupul de administratori e wheel, nu sudo. Cu SELinux activ, ține site-urile sub /var/www, unde contextul de securitate e deja corect.
Verificare finală
systemctl is-active apache2 mysql
sudo apache2ctl -S
curl -sI https://exemplu.ro | head -1
curl -s -o /dev/null -w "%{http_code}\n" https://exemplu.ro/info.php
Ce trebuie să vezi: ambele servicii active; în apache2ctl -S, exemplu.ro pe porturile 80 și 443 și niciun 000-default; HTTP/1.1 200 OK pe HTTPS; 404 pentru info.php.
Probleme frecvente
Avertismentul AH00558: Could not reliably determine the server's fully qualified domain name. Nu blochează nimic, dar îl elimini dându-i lui Apache un nume global:
echo "ServerName localhost" | sudo tee /etc/apache2/conf-available/servername.conf
sudo a2enconf servername
sudo apache2ctl configtest
sudo systemctl reload apache2
403 Forbidden pe site. De obicei lipsește fișierul index (iar listarea e oprită prin -Indexes) sau Apache nu poate citi directorul. Jurnalul de erori al site-ului îți spune exact care e cauza:
sudo tail -n 20 /var/log/apache2/exemplu.ro-error.log
ls -ld /var/www/exemplu.ro /var/www/exemplu.ro/public
AH01276: Cannot serve directory înseamnă că lipsește fișierul index. AH01630: client denied by server configuration înseamnă că o regulă Require blochează accesul (de exemplu, restricția pentru phpMyAdmin de la Pasul 8). Dacă e o problemă de permisiuni, directoarele trebuie să aibă grupul www-data și drept de citire pentru grup.
Browserul descarcă fișierul .php sau îi afișează codul. Modulul PHP nu e activ în Apache:
sudo a2enmod php8.3
sudo systemctl restart apache2
Dacă a2enmod php8.3 se oprește cu ERROR: Module mpm_event is enabled - cannot proceed due to conflicts, Apache rulează cu mpm_event, iar modulul PHP are nevoie de mpm_prefork. Dezactivezi întâi mpm_event, activezi mpm_prefork și modulul PHP, apoi repornești Apache:
sudo a2dismod mpm_event && sudo a2enmod mpm_prefork php8.3
sudo systemctl restart apache2
Certbot eșuează la validare. Aproape mereu cauza e DNS-ul (domeniul nu arată încă spre server) sau portul 80 închis. Verifici ce IP vede serverul pentru domeniu și regulile firewallului:
getent hosts exemplu.ro
sudo ufw status
Instalarea phpMyAdmin se oprește cu ERROR 1819 (HY000): Your password does not satisfy the current policy requirements. Contul MySQL pe care pachetul îl creează întâi fără parolă nu trece de politica componentei validate_password, activată la Pasul 3. Dezinstalezi componenta și reconfigurezi pachetul. La întrebarea „Reinstall database for phpmyadmin?” răspunzi Yes:
sudo mysql -e "UNINSTALL COMPONENT 'file://component_validate_password';"
sudo dpkg-reconfigure phpmyadmin
Rezumat
- Apache din depozitele Ubuntu, cu porturile 80 și 443 deschise prin profilul UFW
Apache Full, după ce OpenSSH e deja permis. - MySQL 8.0 securizat cu
mysql_secure_installation; root rămâne peauth_socket, iar aplicația are utilizatorul ei, limitat la baza ei și lalocalhost. - PHP 8.3 cu
libapache2-mod-phpși extensiile uzuale;info.phpfolosit pentru test, apoi șters. - Un virtual host pe domeniu, cu permisiuni
2750, fără777și fără pagina implicită Apache. - HTTPS cu Certbot și reînnoire automată, pe care o verifici tu, pentru că Let’s Encrypt nu mai trimite emailuri de expirare.
- phpMyAdmin doar dacă ai nevoie de el, închis pentru internet și folosit prin tunel SSH.
Documentația oficială pentru pașii de aici: ghidul Apache din Ubuntu Server, virtual hosts în Apache, crearea utilizatorilor în MySQL, instrucțiunile Certbot și manualul PHP.



