Indice
- Comandi di base e configurazione iniziale
- Macchina Oracle cloud “Always free”
- Firewall (firewalld)
- Gestione pacchetti con DNF
- SSH con autenticazione a chiave
- Git con GitHub e Bitbucket
- Cartelle condivise (VMware Shared Folders e Samba)
- Stack LAMP
- phpMyAdmin
- WordPress
- Certificati SSL/TLS per i siti Apache
- Basic Auth Apache
Comandi di base e configurazione iniziale
Questa guida assume che Linux (AlmaLinux, RockyLinux, oppure Oracle Linux 10) sia disponibile come macchina remota (attraverso servizi come digital oceans, oppure aruba cloud) oppure che firi come macchina virtuale (VMware).
Nel caso di una macchina locale la modalità di rete utilizzata è NAT, con macchina host Windows 11.
La guida è compatibile anche se usi linux su Virtualbox, l’unica differenza è come fare i port forwarding
Port Forwarding
Recperare l’ip della macchina virtuale. Da dentro oracle linux eseguire il comando ip a. Nel mio caso l’ip della macchina è 192.168.86.128
Dalla interfaccia di WMware acedi alla voce di menu Edit / Virtual Network Editor
Clicca sul pulsante Change Settings

Clicca sulla riga VMnet8 e poi su NAT settings

Cliccare sul tasto Add e impostare la regole seguendo come da immagine, modificando dove serve

L’immagine precedente imposta la reole per accedere alla macchina con ssh. Per accedere alla macchina posso usare il comando seguente, sostituendo il nome utente reale
ssh localhost@[nomeutente] -p 34522
Comandi di sistema essenziali
Ecco i comandi che userai di più nella gestione quotidiana
# Aggiornare il sistema
sudo dnf update -y
# Riavviare / spegnere
sudo reboot
sudo shutdown -h now
# Informazioni sul sistema
uname -a
cat /etc/os-release
hostnamectl
# Gestione servizi (systemd)
sudo systemctl start [servizio]
sudo systemctl stop [servizio]
sudo systemctl restart [servizio]
sudo systemctl enable [servizio] # avvio automatico al boot
sudo systemctl disable [servizio]
sudo systemctl status [servizio]
# Monitoraggio processi e risorse
top
htop # più leggibile, installa con: sudo dnf install htop -y
df -h # spazio disco
free -h # memoria RAM
Abilitare CRB, EPEL e REMI
Questi repository estendono i pacchetti disponibili su distribuzioni AlmaLinux/RockyLinux/Oracle Linux 10.
- CRB (CodeReady Builder): contiene pacchetti di sviluppo e dipendenze che normalmente non sono incluse nel repo base. Molti pacchetti di EPEL e REMI lo richiedono.
- EPEL (Extra Packages for Enterprise Linux): repository della community Fedora con centinaia di pacchetti non presenti nei repo ufficiali Red Hat/Oracle.
- REMI: repository specializzato per versioni aggiornate di PHP, MySQL e software LAMP. Fondamentale per installare PHP 8.5.
Per Oracle Linux 10 puoi i seguenti comandi
# Command to install the EPEL repository configuration package:
sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm
# abilitare crb
sudo /usr/bin/crb status
sudo /usr/bin/crb enable
# Command to install the Remi repository configuration package:
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-10.rpm
sudo dnf update
Per AlmaLinux / RockyLinux 10 puoi usare i seguenti comandi
sudo dnf config-manager --set-enabled crb
sudo dnf install epel-release
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-10.rpm
sudo dnf update
Disabilitare SELinux
SELinux (Security-Enhanced Linux) è un sistema di controllo degli accessi obligtorio. In produzione va gestito correttamente, ma su un server di sviluppo locale crea spesso problemi con Apache, PHP e la lettura delle cartelle condivise.
Esegui la seguente linea di codice e poi riavvia la macchina
sudo sed -i -e "s/^SELINUX=.*/SELINUX=disabled/" /etc/selinux/config
Impostare il timezone
Verifica che il tuo timezone sia corretto, e nel caso correggilo con i seguenti comandi
# Verificare
timedatectl
date
# Elencare i timezone disponibili (filtrando per Europa)
timedatectl list-timezones | grep Europe
# Impostare Roma
sudo timedatectl set-timezone Europe/Rome
Programmi aggiuntivi
Opzionalmente puoi installare i seuenti programmi aggiuntivi
sudo dnf install wget curl zip unzip nano tar rsync dos2unix
Dopo aver abilitato epel-release puoi installare anche i seguenti programmi
sudo dnf install htop
Gestione pachetti con DNF
# per vedere i programmi installati
sudo dnf list installed
# per vedere se un programma è installato
sudo dnf list installed | grep libreoffice
# per rimuovere un pacchetto e le sue dipendenze
sudo dnf remove libreoffice*
# pulizia dei pacchetti residui
sudo dnf autoremove
sudo dnf clean all
Macchina Oracle cloud “Always free”
Tutorial utile a questa pagina
Tenere attiva istanza Oracle con stress ng
Le risorse che non vengono utilizzate a sufficienza possono essere ritirate da Oracle. Vedere di più a questa pagina.
Per evitare ciò possiamo usare l’utility stress-ng e schedularla di notte di modo che la nostra istanza continui a funzionare nel tempo. Per prima cosa procediamo a installare l’utility
sudo dnf install stress-ng
Dopodichè il comando che esegue è il seguente
stress-ng -c `grep -c ^processor /proc/cpuinfo` -t 5000 -l 22
dove
- -c grep -c ^processor /proc/cpuinfo recupera il numero di CPU
- -t 5000 è il numero di secondi impiegato dal job, poco meno di 1h e mezza
- -l 22 indica la percentuale stress
Per far girare questo applicativo ogni giorno aggiungere ils eguente comando a cronjob
sudo crontab -e
# strees ng per macchine oracle
00 05 * * * stress-ng -c `grep -c ^processor /proc/cpuinfo` -t 5000 -l 22
Aprire porte 80 e 443 per macchina oracle linux
Se usi una macchina virtuale “always free” creata su oracle linux assicurati di avere le porte 443 e 80 apert. Per fare ciò segui questi screenshot.
- Entra dentro la sezione “Networking” della macchina. Nella sezione “Attached VNICs” clicca sul link che porta alla tua subnet

- Vai nel tab “Security” e infine clicca sulla riga relativa alla security list

- Naviga nel tab “Security rules” e infine aggiungi le regole per le porte 80 e 443 se non esistono


