1 11/05/2026 10 min

Se devi portare su una macchina Linux un ambiente web classico e nello stesso tempo avere un editor remoto comodo e controllabile, LAMP e Code-Server stanno bene insieme: Apache espone il sito, PHP esegue la logica applicativa, MariaDB gestisce i dati e Code-Server ti evita di aprire SSH a caso solo per modificare file. La scelta sensata è tenere il web stack stabile e separare bene l’accesso di sviluppo, così riduci il rischio di mescolare codice, permessi e servizi esposti.

Qui parto da un’installazione pulita su una distribuzione Linux recente con systemd. Cambiano i nomi dei pacchetti tra Debian/Ubuntu e RHEL/Alma/Rocky, ma la logica resta identica: prima verifichi rete e repository, poi installi il minimo necessario, poi metti in sicurezza l’esposizione e solo dopo aggiungi comodità come Code-Server.

Scelta architetturale: LAMP locale, Code-Server separato

La combinazione più pulita è questa: Apache ascolta su 80/443, PHP gira come modulo o via PHP-FPM, MariaDB resta in locale o su rete privata, Code-Server ascolta solo su localhost o dietro reverse proxy con autenticazione forte. Se metti tutto sulla stessa porta o senza separazione di rete, poi ti ritrovi a inseguire problemi di permessi, collisioni di virtual host e accessi indesiderati.

Per un server di produzione la regola è semplice: il sito deve funzionare anche se Code-Server è spento. Per questo l’editor remoto va trattato come servizio accessorio, non come dipendenza del web stack.

1) Aggiorna il sistema e prepara i pacchetti

Prima di installare controlla che il sistema sia allineato e che i repository rispondano. Questo evita di confondere errori di mirror con problemi del servizio.

sudo apt update && sudo apt -y upgrade

Su Debian/Ubuntu il set base è Apache, MariaDB e PHP con i moduli più comuni. Su RHEL-like i nomi cambiano leggermente, ma il contenuto non cambia.

sudo apt install -y apache2 mariadb-server php libapache2-mod-php php-mysql php-cli php-curl php-xml php-mbstring unzip curl

Se usi un sistema basato su RHEL, l’equivalente concettuale è installare httpd, mariadb-server, php e i moduli PHP necessari. Non forzo qui i comandi specifici per la famiglia RPM perché i pacchetti dipendono dalla release e dai repository abilitati.

2) Avvia e verifica Apache e MariaDB

Appena installati, i servizi vanno avviati e controllati subito. Se aspetti di arrivare alla fine della configurazione, poi devi distinguere tra errore di installazione e errore applicativo.

sudo systemctl enable --now apache2 mariadb

La verifica minima è questa: i servizi devono risultare attivi e senza restart loop.

systemctl status apache2 mariadb --no-pager

Se Apache non parte, guarda subito il journal e non andare a tentativi.

journalctl -u apache2 -b --no-pager | tail -n 50

Con MariaDB il primo controllo utile è la reachability locale e lo stato del socket. Se il servizio è attivo ma non accetta connessioni, spesso il problema è un bind errato o una configurazione incompleta.

mysqladmin ping

3) Metti in sicurezza MariaDB prima di usarlo

Il database non va lasciato con impostazioni di default più del necessario. Il wizard di hardening serve a togliere accessi anonimi, database di test e login remoto non voluti.

sudo mysql_secure_installation

Le scelte sane di solito sono: password forte per l’account amministrativo, rimozione degli utenti anonimi, disabilitazione del login root remoto e rimozione del database di test. Se devi consentire connessioni da un host applicativo separato, fallo in modo esplicito con un utente dedicato e bind controllato, non aprendo tutto il servizio sulla rete.

Per verificare l’ascolto del database controlla su quale indirizzo è in bind. Se vedi 0.0.0.0 senza una ragione precisa, stai esponendo MariaDB più del necessario.

ss -lntp | grep 3306

4) Configura PHP in modo coerente con Apache

Per un setup semplice puoi usare mod_php, che è immediato da far funzionare. Se preferisci una separazione più pulita e migliore gestione dei processi, puoi passare a PHP-FPM. La scelta dipende dal carico e dal livello di controllo che vuoi sul runtime.