Aggiungere Swap
Se con il comando free -h oppure swapon --show lo spazio di swap è 0 ti consiglio di impostare lo spazio di swap. Per fare ciò crea prima il file di swap e imposta i permessi corretti.
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
Dopodichè formatta il file come swap, e attiva lo swap
sudo mkswap /swapfile
sudo swapon /swapfile
Verifica che vi sia 2GB eseguendo il comando free -h. Per rendere lo swap permanente aggiungi la seguente voce in /etc/fstab
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Ora settiamo quanto il kernel deve usare lo swap, impostando lo swappiness
# Imposta subito (senza riavvio)
sudo sysctl vm.swappiness=10
# Rendi permanente
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Verifica con il seguente comando, dovrebbe restituire 10
cat /proc/sys/vm/swappiness
Firewall (firewalld)
Oracle Linux 10 usa firewalld come frontend per iptables. Il concetto base è quello delle zone: ogni interfaccia di rete viene assegnata a una zona con regole specifiche. La zona di default è public
Comandi base
# Stato del firewall
sudo systemctl status firewalld
sudo firewall-cmd --state
# Avviare e abilitare al boot
sudo systemctl enable --now firewalld
# Vedere tutte le regole attive
sudo firewall-cmd --list-all
# Vedere le zone disponibili
sudo firewall-cmd --get-zones
sudo firewall-cmd --get-active-zones
Abilitare servizi http e https
# Aggiungere http e https (permanente)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
# Ricaricare per applicare le modifiche permanenti
sudo firewall-cmd --reload
# Verificare
sudo firewall-cmd --list-services
Abilitare RDP
sudo firewall-cmd --permanent --add-port=3389/tcp
sudo firewall-cmd --reload
Aprire porte singole
# Aprire la porta 3389 (TCP)
sudo firewall-cmd --permanent --add-port=3389/tcp
# Aprire una porta custom, es. 8080
sudo firewall-cmd --permanent --add-port=8080/tcp
# Aprire un range di porte
sudo firewall-cmd --permanent --add-port=8080-8090/tcp
# Ricaricare
sudo firewall-cmd --reload
# Verificare le porte aperte
sudo firewall-cmd --list-ports
Rimuovere regole
# Rimuovere un servizio
sudo firewall-cmd --permanent --remove-service=http
# Rimuovere una porta
sudo firewall-cmd --permanent --remove-port=3389/tcp
# Ricaricare
sudo firewall-cmd --reload
Per disabilitare e fermare il firewall
sudo systemctl stop firewalld
sudo systemctl disable firewalld
# per verifica
sudo systemctl status firewalld
Gestione pacchetti con DNF
DNF è il package manager di Oracle Linux 10 (successore di YUM). Gestisce l’installazione, aggiornamento e rimozione di software.
Di seguito una serie di comandi base
# Aggiornare tutti i pacchetti
sudo dnf update -y
# Installare un pacchetto
sudo dnf install [nome-pacchetto] -y
# Installare più pacchetti
sudo dnf install wget curl git vim -y
# Rimuovere un pacchetto
sudo dnf remove [nome-pacchetto] -y
# Cercare un pacchetto
sudo dnf search [termine]
# Informazioni su un pacchetto
sudo dnf info [nome-pacchetto]
# Elencare i pacchetti installati
sudo dnf list installed
sudo dnf list installed | grep php
# Pulire la cache
sudo dnf clean all
# Vedere la cronologia delle operazioni
sudo dnf history
# Annullare l'ultima operazione
sudo dnf history undo last
# Elencare i gruppi disponibili
sudo dnf group list
# Installare un gruppo di pacchetti
sudo dnf group install 'Development Tools' -y
SSH con autenticazione a chiave
Macchina remota cloud
L’autenticazione con chiave SSH è più sicura della password. Generi una coppia di chiavi sul tuo PC, copi la chiave pubblica sul server, e da quel momento ti connetti senza digitare la password.
Installa ssh sul server
sudo dnf install openssh-server
sudo systemctl enable --now sshd
# per verificare ssh
sudo systemctl status sshd
Genera la coppia di chiavi in locale, sul tuo PC
# Sul tuo computer locale (Windows PowerShell / macOS / Linux)
ssh-keygen -t ed25519 -C 'mio-server-oracle'
# Ti chiede dove salvare (default: ~/.ssh/id_ed25519)
# e una passphrase opzionale (consigliata)
# Verrà creata:
# ~/.ssh/id_ed25519 (chiave privata - non condividere mai!)
# ~/.ssh/id_ed25519.pub (chiave pubblica - questa va sul server)
Copiare la chiave pubblica sul server
# Metodo 1: ssh-copy-id (Linux/macOS)
ssh-copy-id -i ~/.ssh/id_ed25519.pub utente@ip-server
# Metodo 2: manuale (se ssh-copy-id non è disponibile)
# Sul server, crea la cartella .ssh e il file authorized_keys
mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
# Incolla il contenuto del file id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
Configura SSH sul server
sudo nano /etc/ssh/sshd_config
# Valori consigliati:
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication no # disabilita login con password
PermitRootLogin no # blocca login diretto come root
# Riavviare il servizio
sudo systemctl restart sshd
# Aprire la porta SSH nel firewall (se non già aperta)
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
Crea il file config SSH locale (sul tuo PC). Il file ~/.ssh/config ti permette di definire alias e impostazioni per ogni server, evitando di digitare ogni volta ip, utente e chiave.
nano ~/.ssh/config
Host oracle-dev
HostName 192.168.1.100
User mario
IdentityFile ~/.ssh/id_ed25519
Port 22
Host oracle-prod
HostName 10.0.0.50
User deploy
IdentityFile ~/.ssh/id_ed25519_prod
Modifica le permission del file creato
sudo chmod 600 ~/.ssh/config
sudo chown $USER:$USER ~/.ssh/config
Con questo file puoi connetterti semplicemente con ssh oracle-dev
Macchina locale VMWare
Con VMware in modalità NAT e il port forwarding configurato, non ti connetti direttamente all’IP della VM ma all’IP dell’host Windows sulla porta mappata.
Nel mio caso specifico ho fatto port forwarding della porta 34522 dell’host, sulla porta 22 del guest. Quindi per colelgarmi alla machina posso fare come segue
# Da PowerShell o terminale Windows
ssh mario@127.0.0.1 -p 34522
# Oppure, se ti connetti da un altro PC sulla stessa rete
ssh mario@192.168.86.128 -p 34522
Se vuoi semplificare il comando, aggiungi una voce al file `~/.ssh/config` sul tuo PC Windows (`C:\Users\mario\.ssh\config`):
Host oracle-dev
HostName 127.0.0.1
User mario
Port 34522
Da quel momento ti basta:
ssh oracle-dev
Git con GitHub e Bitbucket
Installazione e configurazione base
sudo dnf install git
# Configurazione globale
git config --global user.name 'NomeCognome'
git config --global user.email 'nome@esempio.it'
# Verificare
git config --list
Se la cartella ~/.ssh non esiste creala ora
sudo mkdir ~/.ssh && sudo chown -R $USER:$USER ~/.ssh
Autenticazione con chiave SSH: Sia GitHub che Bitbucket supportano l’autenticazione tramite chiave SSH. Il processo è lo stesso per entrambi.
# Generare una chiave dedicata per GitHub
ssh-keygen -t ed25519 -C 'mario@esempio.it' -f ~/.ssh/id_github
# Generare una chiave dedicata per Bitbucket
ssh-keygen -t ed25519 -C 'mario@esempio.it' -f ~/.ssh/id_bitbucket
# Aggiungere le chiavi all'agente SSH
eval '$(ssh-agent -s)'
# oppure
eval "$(ssh-agent)"
# comandi per aggiungere chiavi
ssh-add ~/.ssh/id_github
ssh-add ~/.ssh/id_bitbucket
# per verificare le chiavi caricate
ssh-add -l
Per visualizzare le chiavi pubbliche da copiare su GitHub/Bitbucket
cat ~/.ssh/id_github.pub
cat ~/.ssh/id_bitbucket.pub
Copia il contenuto di ogni .pub nelle rispettive impostazioni SSH del tuo account:
- GitHub → Settings → SSH Keys
- Bitbucket → Personal settings → SSH keys
File config SSH per Git
# nano ~/.ssh/config
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_github
Host bitbucket.org
HostName bitbucket.org
User git
IdentityFile ~/.ssh/id_bitbucket
Testa la connessione con
ssh -T git@github.com
ssh -T git@bitbucket.org
Cartelle condivise (VMware Shared Folders e Samba)
VMWare cartella condivisa
Come prima cosa impostare la cartella da condividere con VMware