In un contesto classico da laboratorio o server piccolo, mod_php è spesso sufficiente. In ambienti più seri, PHP-FPM tende a essere una scelta migliore perché isola meglio gli errori e ti lascia più margine sulla gestione dei pool.

php -v

Fai un test rapido con una pagina PHP di verifica solo per confermare il percorso di esecuzione, poi rimuovila. Lasciare file di test in webroot è un errore banale che capita troppo spesso.

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

Poi apri la pagina dal browser o con curl. Se funziona, elimina subito il file.

curl -I http://localhost/info.php

Rimozione dopo test:

sudo rm -f /var/www/html/info.php

5) Crea un virtual host pulito per il sito

Non usare il virtual host di default oltre il primo test. Appena sai che Apache risponde, crea una configurazione dedicata al dominio o al nome host che userai davvero.

sudo nano /etc/apache2/sites-available/site.conf

Un esempio essenziale:

<VirtualHost *:80>
    ServerName example.local
    DocumentRoot /var/www/example

    <Directory /var/www/example>
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/example_error.log
    CustomLog ${APACHE_LOG_DIR}/example_access.log combined
</VirtualHost>

Abilita il sito, disabilita il default se non serve e ricarica Apache.

sudo a2ensite site.conf
sudo a2dissite 000-default.conf
sudo systemctl reload apache2

Verifica che il nuovo host risponda e che i log vengano scritti nel file giusto.

curl -I http://example.local
sudo tail -n 20 /var/log/apache2/example_access.log

6) Installa Code-Server senza esporlo male

Code-Server è comodo, ma non va trattato come un giocattolo. L’errore tipico è aprirlo direttamente su Internet con password debole o senza TLS. La scelta corretta è tenerlo dietro un reverse proxy o limitarlo a localhost e farci arrivare solo chi deve usarlo.

Il metodo di installazione dipende dal packaging disponibile sulla tua distro. Se usi il binario ufficiale o un pacchetto della community, controlla sempre firma, origine e path del servizio. Non dare per scontato che un installer terzo aggiorni come ti aspetti.

curl -fsSL https://code-server.dev/install.sh | sh

Dopo l’installazione verifica il servizio e la porta di ascolto.

systemctl status code-server --no-pager
ss -lntp | grep code-server

Se il servizio non esiste con quel nome, il pacchetto può aver creato un’unità diversa o un’installazione per singolo utente. In quel caso il punto da controllare è il file di unità in ~/.config/systemd/user/ oppure il percorso indicato dalla documentazione del pacchetto installato.

7) Configura Code-Server in modo operativo

La configurazione minima deve fissare porta, autenticazione e directory di lavoro. Se vuoi usarlo come editor di progetto, fai in modo che apra direttamente la cartella giusta e non la home dell’utente di servizio.

Un file di configurazione tipico, se previsto dal pacchetto, può includere host locale e password iniziale. La password non va lasciata in chiaro in documenti condivisi o in script di provisioning; se la devi distribuire, usa variabili segrete o un vault e ruotala dopo il primo accesso.

bind-addr: 127.0.0.1:8080
auth: password
password: <imposta-in-modo-sicuro>
cert: false

Se lo esponi solo in locale, poi lo pubblichi tramite Apache con proxy inverso e TLS. Questo ti consente di centralizzare certificati, header, access control e logging.

8) Pubblica Code-Server dietro Apache con HTTPS

Il modo più robusto è creare un secondo virtual host o una location dedicata. Apache termina TLS e inoltra le richieste a Code-Server in loopback.

sudo a2enmod proxy proxy_http proxy_wstunnel ssl headers

Snippet essenziale per il proxy, da adattare al tuo dominio:

<VirtualHost *:443>
    ServerName code.example.local

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/code.example.local/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/code.example.local/privkey.pem

    ProxyPreserveHost On
    ProxyRequests Off
    RequestHeader set X-Forwarded-Proto "https"

    ProxyPass / http://127.0.0.1:8080/ nocanon
    ProxyPassReverse / http://127.0.0.1:8080/

    ErrorLog ${APACHE_LOG_DIR}/code_error.log
    CustomLog ${APACHE_LOG_DIR}/code_access.log combined