Supponiamo di mondare la cartella condivisa d. Crea la cartella dentro /mnt
sudo mkdir -p /mnt/d
sudo chown $USER:$USER /mnt/d
Assicurati che il comando vmware-hgfsclient venga eseguito correttamente. In caso contrario ti mancano le open-vm-tools che puoi installare così
sudo dnf install open-vm-tools fuse
Per montare la cartella host sulla cartella /mnt/d di linux lanciare il seguente comando da terminale
sudo vmhgfs-fuse .host:/ /mnt/d/ -o allow_other -o uid=1000
Oppure puoi montare tutto dentro la cartella /mnt
sudo vmhgfs-fuse .host:/ /mnt/ -o allow_other -o uid=1000
Per scoprire le cartelle condivise `.host:/` dentro usare
vmware-hgfsclient
Per montare all’avvio della macchina
# Use shared folders between VMWare guest and host
.host:/ /mnt/d/ fuse.vmhgfs-fuse defaults,allow_other,uid=1000 0 0
Samba – condivisione cartelle con Windows
Samba permette di esporre cartelle Linux come share di rete accessibili da Windows. L’utente Samba avrà lo stesso nome dell’utente Linux (mario), con una password Samba separata.
Dato che uso NAT sulla macchiana virtuale devo fare il port forwarding di una porta della macchina windows sulla macchina linux
esempio 34545 -> 445
Procedo con l’installazione di samba
# Installare Samba
sudo dnf install samba samba-client
# Abilitare e avviare
sudo systemctl enable --now smb nmb
# Aprire il firewall
sudo firewall-cmd --permanent --add-service=samba
sudo firewall-cmd --reload
Configura la share nel file smb.conf:
# sudo nano /etc/samba/smb.conf
[home-mario]
comment = Home di Mario
path = /home/mario
valid users = mario
read only = no
browsable = yes
create mask = 0664
directory mask = 0775
force user = mario
force group = mario
Ora aggiungo la password all’utente samba
sudo smbpasswd -a mario
# Riavviare Samba
sudo systemctl restart smb
Da Windows, apri Esplora File e digita nella barra degli indirizzi \\ip-del-server. Dato però che ho mappato la porta 34545 (host) sulla macchina 445 (linux) posso attaccare una directory di rete teporanea a windows specificando la porta di connessione.
net use T: \\127.0.0.1\home-mario /TCPPORT:34545 /user:mario
# per togliere la cartella di rete
NET USE T: /DELETE
Inserisci come credenziali mario e la password impostata con smbpasswd. Poiché mario è proprietario della propria home, avrà già pieno accesso in lettura e scrittura senza bisogno di modificare permessi.
Stack LAMP
Apache
Installiamo Apache (httpd) e lo configuriamo per supportare WordPress, Laravel e phpMyAdmin.
Procediamo con l’installazione
# Installazione
sudo dnf install httpd httpd-tools mod_ssl
# Abilitare e avviare
sudo systemctl enable --now httpd
Se la macchina è remota agiungiamo le seguenti regole al firewall
# lancia i seguenti comandi per aprire il firewall
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Per comodità decido di settare una variabile che riassume la porta utilizza dal web server apache
export APACHE_PORT=80
echo "export APACHE_PORT=80" >> ~/.bashrc
Se stai usando la macchina locale con NAT di seguito considero di aver fatto il port forwarding dalla porta 34580 (host) alla 34580 (guest). Quindi il web server apache risponderà all’indirizzo http://localhost:34580. Apporta le seguenti modifiche
export APACHE_PORT=34580
sudo nano /etc/httpd/conf/httpd.conf
# Assicurati che ci sia la seguente riga:
Listen 34580
# lancia i seguenti comandi per aprire il firewall
sudo firewall-cmd --zone=public --permanent --add-port=34580/tcp
sudo firewall-cmd --reload
La root di Apache sarà /var/www. Quando accedi a localhost la root è /var/www/html
Modifica il file di configurazione principale:
sudo nano /etc/httpd/conf/httpd.conf
# Cerca la riga #ServerName www.example.com:80 e sostituiscila con:
ServerName localhost
# assicurati che ci sia "AllowOverride All"
<Directory "/var/www/html">
....
AllowOverride All
Aggiungi il virtualhost per la cartella /var/www/html che risponde all’indirizzo ip della macchina. Inserisci servername e la porta corretta (NON scrivere $APACHE_PORTche non funziona correttamente).
sudo nano /etc/httpd/conf.d/000-default.conf
<VirtualHost *:......>
ServerName ......
DocumentRoot /var/www/html
<Directory "/var/www/html">
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog /var/log/httpd/error.log
CustomLog /var/log/httpd/access.log combined
</VirtualHost>
Disabilita il conf welcome.conf
sudo mv /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/welcome.conf.old
Riavvia Apache e controlla lo status
sudo systemctl restart httpd
sudo systemctl status httpd
Per ogni sito crea un file di configurazione separato in /etc/httpd/conf.d/. Inserisci la porta corretta, non scrivere $APACHE_PORT che non lo legge correttamente.
sudo nano /etc/httpd/conf.d/miosito.conf
<VirtualHost *:.......>
ServerName miosito.local
DocumentRoot /var/www/miosito
<Directory /var/www/miosito>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog /var/log/httpd/miosito-error.log
CustomLog /var/log/httpd/miosito-access.log combined
</VirtualHost>
Se sono in locale per comodità posso aggiungere il mio utente locale al gruppo apache
sudo usermod -aG apache $USER
# riavvia macchina
sudo reboot
# controlla gruppi utente corrente
groups
D’ora in poi posso aggiornare i permessi della cartella /var/www nel seguente modo (di modo che posso modificare i files con il mio utente locale)
# Imposta permessi corretti
sudo chown -R apache:apache /var/www
sudo find /var/www -type d -exec chmod 775 {} \;
sudo find /var/www -type f -exec chmod 664 {} \;
Come utility creo uno script per aggiornare i permessi della cartella corrente, di modo che possa modificare senza problemi i files e cartelle con il mio utente locale
sudo nano /usr/local/bin/aggiorna_permessi_web.sh
#!/bin/bash
# Define user and group variables
WEB_USER="apache"
WEB_GROUP="apache"
# Script to update permissions recursively from current directory
# Usage: ./update_permissions.sh
# Check if running as root or with sudo
# if [ "$EUID" -ne 0 ]; then
# echo "Please run as root or with sudo"
# exit 1
# fi
# Set ownership recursively
echo "Updating ownership to $WEB_USER:$WEB_GROUP..."
sudo chown $WEB_USER:$WEB_GROUP -R .
# Set directory permissions (775)
echo "Setting directory permissions to 775..."
sudo find . -type d -exec chmod 775 {} \;
# Set file permissions (664)
echo "Setting file permissions to 664..."
sudo find . -type f -exec chmod 664 {} \;
echo "Permissions updated successfully!"
Rendi eseguibile lo script con
sudo chmod +x /usr/local/bin/aggiorna_permessi_web.sh
Per vedere i log di apache
# Log di errore principale
sudo tail -f /var/log/httpd/error_log
# Log accessi
sudo tail -f /var/log/httpd/access_log
# Log dei virtual host specifici
sudo tail -f /var/log/httpd/miosito-error.log
# Testare la configurazione senza riavviare
sudo apachectl configtest
# Ricaricare la configurazione
sudo systemctl reload httpd
PHP 8.5
Usiamo il repository REMI per installare PHP 8.5
sudo dnf module reset php
# per vedere i moduli php
sudo dnf module list php
# abilita il modulo per php8.5
sudo dnf module enable php:remi-8.5
Installiamo php
sudo dnf install php php-cli php-fpm php-mysqlnd php-zip php-devel php-gd php-mcrypt php-mbstring php-curl php-xml php-pear php-bcmath php-json php-opcache php-intl php-soap php-xmlrpc php-gettext php-ldap php-imap php-odbc php-pdo php-common php-process php-imagick php-xdebug
Per verificare la versione
php -v
Aumenta i limiti di PHP per compatibilità con WordPress e upload di file grandi:
# Trovare il percorso del php.ini
php --ini
# Di solito si trova in /etc/php.ini
sudo nano /etc/php.ini
# Modificare questi valori:
max_execution_time = 300
max_input_time = 300
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 512M
date.timezone = Europe/Rome
Configuriamo XDebug
# Trovare il file di configurazione xdebug
php --ini | grep xdebug
# modifica il file xdebug.ini
sudo nano /etc/php.d/15-xdebug.ini
# contenuto da aggiungere
xdebug.mode = develop,debug
xdebug.start_with_request = trigger
xdebug.client_host = localhost
xdebug.client_port = 9003
Riavviamo apache e controlliamo che sia caricato il modulo xdebug
# Riavviare Apache
sudo systemctl restart httpd php-fpm
# Verificare che Xdebug sia caricato
php -m | grep xdebug
Per debuggare con vscode
- Installa l’estensione PHP Debug su VS Code
- Crea il launch.json in VS Code: Nella cartella del tuo progetto, VS Code crea automaticamente .vscode/launch.json quando premi F5 → scegli PHP. Il contenuto sarà:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003
}
]
}
Come debug aggiungiamo il file info.php alla cartella /var/www/html
echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php
sudo chown apache:apache /var/www/html/info.php
Verifica lo stato navigando su http://[server_ip]:[apache_porta]
MariaDB
Creiamo il file /etc/yum.repos.d/MariaDB.repo e aggiungiamo ils eguente contenuto
sudo nano /etc/yum.repos.d/MariaDB.repo
[mariadb]
name = MariaDB
baseurl = https://mirror1.hs-esslingen.de/pub/Mirrors/mariadb/yum/12.2/rhel/$releasever/$basearch
gpgkey = https://mirror1.hs-esslingen.de/pub/Mirrors/mariadb/yum/RPM-GPG-KEY-MariaDB
gpgcheck = 1
Installa mariadb con il seguente comando
sudo dnf install MariaDB-server MariaDB-client
In aggiunta prosegui con i seguenti comandi
# Abilitare e avviare
sudo systemctl enable --now mariadb
# Verificare la versione
mariadb --version
# Wizard di configurazione sicurezza (imposta password root, rimuove utenti anonimi, ecc.)
sudo mariadb-secure-installation
# Rispondere così:
# Enter current password for root: [invio - vuota di default]
# Switch to unix_socket auth: N
# Change root password: Y → inserisci una password sicura
# Remove anonymous users: Y
# Disallow root login remotely: Y
# Remove test database: Y
# Reload privilege tables: Y
Per gestire il database ti riporto alcune query di utilità generale
# Accedere a MariaDB
mariadb -u root -p
-- Creare un database e un utente
CREATE DATABASE miosito CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'mario'@'localhost' IDENTIFIED BY 'password-sicura';
GRANT ALL PRIVILEGES ON miosito.* TO 'mario'@'localhost';
FLUSH PRIVILEGES;
EXIT;
phpMyAdmin
Scarichiamo l’ultima versione di phpMyAdmin e rendiamo il sito disponibile sotto http://localhost:[PORTA]/pma.
Procediamo con l’installazione
# mi spoto nella cartella /var/www/html
cd /var/www/html
# Scaricare l'ultima versione (controlla la versione corrente su phpmyadmin.net)
sudo wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz
# Estrarre
sudo tar -xzf phpMyAdmin-latest-all-languages.tar.gz
sudo mv phpMyAdmin-*-all-languages pma
# pulizia
sudo rm phpMyAdmin-latest-all-languages.tar.gz
# Creare la cartella temporanea
sudo mkdir -p /var/www/html/pma/tmp
# Permessi
sudo chown -R apache:apache /var/www/html/pma
sudo find /var/www/html/pma -type d -exec chmod 775 {} \;
sudo find /var/www/html/pma -type f -exec chmod 664 {} \;
Modifichiamo il file di configurazione di phpmyadmin
# Generare una stringa casuale per blowfish_secret (es. con openssl):
openssl rand -hex 16
# Copiare il file di config di esempio
sudo cp /var/www/html/pma/config.sample.inc.php /var/www/html/pma/config.inc.php
sudo nano /var/www/html/pma/config.inc.php
# Impostare nel file:
$cfg['blowfish_secret'] = 'stringa-generata-da-openssl-qui';
$cfg['TempDir'] = '/var/www/html/pma/tmp';
# per eseguire il login automatico (AMBIENTE LOCALE) aggiungere o modificare i seguenti parametri
$cfg['Servers'][$i]['host'] = 'localhost';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = 'password di root';
$cfg['Servers'][$i]['auth_type'] = 'config';
$cfg['Servers'][$i]['AllowNoPassword'] = true;
WordPress
Per una configurazione veloce di wordpress seguire questi passaggi. Supponiamo di voler creare il sito web www.miosito.wp avente come cartella root /var/www/www.miosito.wp. Inoltre suppongo sia già stato configurato correttamento il puntamento DNS. Per prima cosa scarichiamo wordpress e creiamo la cartella del sito.
Cominciamo a creare il database miositowp e il relativo utente utentesito identificato da password password
mariadb -u root -p
CREATE DATABASE miositowp DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CREATE USER 'utentesito'@'%' IDENTIFIED BY 'password';
GRANT ALL ON miositowp.* TO 'utentesito'@'%';
FLUSH PRIVILEGES;
EXIT;
Scarichiamo wordpress e creiamo la cartella per il nuovo sito
cd /var/www
sudo wget https://wordpress.org/latest.tar.gz
sudo tar xzf latest.tar.gz
sudo mv wordpress www.miosito.wp
sudo rm latest.tar.gz
Da dentro la cartella del sito appena creato apri in modifica il file config di wordpress
cd /var/www/www.miosito.wp
sudo cp wp-config-sample.php wp-config.php
sudo nano wp-config.php
modifica le seguenti costanti
define( 'DB_NAME', 'nomedb' );
define( 'DB_USER', 'utentedb' );
define( 'DB_PASSWORD', 'passwordutente' );
Visitando questo sito aggiungi queste informazioni casuali sostituendo le costanti presenti
define( 'AUTH_KEY', '' );
define( 'SECURE_AUTH_KEY', '' );
define( 'LOGGED_IN_KEY', '' );
define( 'NONCE_KEY', '' );
define( 'AUTH_SALT', '' );
define( 'SECURE_AUTH_SALT', '' );
define( 'LOGGED_IN_SALT', '' );
define( 'NONCE_SALT', '' );
Infine per comodità, dopo la costante WP_DEBUG aggiungi le seguenti costanti
define( 'WP_POST_REVISIONS', 5 );
define( 'WP_AUTO_UPDATE_CORE', false );
define( 'ALLOW_UNFILTERED_UPLOADS', true );
Crea ora il file conf per il sito (imposta il numero della porta corretta)
sudo tee /etc/httpd/conf.d/www.miosito.wp.conf > /dev/null <<EOF
<VirtualHost *:......>
ServerName www.miosito.wp
DocumentRoot /var/www/www.miosito.wp
<Directory /var/www/www.miosito.wp>
DirectoryIndex index.php index.html
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog /var/log/httpd/miosito.local_error.log
CustomLog /var/log/httpd/miosito.local_access.log combined
</VirtualHost>
EOF
Aggiorna i permessi per la cartella root del sito
sudo chown -R apache:apache /var/www/www.miosito.wp
sudo find /var/www/www.miosito.wp -type d -exec chmod 775 {} \;
sudo find /var/www/www.miosito.wp -type f -exec chmod 664 {} \;
Controlla che non ci siano errori e riavvia apache
sudo apachectl configtest
sudo systemctl restart httpd
sudo systemctl status httpd
Supponiamo di creare ora uno script che gestisce la creazione di istanze wordpress sotto la cartella /var/www/html. In questo specifico caso non ho bisogno di creare un file virtualhost. La porta utilizzata è quella locale di apache overo la 34580. All’inizio dello script ci sono una serie di variabili da modificare secondo il tuo specifico caso
sudo nano /usr/local/bin/wp-manager.sh
#!/bin/bash
# wp-manager.sh - Gestione istanze WordPress
#
# Uso guidato (senza parametri):
# wp-manager.sh
#
# Uso diretto:
# wp-manager.sh create <nome>
# wp-manager.sh delete <nome>
# wp-manager.sh backup <nome>
# wp-manager.sh restore <nome>
# wp-manager.sh list
# ===========================================================================
# CONFIGURAZIONE
# ===========================================================================
# Distribuzione Linux: "rhel" oppure "debian"
DISTRO="rhel"
# Porta Apache (80 per standard, altra porta per sviluppo locale)
APACHE_PORT="34580"
# Root per siti localhost
LOCALHOST_ROOT="/var/www/html"
# Root per virtual host con dominio (senza slash finale)
VHOST_ROOT="/var/www"
# Dominio base per i virtual host.
# Se VHOST_DOMAIN="casa.miodominio.com" e il nome istanza è "sito1",
# il dominio completo sarà: sito1.casa.miodominio.com
VHOST_DOMAIN="casa.miodominio.com"
# Cartella dove vengono salvati tutti i backup (owner: utente corrente)
BACKUP_DIR="$HOME/wpbackup_bzip2"
# Credenziali MariaDB
DB_ROOT_PASSWORD="root"
# Versioni WordPress disponibili (oltre a "latest" che è sempre la default).
# Formato: solo il numero di versione, es. "6.9.4"
WP_VERSIONS=("6.9.4" "6.8.2" "6.7.2" "6.6.2" "6.5.5")
# ===========================================================================
# VARIABILI DERIVATE (non modificare)
# ===========================================================================
case "$DISTRO" in
rhel)
APACHE_USER="apache"
APACHE_SERVICE="httpd"
VHOST_CONF_DIR="/etc/httpd/conf.d"
;;
debian)
APACHE_USER="www-data"
APACHE_SERVICE="apache2"
VHOST_CONF_DIR="/etc/apache2/sites-available"
;;
*)
echo "Errore: DISTRO deve essere 'rhel' oppure 'debian'."
exit 1
;;
esac
# Crea le cartelle necessarie se non esistono (owner: utente corrente, non root)
WP_DOWNLOAD_DIR="${BACKUP_DIR}/wp_official_release_zip"
for _DIR in "$BACKUP_DIR" "$WP_DOWNLOAD_DIR"; do
if [ ! -d "$_DIR" ]; then
mkdir -p "$_DIR"
echo "Cartella creata: $_DIR"
fi
done
unset _DIR
# ===========================================================================
# FUNZIONI DI UTILITÀ
# ===========================================================================
# ---------------------------------------------------------------------------
# Validazione nome sito
# Regole: solo lettere, cifre e underscore; non inizia con cifra; non vuoto
# ---------------------------------------------------------------------------
validate_site_name() {
local NAME="$1"
if [ -z "$NAME" ]; then
echo "Errore: il nome del sito non può essere vuoto."
return 1
fi
if [[ "$NAME" =~ ^[0-9] ]]; then
echo "Errore: il nome del sito non può iniziare con un numero."
return 1
fi
if [[ ! "$NAME" =~ ^[a-zA-Z0-9_]+$ ]]; then
echo "Errore: il nome del sito può contenere solo lettere, cifre e underscore."
return 1
fi
return 0
}
# ---------------------------------------------------------------------------
# Menu interattivo per scegliere un sito esistente tra quelli installati.
# Imposta la variabile globale SITE_NAME con il nome (solo nome, senza dominio).
# Parametro opzionale $1: etichetta da mostrare nel prompt (es. "eliminare").
# Ritorna 1 se non ci sono siti installati.
# ---------------------------------------------------------------------------
pick_existing_site() {
local ACTION_LABEL="${1:-selezionare}"
# Raccogli tutti i siti installati in due array paralleli:
# SITE_PICK_NAMES → nome breve (quello da passare alle funzioni)
# SITE_PICK_LABELS → riga descrittiva da mostrare all'utente
local -a SITE_PICK_NAMES=()
local -a SITE_PICK_LABELS=()
# Siti localhost
for DIR in "${LOCALHOST_ROOT}"/*/; do
if [ -f "${DIR}wp-config.php" ]; then
local N
N=$(basename "$DIR")
local U
if [ "$APACHE_PORT" = "80" ]; then
U="http://localhost/${N}"
else
U="http://localhost:${APACHE_PORT}/${N}"
fi
SITE_PICK_NAMES+=("$N")
SITE_PICK_LABELS+=("${N} [localhost] ${U}")
fi
done
# Siti vhost
for DIR in "${VHOST_ROOT}"/*/; do
[ "$(basename "$DIR")" = "html" ] && continue
if [ -f "${DIR}wp-config.php" ]; then
local N
N=$(basename "$DIR") # es. sito1.casa.miodominio.com
# Il "nome" da passare alle funzioni è solo la prima parte
local SHORT_NAME
SHORT_NAME=$(echo "$N" | cut -d. -f1)
local U
if [ "$APACHE_PORT" = "80" ]; then
U="http://${N}"
else
U="http://${N}:${APACHE_PORT}"
fi
SITE_PICK_NAMES+=("$SHORT_NAME")
SITE_PICK_LABELS+=("${SHORT_NAME} [vhost: ${N}] ${U}")
fi
done
if [ ${#SITE_PICK_NAMES[@]} -eq 0 ]; then
echo "Nessuna istanza WordPress installata."
return 1
fi
echo ""
echo "Istanze disponibili:"
for i in "${!SITE_PICK_LABELS[@]}"; do
echo " $((i+1))) ${SITE_PICK_LABELS[$i]}"
done
echo ""
local SCELTA
read -p "Quale istanza vuoi ${ACTION_LABEL}? [1-${#SITE_PICK_NAMES[@]}]: " SCELTA
if ! [[ "$SCELTA" =~ ^[0-9]+$ ]] || \
[ "$SCELTA" -lt 1 ] || \
[ "$SCELTA" -gt "${#SITE_PICK_NAMES[@]}" ]; then
echo "Scelta non valida. Operazione annullata."
exit 1
fi
SITE_NAME="${SITE_PICK_NAMES[$((SCELTA-1))]}"
echo " -> Istanza selezionata: $SITE_NAME"
}
# ---------------------------------------------------------------------------
# Menu interattivo per scegliere un backup esistente in BACKUP_DIR.
# Scansiona i file <nome>-vhost-*.tar.bz2 e <nome>-local-*.tar.bz2.
# Imposta le variabili globali: SITE_NAME, BACKUP_FILE.
# Ritorna 1 se non ci sono backup disponibili.
# ---------------------------------------------------------------------------
pick_backup() {
local -a BACKUP_FILES=()
local -a BACKUP_LABELS=()
mapfile -t BACKUP_FILES < <(ls -1 "${BACKUP_DIR}"/*.tar.bz2 2>/dev/null | sort)
if [ ${#BACKUP_FILES[@]} -eq 0 ]; then
echo "Nessun backup trovato in ${BACKUP_DIR}."
return 1
fi
echo ""
echo "Backup disponibili in ${BACKUP_DIR}:"
for i in "${!BACKUP_FILES[@]}"; do
local FNAME
FNAME=$(basename "${BACKUP_FILES[$i]}")
# Formato: <nome>-vhost-YYYYMMDD-HHMMSS.tar.bz2
# o: <nome>-local-YYYYMMDD-HHMMSS.tar.bz2
local BNAME BTYPE BDATE BTIME
BNAME=$(echo "$FNAME" | cut -d- -f1)
BTYPE=$(echo "$FNAME" | cut -d- -f2)
BDATE=$(echo "$FNAME" | cut -d- -f3)
BTIME=$(echo "$FNAME" | cut -d- -f4 | cut -d. -f1)
local LABEL_TYPE
if [ "$BTYPE" = "vhost" ]; then
LABEL_TYPE="vhost: ${BNAME}.${VHOST_DOMAIN}"
else
LABEL_TYPE="localhost"
fi
BACKUP_LABELS+=("${BNAME} [${LABEL_TYPE}] ${BDATE:0:4}-${BDATE:4:2}-${BDATE:6:2} ${BTIME:0:2}:${BTIME:2:2}:${BTIME:4:2}")
echo " $((i+1))) ${BACKUP_LABELS[$i]}"
done
echo ""
local SCELTA
read -p "Quale backup vuoi ripristinare? [1-${#BACKUP_FILES[@]}]: " SCELTA
if ! [[ "$SCELTA" =~ ^[0-9]+$ ]] || \
[ "$SCELTA" -lt 1 ] || \
[ "$SCELTA" -gt "${#BACKUP_FILES[@]}" ]; then
echo "Scelta non valida. Operazione annullata."
exit 1
fi
BACKUP_FILE="${BACKUP_FILES[$((SCELTA-1))]}"
local FNAME
FNAME=$(basename "$BACKUP_FILE")
SITE_NAME=$(echo "$FNAME" | cut -d- -f1)
echo " -> Backup selezionato: $FNAME (sito: $SITE_NAME)"
}
# ---------------------------------------------------------------------------
# Ricava il percorso e l'URL del sito in base alla modalità
# Imposta le variabili globali: SITE_DIR, SITE_URL, FULL_DOMAIN, IS_VHOST
# ---------------------------------------------------------------------------
resolve_site_paths() {
local SITE="$1"
local MODE="$2" # "localhost" oppure "vhost"
if [ "$MODE" = "vhost" ]; then
IS_VHOST=1
FULL_DOMAIN="${SITE}.${VHOST_DOMAIN}"
SITE_DIR="${VHOST_ROOT}/${FULL_DOMAIN}"
if [ "$APACHE_PORT" = "80" ]; then
SITE_URL="http://${FULL_DOMAIN}"
else
SITE_URL="http://${FULL_DOMAIN}:${APACHE_PORT}"
fi
else
IS_VHOST=0
FULL_DOMAIN="localhost"
SITE_DIR="${LOCALHOST_ROOT}/${SITE}"
if [ "$APACHE_PORT" = "80" ]; then
SITE_URL="http://localhost/${SITE}"
else
SITE_URL="http://localhost:${APACHE_PORT}/${SITE}"
fi
fi
}
# ---------------------------------------------------------------------------
# Scelta interattiva della versione WordPress
# Imposta la variabile globale: WP_VERSION (stringa) e WP_URL (URL archivio)
# ---------------------------------------------------------------------------
choose_wp_version() {
echo ""
echo "Versioni WordPress disponibili:"
echo " 0) latest (default)"
for i in "${!WP_VERSIONS[@]}"; do
echo " $((i+1))) ${WP_VERSIONS[$i]}"
done
echo ""
read -p "Quale versione vuoi installare? [0-${#WP_VERSIONS[@]}, default=0]: " VER_SCELTA
if [ -z "$VER_SCELTA" ] || [ "$VER_SCELTA" = "0" ]; then
WP_VERSION="latest"
WP_URL="https://wordpress.org/latest.tar.gz"
WP_ARCHIVE="latest.tar.gz"
else
if ! [[ "$VER_SCELTA" =~ ^[0-9]+$ ]] || \
[ "$VER_SCELTA" -lt 1 ] || \
[ "$VER_SCELTA" -gt "${#WP_VERSIONS[@]}" ]; then
echo "Scelta non valida. Verrà usata la versione latest."
WP_VERSION="latest"
WP_URL="https://wordpress.org/latest.tar.gz"
WP_ARCHIVE="latest.tar.gz"
else
WP_VERSION="${WP_VERSIONS[$((VER_SCELTA-1))]}"
WP_URL="https://wordpress.org/wordpress-${WP_VERSION}.zip"
WP_ARCHIVE="wordpress-${WP_VERSION}.zip"
fi
fi
echo " -> Versione selezionata: $WP_VERSION"
}
# ---------------------------------------------------------------------------
# Applica i permessi corretti alla cartella del sito
# ---------------------------------------------------------------------------
set_permissions() {
local DIR="$1"
local MODE="$2" # "localhost" oppure "vhost"
if [ "$MODE" = "vhost" ]; then
sudo chown -R "${APACHE_USER}:${APACHE_USER}" "$DIR"
sudo find "$DIR" -type d -exec chmod 775 {} \;
sudo find "$DIR" -type f -exec chmod 664 {} \;
else
sudo chown -R "${APACHE_USER}:${APACHE_USER}" "$DIR"
sudo chmod -R 775 "$DIR"
sudo find "$DIR" -type d -exec chmod g+s {} \;
fi
}
# ---------------------------------------------------------------------------
# Crea il file VirtualHost e (re)avvia Apache
# ---------------------------------------------------------------------------
create_vhost_conf() {
local DOMAIN="$1"
local DIR="$2"
local LOG_BASE
LOG_BASE=$(echo "$DOMAIN" | cut -d. -f1)
local CONF_FILE="${VHOST_CONF_DIR}/${DOMAIN}.conf"
echo ">>> Creazione VirtualHost ${CONF_FILE}..."
sudo tee "$CONF_FILE" > /dev/null <<EOF
<VirtualHost *:${APACHE_PORT}>
ServerName ${DOMAIN}
DocumentRoot ${DIR}
<Directory ${DIR}>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog /var/log/${APACHE_SERVICE}/${LOG_BASE}-error.log
CustomLog /var/log/${APACHE_SERVICE}/${LOG_BASE}-access.log combined
</VirtualHost>
EOF
# Su Debian/Ubuntu occorre abilitare il sito
if [ "$DISTRO" = "debian" ]; then
sudo a2ensite "${DOMAIN}.conf"
fi
echo ">>> Riavvio ${APACHE_SERVICE}..."
sudo systemctl restart "$APACHE_SERVICE"
}
# ---------------------------------------------------------------------------
# Rimuove il file VirtualHost e (re)avvia Apache
# ---------------------------------------------------------------------------
remove_vhost_conf() {
local DOMAIN="$1"
local CONF_FILE="${VHOST_CONF_DIR}/${DOMAIN}.conf"
if [ -f "$CONF_FILE" ]; then
echo ">>> Rimozione VirtualHost ${CONF_FILE}..."
if [ "$DISTRO" = "debian" ]; then
sudo a2dissite "${DOMAIN}.conf"
fi
sudo rm -f "$CONF_FILE"
echo ">>> Riavvio ${APACHE_SERVICE}..."
sudo systemctl restart "$APACHE_SERVICE"
fi
}
# ---------------------------------------------------------------------------
# Scarica WordPress in WP_DOWNLOAD_DIR ed estrae in una tmp dir.
# Restituisce il percorso della cartella estratta in WP_EXTRACTED_DIR.
# ---------------------------------------------------------------------------
download_and_extract_wp() {
local ARCHIVE_PATH="${WP_DOWNLOAD_DIR}/${WP_ARCHIVE}"
# Download nella cartella centralizzata (owner: utente corrente)
if [ -f "$ARCHIVE_PATH" ]; then
read -p "Il file $WP_ARCHIVE esiste già. Vuoi riscaricarlo? [s/N] " risposta
if [ "$risposta" = "s" ] || [ "$risposta" = "S" ]; then
rm -f "$ARCHIVE_PATH"
wget -q "$WP_URL" -O "$ARCHIVE_PATH"
fi
else
wget -q "$WP_URL" -O "$ARCHIVE_PATH"
fi
# Estrazione in una directory temporanea
local TMP_EXTRACT
TMP_EXTRACT=$(mktemp -d)
if [ "$WP_VERSION" = "latest" ]; then
sudo tar -xzf "$ARCHIVE_PATH" -C "$TMP_EXTRACT"
else
sudo unzip -q "$ARCHIVE_PATH" -d "$TMP_EXTRACT"
fi
WP_EXTRACTED_DIR="${TMP_EXTRACT}/wordpress"
# Salva il riferimento alla tmp per poterla pulire dopo il mv
WP_EXTRACT_TMP="$TMP_EXTRACT"
}
# ---------------------------------------------------------------------------
# Configura wp-config.php (chiavi salt, db, costanti extra)
# ---------------------------------------------------------------------------
configure_wp_config() {
local DIR="$1"
local DB="$2"
sudo cp "$DIR/wp-config-sample.php" "$DIR/wp-config.php"
sudo sed -i "s/database_name_here/$DB/" "$DIR/wp-config.php"
sudo sed -i "s/username_here/root/" "$DIR/wp-config.php"
sudo sed -i "s/password_here/$DB_ROOT_PASSWORD/" "$DIR/wp-config.php"
# Sostituzione chiavi salt
NEW_KEYS=$(curl -s https://api.wordpress.org/secret-key/1.1/salt)
FIRST_LINE=$(grep -n "define( 'AUTH_KEY'" "$DIR/wp-config.php" | head -1 | cut -d: -f1)
LAST_LINE=$(grep -n "define( 'NONCE_SALT'" "$DIR/wp-config.php" | head -1 | cut -d: -f1)
sudo sed -i "${FIRST_LINE},${LAST_LINE}d" "$DIR/wp-config.php"
sudo sed -i "$((FIRST_LINE - 1))r /dev/stdin" "$DIR/wp-config.php" <<< "$NEW_KEYS"
# Costanti extra dopo WP_DEBUG
EXTRA_DEFINES="define( 'WP_POST_REVISIONS', 5 );\ndefine( 'WP_AUTO_UPDATE_CORE', false );\ndefine( 'ALLOW_UNFILTERED_UPLOADS', true );"
sudo sed -i "/define( 'WP_DEBUG', false );/a ${EXTRA_DEFINES}" "$DIR/wp-config.php"
}
# ===========================================================================
# MODALITÀ GUIDATA (nessun argomento)
# ===========================================================================
interactive_mode() {
echo "======================================"
echo " wp-manager.sh - Modalità guidata"
echo "======================================"
echo ""
echo "Cosa vuoi fare?"
echo " 1) create - Installa una nuova istanza WordPress"
echo " 2) delete - Elimina un'istanza esistente"
echo " 3) backup - Crea un backup di un'istanza"
echo " 4) restore - Ripristina un'istanza da backup"
echo " 5) list - Elenca le istanze installate"
echo ""
read -p "Scelta [1-5]: " SCELTA_OP
case "$SCELTA_OP" in
1) OP="create" ;;
2) OP="delete" ;;
3) OP="backup" ;;
4) OP="restore" ;;
5) OP="list" ;;
*)
echo "Scelta non valida. Uscita."
exit 1
;;
esac
if [ "$OP" = "create" ]; then
echo ""
read -p "Nome della nuova istanza WordPress: " SITE_NAME
if ! validate_site_name "$SITE_NAME"; then
exit 1
fi
elif [ "$OP" = "restore" ]; then
if ! pick_backup; then
exit 1
fi
# SITE_NAME e BACKUP_FILE sono già impostati da pick_backup
elif [ "$OP" != "list" ]; then
if ! pick_existing_site "$OP"; then
exit 1
fi
fi
# Per create, chiedi anche modalità (localhost / vhost)
if [ "$OP" = "create" ]; then
echo ""
echo "Tipo di installazione:"
echo " 1) localhost (http://localhost:${APACHE_PORT}/${SITE_NAME})"
echo " 2) vhost (http://${SITE_NAME}.${VHOST_DOMAIN})"
read -p "Scelta [1-2, default=1]: " SCELTA_TIPO
case "$SCELTA_TIPO" in
2) INSTALL_MODE="vhost" ;;
*) INSTALL_MODE="localhost" ;;
esac
choose_wp_version
fi
# Esegui l'operazione raccolta
case "$OP" in
create) create_wp "$SITE_NAME" "$INSTALL_MODE" ;;
delete) delete_wp "$SITE_NAME" ;;
backup) backup_wp "$SITE_NAME" ;;
restore) restore_wp "$SITE_NAME" ;;
list) list_wp ;;
esac
}
# ===========================================================================
# create
# ===========================================================================
create_wp() {
local SITE="$1"
local MODE="${2:-localhost}" # default: localhost
if [ -z "$SITE" ]; then
echo "Uso: wp-manager.sh create <nome> [localhost|vhost]"
exit 1
fi
if ! validate_site_name "$SITE"; then
exit 1
fi
resolve_site_paths "$SITE" "$MODE"
# Se WP_VERSION non è ancora impostata (invocazione diretta), chiedi
if [ -z "$WP_VERSION" ]; then
choose_wp_version
fi
DB_NAME="wp_${SITE}"
if [ -d "$SITE_DIR" ]; then
echo "Errore: la cartella $SITE_DIR esiste già."
exit 1
fi
echo ""
echo "=== Riepilogo creazione ==="
echo " Nome : $SITE"
echo " Modalità : $MODE"
echo " Cartella : $SITE_DIR"
echo " Database : $DB_NAME"
echo " URL : $SITE_URL"
echo " WP versione: $WP_VERSION"
if [ "$IS_VHOST" = "1" ]; then
echo " VirtualHost: ${VHOST_CONF_DIR}/${FULL_DOMAIN}.conf"
fi
echo ""
# --- Database ---
echo ">>> Creazione database '$DB_NAME'..."
sudo mariadb -u root -p"$DB_ROOT_PASSWORD" -e "
DROP DATABASE IF EXISTS \`$DB_NAME\`;
CREATE DATABASE IF NOT EXISTS \`$DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
"
# --- Download e installazione ---
echo ">>> Download WordPress $WP_VERSION..."
download_and_extract_wp
sudo mv "$WP_EXTRACTED_DIR" "$SITE_DIR"
rm -rf "$WP_EXTRACT_TMP"
# --- Configurazione ---
echo ">>> Configurazione wp-config.php..."
configure_wp_config "$SITE_DIR" "$DB_NAME"
# --- Permessi ---
echo ">>> Permessi..."
set_permissions "$SITE_DIR" "$MODE"
# --- VirtualHost (solo vhost) ---
if [ "$IS_VHOST" = "1" ]; then
create_vhost_conf "$FULL_DOMAIN" "$SITE_DIR"
fi
echo ""
echo "=== WordPress installato! ==="
echo " Cartella : $SITE_DIR"
echo " Database : $DB_NAME"
echo " URL : $SITE_URL"
}
# ===========================================================================
# delete
# ===========================================================================
delete_wp() {
local SITE="$1"
if [ -z "$SITE" ]; then
echo "Uso: wp-manager.sh delete <nome>"
exit 1
fi
DB_NAME="wp_${SITE}"
# Cerca il sito: prima come vhost, poi come localhost
SITE_DIR_VHOST="${VHOST_ROOT}/${SITE}.${VHOST_DOMAIN}"
SITE_DIR_LOCAL="${LOCALHOST_ROOT}/${SITE}"
if [ -d "$SITE_DIR_VHOST" ]; then
SITE_DIR="$SITE_DIR_VHOST"
IS_VHOST=1
FULL_DOMAIN="${SITE}.${VHOST_DOMAIN}"
elif [ -d "$SITE_DIR_LOCAL" ]; then
SITE_DIR="$SITE_DIR_LOCAL"
IS_VHOST=0
else
echo "Errore: nessuna cartella trovata per '$SITE' (cercato in $SITE_DIR_VHOST e $SITE_DIR_LOCAL)."
exit 1
fi
echo "Sito trovato: $SITE_DIR"
read -p "Sei sicuro di voler eliminare '$SITE' (cartella + database '$DB_NAME')? (s/N): " CONFIRM
if [[ "$CONFIRM" != "s" && "$CONFIRM" != "S" ]]; then
echo "Operazione annullata."
exit 0
fi
echo ">>> Rimozione cartella..."
sudo rm -rf "$SITE_DIR"
echo ">>> Rimozione database '$DB_NAME'..."
sudo mariadb -u root -p"$DB_ROOT_PASSWORD" -e "
DROP DATABASE IF EXISTS \`$DB_NAME\`;
"
# Rimuovi VirtualHost se presente
if [ "${IS_VHOST:-0}" = "1" ]; then
remove_vhost_conf "$FULL_DOMAIN"
fi
echo "=== Istanza '$SITE' eliminata. ==="
}
# ===========================================================================
# backup
# Crea: $BACKUP_DIR/<nome>-vhost-YYYYMMDD-HHMMSS.tar.bz2
# o: $BACKUP_DIR/<nome>-local-YYYYMMDD-HHMMSS.tar.bz2
# L'archivio contiene la cartella del sito e il dump SQL (<nome>.sql)
# Owner del file: utente corrente (non root)
# ===========================================================================
backup_wp() {
local SITE="$1"
if [ -z "$SITE" ]; then
echo "Uso: wp-manager.sh backup <nome>"
exit 1
fi
DB_NAME="wp_${SITE}"
# Individua la cartella sorgente
SITE_DIR_VHOST="${VHOST_ROOT}/${SITE}.${VHOST_DOMAIN}"
SITE_DIR_LOCAL="${LOCALHOST_ROOT}/${SITE}"
local BACKUP_TYPE BACKUP_SITE_NAME
if [ -d "$SITE_DIR_VHOST" ]; then
SITE_DIR="$SITE_DIR_VHOST"
IS_VHOST=1
BACKUP_TYPE="vhost"
BACKUP_SITE_NAME="${SITE}.${VHOST_DOMAIN}"
elif [ -d "$SITE_DIR_LOCAL" ]; then
SITE_DIR="$SITE_DIR_LOCAL"
IS_VHOST=0
BACKUP_TYPE="local"
BACKUP_SITE_NAME="$SITE"
else
echo "Errore: nessuna cartella trovata per '$SITE'."
exit 1
fi
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
BACKUP_FILE="${BACKUP_DIR}/${SITE}-${BACKUP_TYPE}-${TIMESTAMP}.tar.bz2"
TMP_DIR=$(mktemp -d)
echo ">>> Dump del database '$DB_NAME'..."
sudo mariadb-dump -u root -p"$DB_ROOT_PASSWORD" \
--single-transaction --routines --triggers \
"$DB_NAME" > "$TMP_DIR/${SITE}.sql"
if [ $? -ne 0 ]; then
echo "Errore durante il dump del database."
rm -rf "$TMP_DIR"
exit 1
fi
echo ">>> Creazione archivio $BACKUP_FILE ..."
sudo tar -cjf "$BACKUP_FILE" \
-C "$(dirname "$SITE_DIR")" "$BACKUP_SITE_NAME" \
-C "$TMP_DIR" "${SITE}.sql"
if [ $? -ne 0 ]; then
echo "Errore durante la creazione dell'archivio."
rm -rf "$TMP_DIR"
exit 1
fi
# Restituisce l'ownership del file all'utente corrente (non root)
sudo chown "${USER}:${USER}" "$BACKUP_FILE"
rm -rf "$TMP_DIR"
echo ""
echo "=== Backup completato! ==="
echo " File : $BACKUP_FILE"
echo " Sito : $SITE_DIR"
echo " Database: $DB_NAME"
}
# ===========================================================================
# restore
# Legge i backup da $BACKUP_DIR.
# Il tipo (localhost/vhost) viene ricavato dal nome file:
# <nome>-vhost-YYYYMMDD-HHMMSS.tar.bz2
# <nome>-local-YYYYMMDD-HHMMSS.tar.bz2
# Se BACKUP_FILE è già impostato (da pick_backup) lo usa direttamente,
# altrimenti cerca tutti i backup per il sito $SITE e mostra un menu.
# ===========================================================================
restore_wp() {
local SITE="$1"
if [ -z "$SITE" ]; then
echo "Uso: wp-manager.sh restore <nome>"
exit 1
fi
DB_NAME="wp_${SITE}"
# Se BACKUP_FILE non è già stato scelto da pick_backup, mostra il menu
# filtrato per questo sito specifico
if [ -z "$BACKUP_FILE" ]; then
mapfile -t BACKUPS < <(ls -1 "${BACKUP_DIR}/${SITE}-"*.tar.bz2 2>/dev/null | sort)
if [ ${#BACKUPS[@]} -eq 0 ]; then
echo "Errore: nessun file di backup trovato per il sito '$SITE' in ${BACKUP_DIR}."
echo " (formato atteso: ${SITE}-vhost-YYYYMMDD-HHMMSS.tar.bz2)"
exit 1
fi
if [ ${#BACKUPS[@]} -eq 1 ]; then
BACKUP_FILE="${BACKUPS[0]}"
echo "Backup trovato: $(basename "$BACKUP_FILE")"
else
echo "Backup disponibili per '$SITE':"
for i in "${!BACKUPS[@]}"; do
local FNAME BTYPE BDATE BTIME
FNAME=$(basename "${BACKUPS[$i]}")
BTYPE=$(echo "$FNAME" | cut -d- -f2)
BDATE=$(echo "$FNAME" | cut -d- -f3)
BTIME=$(echo "$FNAME" | cut -d- -f4 | cut -d. -f1)
local LABEL_TYPE
[ "$BTYPE" = "vhost" ] && LABEL_TYPE="vhost" || LABEL_TYPE="localhost"
echo " $((i+1))) ${FNAME} [${LABEL_TYPE}] ${BDATE:0:4}-${BDATE:4:2}-${BDATE:6:2} ${BTIME:0:2}:${BTIME:2:2}:${BTIME:4:2}"
done
local SCELTA
read -p "Quale vuoi ripristinare? [1-${#BACKUPS[@]}]: " SCELTA
if ! [[ "$SCELTA" =~ ^[0-9]+$ ]] || [ "$SCELTA" -lt 1 ] || [ "$SCELTA" -gt ${#BACKUPS[@]} ]; then
echo "Scelta non valida. Operazione annullata."
exit 1
fi
BACKUP_FILE="${BACKUPS[$((SCELTA-1))]}"
fi
fi
# Ricava il tipo dal nome del file di backup
local FNAME BTYPE
FNAME=$(basename "$BACKUP_FILE")
BTYPE=$(echo "$FNAME" | cut -d- -f2)
if [ "$BTYPE" = "vhost" ]; then
IS_VHOST=1
FULL_DOMAIN_EXTRACTED="${SITE}.${VHOST_DOMAIN}"
SITE_DIR="${VHOST_ROOT}/${FULL_DOMAIN_EXTRACTED}"
INSTALL_MODE="vhost"
if [ "$APACHE_PORT" = "80" ]; then
SITE_URL="http://${FULL_DOMAIN_EXTRACTED}"
else
SITE_URL="http://${FULL_DOMAIN_EXTRACTED}:${APACHE_PORT}"
fi
else
IS_VHOST=0
SITE_DIR="${LOCALHOST_ROOT}/${SITE}"
INSTALL_MODE="localhost"
if [ "$APACHE_PORT" = "80" ]; then
SITE_URL="http://localhost/${SITE}"
else
SITE_URL="http://localhost:${APACHE_PORT}/${SITE}"
fi
fi
# Conferma sovrascrittura se il sito esiste già
if [ -d "$SITE_DIR" ]; then
read -p "La cartella $SITE_DIR esiste già e verrà sovrascritta. Continuare? (s/N): " CONFIRM
if [[ "$CONFIRM" != "s" && "$CONFIRM" != "S" ]]; then
echo "Operazione annullata."
exit 0
fi
echo ">>> Rimozione cartella esistente..."
sudo rm -rf "$SITE_DIR"
fi
TMP_DIR=$(mktemp -d)
echo ">>> Estrazione archivio $BACKUP_FILE ..."
sudo tar -xjf "$BACKUP_FILE" -C "$TMP_DIR"
if [ $? -ne 0 ]; then
echo "Errore durante l'estrazione dell'archivio."
rm -rf "$TMP_DIR"
exit 1
fi
# Individua la cartella estratta (può essere <site> o <site>.<domain>)
local EXTRACTED_SITE_DIR
if [ -d "$TMP_DIR/${SITE}.${VHOST_DOMAIN}" ]; then
EXTRACTED_SITE_DIR="$TMP_DIR/${SITE}.${VHOST_DOMAIN}"
elif [ -d "$TMP_DIR/$SITE" ]; then
EXTRACTED_SITE_DIR="$TMP_DIR/$SITE"
else
echo "Errore: nessuna cartella sito trovata nell'archivio."
rm -rf "$TMP_DIR"
exit 1
fi
# Controlla dump SQL
local SQL_FILE="$TMP_DIR/${SITE}.sql"
if [ ! -f "$SQL_FILE" ]; then
echo "Errore: il file SQL '${SITE}.sql' non è presente nell'archivio."
rm -rf "$TMP_DIR"
exit 1
fi
sudo mv "$EXTRACTED_SITE_DIR" "$SITE_DIR"
echo ">>> Ripristino database '$DB_NAME'..."
sudo mariadb -u root -p"$DB_ROOT_PASSWORD" -e "
DROP DATABASE IF EXISTS \`$DB_NAME\`;
CREATE DATABASE \`$DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
"
sudo mariadb -u root -p"$DB_ROOT_PASSWORD" "$DB_NAME" < "$SQL_FILE"
if [ $? -ne 0 ]; then
echo "Errore durante il ripristino del database."
rm -rf "$TMP_DIR"
exit 1
fi
rm -rf "$TMP_DIR"
# Aggiorna credenziali in wp-config.php
echo ">>> Aggiornamento credenziali in wp-config.php..."
sudo sed -i "s/define( 'DB_NAME',.*$/define( 'DB_NAME', '${DB_NAME}' );/" "$SITE_DIR/wp-config.php"
sudo sed -i "s/define( 'DB_USER',.*$/define( 'DB_USER', 'root' );/" "$SITE_DIR/wp-config.php"
sudo sed -i "s/define( 'DB_PASSWORD',.*$/define( 'DB_PASSWORD', '${DB_ROOT_PASSWORD}' );/" "$SITE_DIR/wp-config.php"
# Permessi
echo ">>> Permessi..."
set_permissions "$SITE_DIR" "$INSTALL_MODE"
# VirtualHost (se necessario)
if [ "$IS_VHOST" = "1" ]; then
create_vhost_conf "$FULL_DOMAIN_EXTRACTED" "$SITE_DIR"
fi
echo ""
echo "=== Restore completato! ==="
echo " Sorgente : $BACKUP_FILE"
echo " Cartella : $SITE_DIR"
echo " Database : $DB_NAME"
echo " URL : $SITE_URL"
}
# ===========================================================================
# list
# Elenca sia i siti in LOCALHOST_ROOT che quelli in VHOST_ROOT
# ===========================================================================
list_wp() {
echo "=== Istanze WordPress ==="
echo ""
FOUND=0
# Siti localhost
for DIR in "${LOCALHOST_ROOT}"/*/; do
if [ -f "${DIR}wp-config.php" ]; then
FOUND=1
NAME=$(basename "$DIR")
DB=$(grep "DB_NAME" "${DIR}wp-config.php" | grep -o "'[^']*'" | sed -n '2p' | tr -d "'")
if [ "$APACHE_PORT" = "80" ]; then
URL="http://localhost/${NAME}"
else
URL="http://localhost:${APACHE_PORT}/${NAME}"
fi
echo " [${NAME}] (localhost)"
echo " Cartella : $DIR"
echo " Database : $DB"
echo " URL : $URL"
echo ""
fi
done
# Siti vhost (cartelle direttamente sotto VHOST_ROOT, esclusa html/)
for DIR in "${VHOST_ROOT}"/*/; do
[ "$(basename "$DIR")" = "html" ] && continue
if [ -f "${DIR}wp-config.php" ]; then
FOUND=1
NAME=$(basename "$DIR")
DB=$(grep "DB_NAME" "${DIR}wp-config.php" | grep -o "'[^']*'" | sed -n '2p' | tr -d "'")
if [ "$APACHE_PORT" = "80" ]; then
URL="http://${NAME}"
else
URL="http://${NAME}:${APACHE_PORT}"
fi
echo " [${NAME}] (vhost)"
echo " Cartella : $DIR"
echo " Database : $DB"
echo " URL : $URL"
if [ -f "${VHOST_CONF_DIR}/${NAME}.conf" ]; then
echo " VirtualHost: ${VHOST_CONF_DIR}/${NAME}.conf"
fi
echo ""
fi
done
if [ $FOUND -eq 0 ]; then
echo " Nessuna istanza trovata."
fi
}
# ===========================================================================
# Entry point
# ===========================================================================
case "$1" in
"")
# Nessun argomento → modalità guidata
interactive_mode
;;
create)
if [ -z "$2" ]; then
# Nome non specificato → chiedi interattivamente
read -p "Nome dell'istanza WordPress: " SITE_NAME
if ! validate_site_name "$SITE_NAME"; then exit 1; fi
echo ""
echo "Tipo di installazione:"
echo " 1) localhost (http://localhost:${APACHE_PORT}/${SITE_NAME})"
echo " 2) vhost (http://${SITE_NAME}.${VHOST_DOMAIN})"
read -p "Scelta [1-2, default=1]: " SCELTA_TIPO
case "$SCELTA_TIPO" in
2) INSTALL_MODE="vhost" ;;
*) INSTALL_MODE="localhost" ;;
esac
choose_wp_version
create_wp "$SITE_NAME" "$INSTALL_MODE"
else
MODE="${3:-localhost}"
choose_wp_version
create_wp "$2" "$MODE"
fi
;;
delete)
if [ -z "$2" ]; then
if ! pick_existing_site "eliminare"; then exit 1; fi
delete_wp "$SITE_NAME"
else
delete_wp "$2"
fi
;;
backup)
if [ -z "$2" ]; then
if ! pick_existing_site "fare il backup di"; then exit 1; fi
backup_wp "$SITE_NAME"
else
backup_wp "$2"
fi
;;
restore)
if [ -z "$2" ]; then
if ! pick_backup; then exit 1; fi
restore_wp "$SITE_NAME"
else
restore_wp "$2"
fi
;;
list)
list_wp
;;
*)
echo "Uso:"
echo " wp-manager.sh # modalità guidata interattiva"
echo " wp-manager.sh create <nome> [localhost|vhost]"
echo " wp-manager.sh delete <nome>"
echo " wp-manager.sh backup <nome> # salva in $BACKUP_DIR"
echo " wp-manager.sh restore [<nome>] # ripristina da $BACKUP_DIR"
echo " wp-manager.sh list"
;;
esac
Per rendere eseguibile lo script
sudo chmod +x /usr/local/bin/wp-manager.sh
Esempi d’uso dello script
# creo una nuova istanza con nome cartella "miosito" e nome database "wp_miosito"
wp-manager.sh create miosito
# elenco le istanze disponbili
wp-manager.sh list
# cancello l'istanza con nome cartella "miosito" e nome database "wp_miosito"
wp-manager.sh delete miosito
# mi crea una backup bzip2 dell'instanza specificata
wp-manager.sh backup miosito
# mi fa il restore di una istanza salvata in precedenza
wp-manager.sh restore miosito
Dopo create, apri il browser su http://localhost:34580/miosito per completare l’installazione di WordPress.
Certificati SSL/TLS per i siti Apache
Usiamo Certbot con Let’s Encrypt per i siti raggiungibili da internet. Let’s Encrypt fornisce certificati gratuiti e riconosciuti da tutti i browser.
# Installare Certbot
sudo dnf install certbot python3-certbot-apache -y
# Ottenere e installare il certificato (modifica automaticamente il virtual host)
sudo certbot --apache -d miosito.com -d www.miosito.com
# Certbot chiederà:
# - indirizzo email per notifiche di scadenza
# - accettazione termini di servizio
# - se redirigere HTTP → HTTPS automaticamente (consigliato: sì)
Il certificato viene rinnovato automaticamente. Puoi testare il rinnovo con:
sudo certbot renew --dry-run
Per Elencare i certificati Let’s Encrypt gestiti da Certbot
sudo certbot certificates
Per rimuovere un certificato Let’s Encrypt:
# Revocare e cancellare il certificato
sudo certbot delete --cert-name miosito.com
# In alternativa, solo revocare (mantiene i file)
sudo certbot revoke --cert-path /etc/letsencrypt/live/miosito.com/fullchain.pem
# Dopo la cancellazione, rimuovere il virtual host HTTPS se non più necessario
sudo rm /etc/httpd/conf.d/miosito-ssl.conf
sudo systemctl reload httpd
Basic Auth Apache
Crea il file delle password
# Crea la directory per i file di auth (fuori dal webroot)
sudo mkdir -p /etc/httpd/auth
# Crea il primo utente (-c crea il file, usalo solo la prima volta)
sudo htpasswd -c /etc/httpd/auth/pma.htpasswd nomeutente
# Per aggiungere altri utenti (senza -c, altrimenti sovrascrive)
sudo htpasswd /etc/httpd/auth/pma.htpasswd altrouser
Poi modifica il file conf ssl di apache, aggiungendo la direttiva <Location>
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName ....
DocumentRoot ....
<Directory ....>
....
</Directory>
# Basic Auth tramite Location (ha precedenza su .htaccess)
<Location "/">
AuthType Basic
AuthName "Area Riservata"
AuthUserFile /etc/httpd/auth/pma.htpasswd
Require valid-user
</Location>
ErrorLog ....
CustomLog ....
SSLCertificateFile ....
SSLCertificateKeyFile ....
Include ....
</VirtualHost>
</IfModule>
Il file conf relativo alla porta :80 non serve modificarlo perché fa già redirect a HTTPS.
Aggiusta i permessi sul file htpasswd
sudo chown root:apache /etc/httpd/auth/pma.htpasswd
sudo chmod 640 /etc/httpd/auth/pma.htpasswd
Verifica la configurazione e riavvia Apache
# Controlla che non ci siano errori di sintassi
sudo apachectl configtest
# Riavvia Apache
sudo systemctl restart httpd