</VirtualHost>

Se l’interfaccia web perde websocket o terminale integrato, aggiungi i moduli e la direttiva appropriata per il tunneling. In molti casi il sintomo è una UI parziale: editor visibile, terminale morto, reconnect continuo.

Dopo il reload verifica che risponda in HTTPS e che i cookie o i redirect non finiscano in loop.

sudo systemctl reload apache2
curl -Ik https://code.example.local

9) Aggiungi TLS valido e rinnovo automatico

Se il server è esposto in rete, TLS non è opzionale. Con Let’s Encrypt la parte importante non è solo ottenere il certificato, ma verificare il rinnovo automatico e la ricarica del web server.

sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache -d example.local -d code.example.local

Dopo l’emissione controlla la scadenza e il timer di rinnovo.

sudo certbot renew --dry-run
systemctl list-timers | grep certbot

Se usi un DNS interno o un ambiente non pubblico, Let’s Encrypt può non essere praticabile. In quel caso devi usare una CA interna o un certificato gestito in altro modo, ma il principio resta lo stesso: niente HTTP in chiaro per l’accesso editoriale se passa da rete non fidata.

10) Permessi, utenti e superficie d’attacco

Il punto più sottovalutato non è Apache, ma il filesystem. Se Code-Server modifica file del sito, l’utente che lo esegue deve avere solo i permessi necessari sulla directory del progetto. Non dare ownership totale di /var/www a un utente umano se non serve.

Un approccio più pulito è creare un gruppo di lavoro, assegnare la directory del progetto a quel gruppo e usare permessi coerenti. In questo modo il web server legge, l’editor scrive dove deve e non tocchi il resto del sistema.

sudo groupadd webedit
sudo usermod -aG webedit www-data
sudo chgrp -R webedit /var/www/example
sudo chmod -R 2775 /var/www/example

Il bit setgid sulla directory aiuta a mantenere il gruppo sui nuovi file. Va usato con criterio, non come scorciatoia per bypassare un modello di permessi fatto male.

11) Controlli finali che evitano sorprese il giorno dopo

Dopo l’installazione, fai una verifica che tocchi tutti i livelli: servizio, log, rete, applicazione e sicurezza minima. Una check-list rapida vale più di dieci minuti di supposizioni.

  • Apache risponde su 80 e 443: curl -I http://example.local e curl -Ik https://example.local.
  • MariaDB è attivo e non espone porte inutili: systemctl status mariadb e ss -lntp | grep 3306.
  • Code-Server risponde solo dove previsto: ss -lntp | grep 8080 e test via proxy HTTPS.
  • I log mostrano richieste e non errori continui: tail -n 50 /var/log/apache2/*.log.
  • Il rinnovo TLS è testato: certbot renew --dry-run.
  • Quando ha senso fermarsi e cambiare approccio

    Se il server ospita più progetti, più editor o team diversi, Code-Server singolo può diventare un collo di bottiglia operativo. A quel punto conviene valutare istanze separate, reverse proxy con autenticazione per utente o una piattaforma di sviluppo più strutturata. Se invece il carico è piccolo, una sola istanza ben protetta è spesso la scelta più razionale.

    Lo stesso vale per il database: se il sito cresce, MariaDB locale resta semplice ma può diventare fragile in caso di disco lento, backup assenti o RAM insufficiente. Prima di “ottimizzare” il codice, guarda saturazione CPU, I/O disco, memoria e tempi di risposta del database. Spesso il collo di bottiglia è lì, non in Apache.

    Schema operativo riassuntivo

    La sequenza corretta non è installare tutto e sperare. È: sistema aggiornato, servizi base attivi, database blindato, PHP verificato, virtual host separato, Code-Server limitato, TLS applicato, permessi ridotti al minimo, controlli finali. Se salti uno di questi passaggi, poi la manutenzione diventa più costosa del tempo risparmiato all’inizio.

    In pratica, LAMP ti dà la base stabile e Code-Server ti dà il canale operativo per lavorarci sopra. La parte importante è non confondere comodità con esposizione: l’editor remoto deve semplificare il lavoro, non allargare la superficie d’attacco.