Aggiornamento 05/09/2023: è disponibile la nuova guida aggiornata Configurazione di uno Stack LAMP su Windows 11 (e Windows 10), con WSL2, Ubuntu 22.04, servizi systemd nativi e ottimizzazioni per lo sviluppo con VS Code. Si consiglia vivamente di fare riferimento alla nuova guida.
Nota: questa guida creata da Maurizio Fonte è anche disponibile come GIST su GitHub all'indirizzo https://gist.github.com/mauriziofonte/00002661cd527a8a457509c5b4b0613d.
Lo sviluppo web con tecnologie puramente Linux (Stack LAMP - Linux, Apache, Mysql, PHP) è diventato estremamente semplice su Windows 10.
Infatti, con WSL è possibile, citando la pagina ufficiale di Microsoft: Sottosistema Windows per Linux consente agli sviluppatori di eseguire un ambiente GNU/Linux, inclusi la maggior parte degli strumenti da riga di comando, delle utilità e delle applicazioni, direttamente in Windows, senza modifiche e senza il sovraccarico di una macchina virtuale tradizionale o di una configurazione di avvio doppio.
Inoltre, sempre Microsoft è riuscita a creare uno degli editor di codice più potenti e completi in circolazione: Visual Studio Code. Una volta iniziato ad utilizzare, sarà molto molto difficile tornare indietro.
E' importante quindi conoscere come configurare un ambiente di sviluppo confortevole, che permetta di dire addio al vecchio modus operandi inefficiente e macchinoso che obbligava l'uso di WinSCP e Notepad++ con modifiche pubblicate direttamente sui server di produzione (o altri sistemi similari).
Con lo stack LAMP su Windows e l'utilizzo di Visual Studio Code e la continuous integration di Git, sarà possibile essere più produttivi e testare le condizioni reali di produzione direttamente sul proprio PC.
Nel corso del tempo, ho creato una guida esaustiva che spiega come configurare un ambiente di sviluppo comodo con stack LAMP utilizzando WSL2 su Windows. E' una lettura lunga, si consiglia di leggerla con calma, cercando di comprendere ogni passaggio, ed eventualmente adattarla ai propri scopi. Questa guida è anche disponibile a questo indirizzo, per una più comoda lettura: https://gist.github.com/mauriziofonte/00002661cd527a8a457509c5b4b0613d
Importante: come precondizione per un buon uso di questa guida, è necessaria una conoscenza minima del terminale di Linux e una buona dimestichezza con Windows.
Attenzione: questa guida è stata scritta per Windows 10. Tuttavia, potrebbe funzionare su Windows 11, ma non ho avuto modo di testarla dal vivo. Su Windows 11, quindi, seguire una guida specifica per l'abilitazione di WSL2, e tralasciare la parte WSL2 presente in questa guida.
Stack di sviluppo LAMP su Windows 10 con WSL2 e Visual Studio Code
Questa guida illustrerà come installare il supporto al sottosistema Linux nativo di Windows (WSL2), creare uno stack LAMP al suo interno, e agganciare Visual Studio Code per lo sviluppo direttamente su filesystem Linux.
La guida è aggiornata ad Agosto 2022 e necessita di questi prerequisiti:
- Computer con Windows 10, aggiornato all'ultima release disponibile
- 16GB di RAM
- 30GB di spazio libero su C:\ (conterrà il disco virtuale di Ubuntu)
- Un SSD (meglio NVMe) come disco di avvio di Windows (migliori performance con Mysql)
- Una conoscenza di base del terminale Linux (cd, cp, mv, sudo, nano, etc.)
Lo stack LAMP che andremo a configurare supporta https (con certificati autofirmati con scadenza a 10 anni), protocollo http/2 e compressione brotli. Per quanto riguarda la parte PHP, useremo PHP-FPM perchè è più performante e più versatile nella configurazione delle impostazioni per-virtualhost. Per capire le differenze tra l'utilizzo di PHP con Apache in modalità PHP-CGI piuttosto che PHP-FPM, si rimanda a questa guida: https://www.basezap.com/difference-php-cgi-php-fpm/
Installare Ubuntu 20.04 LTS su Windows
- Leggere il warning sotto (La versione di WSL deve essere la 2).
- Abilitare "Sottosistema Linux" da "Programmi e funzionalità"
- Cercare "Ubuntu" nel Windows Store e installare UBUNTU 20.04 LTS
- Avviare la macchina, attendere l'installazione, scegliere un nome utente (occhio, serve sotto ed è importante) composto da una singola parola corta tutta in minuscolo + la relativa password (corta, 1 sola lettera per comodità)
- Creare un collegamento desktop alla macchina Linux
- Creare un collegamento desktop alla directory home dell'utente, esempio:
\\wsl$\Ubuntu-20.04\home\maurizio
WARNING: la versione di WSL DEVE essere la 2
Questo è molto importante. Se non è installato WSL2, non funziona nulla.
Per questo motivo, leggere https://aka.ms/wsl2-install
. SI CONSIGLIA DI FARE QUESTA OPERAZIONE PRIMA DI INSTALLARE UBUNTU SUL SISTEMA.
Se necessario abilitare WSL2 (perchè non già abilitato), bisognerà aprire una PowerShell con privilegi elevati e usare questi comandi:
Installare questo pacchetto: https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart Restart-Computer # bisogna riavviare wsl --set-version Ubuntu-20.04 2 # IMPORTANTE: questo è necessario solo se si è installato ubuntu prima di abilitare WSL2 wsl --set-default-version 2
Modificare il resolver DNS di WSL2
Guida copiata da: https://superuser.com/questions/1533291/how-do-i-change-the-dns-settings-for-wsl2
A) Turn off generation of /etc/resolv.conf
Using your Linux prompt, (I'm using Ubuntu), modify (or create) /etc/wsl.conf with the following content
[network] generateResolvConf = false
(Apparently there's a bug in the current release where any trailing whitespace on these lines will trip things up.)
B) Restart the WSL2 Virtual Machine
Exit all of your Linux prompts and run the following Powershell command
wsl --shutdown
C) Create a custom /etc/resolv.conf
Open a new Linux prompt and cd to /etc
If resolv.conf is soft linked to another file, remove the link with rm resolv.conf
(originally it is linked to ../run/resolvconf/resolv.conf)
Create a new resolv.conf with the following content
nameserver 1.1.1.1
Configurare l'ambiente LAMP su Ubuntu - Step 1
Qui andremo ad installare tutti i pacchetti di PHP in tutte le versioni dalla 5.6 alla 8.1, nonchè il web server Apache e il server Mysql.
Perchè installare tante versioni di PHP? Perchè è importante avere a disposizione un ambiente di sviluppo che consenta, con facilità, di testare la propria applicazione con svariate versioni di PHP. Questo agevolerà il lavoro in caso di constraint specifici sui server di produzione dove andremo ad installare le applicazioni create.
Si presume che la versione di default di PHP che si vorrà utilizzare nel sistema sia la 8.1. Questo è modificabile tramite le righe update-alternatives --set php***
che si troveranno nella lista qui sotto. Ad esempio, se si desidera che la versione di PHP di default (quella che verrà utilizzata digitando semplicemente il comando php
e non la sua versione "versionata" es php7.4
) basterà specificare update-alternatives --set php /usr/bin/php7.4
.
IMPORTANTE: Lanciare tutti questi comando come l'utente root
. IMPORTANTE: Escludere le linee che iniziano con ### in quanto servono solo a differenziare i vari blocchi.
# APT UPGRADE & INSTALL OF PHP + APACHE apt update && apt upgrade apt install net-tools unzip git lsb-release ca-certificates apt-transport-https software-properties-common -y add-apt-repository ppa:ondrej/php add-apt-repository ppa:ondrej/apache2 apt install openssl apache2 brotli libapache2-mod-fcgid libapache2-mod-php8.1 php8.1 php8.1-cli php8.1-fpm php8.1-common php8.1-bcmath php8.1-bz2 php8.1-curl php8.1-gd php8.1-intl php8.1-mbstring php8.1-mcrypt php8.1-mysql php8.1-xml php8.1-zip libapache2-mod-php8.0 php8.0 php8.0-cli php8.0-fpm php8.0-common php8.0-bcmath php8.0-bz2 php8.0-curl php8.0-gd php8.0-intl php8.0-mbstring php8.0-mcrypt php8.0-mysql php8.0-xml php8.0-zip libapache2-mod-php7.4 php7.4 php7.4-cli php7.4-fpm php7.4-common php7.4-bcmath php7.4-bz2 php7.4-curl php7.4-gd php7.4-intl php7.4-json php7.4-mbstring php7.4-mcrypt php7.4-mysql php7.4-xml php7.4-zip libapache2-mod-php7.3 php7.3 php7.3-cli php7.3-fpm php7.3-common php7.3-bcmath php7.3-bz2 php7.3-curl php7.3-gd php7.3-intl php7.3-json php7.3-mbstring php7.3-mcrypt php7.3-mysql php7.3-xml php7.3-zip libapache2-mod-php7.2 php7.2 php7.2-cli php7.2-fpm php7.2-common php7.2-bcmath php7.2-bz2 php7.2-curl php7.2-gd php7.2-intl php7.2-json php7.2-mbstring php7.2-mcrypt php7.2-mysql php7.2-xml php7.2-zip libapache2-mod-php7.1 php7.1 php7.1-cli php7.1-fpm php7.1-common php7.1-bcmath php7.1-bz2 php7.1-curl php7.1-gd php7.1-intl php7.1-json php7.1-mbstring php7.1-mcrypt php7.1-mysql php7.1-xml php7.1-zip libapache2-mod-php7.0 php7.0 php7.0-cli php7.0-fpm php7.0-common php7.0-bcmath php7.0-bz2 php7.0-curl php7.0-gd php7.0-intl php7.0-json php7.0-mbstring php7.0-mcrypt php7.0-mysql php7.0-xml php7.0-zip libapache2-mod-php5.6 php5.6 php5.6-cli php5.6-fpm php5.6-common php5.6-bcmath php5.6-bz2 php5.6-curl php5.6-gd php5.6-intl php5.6-json php5.6-mbstring php5.6-mcrypt php5.6-mysql php5.6-xml php5.6-zip update-alternatives --set php /usr/bin/php8.1 update-alternatives --set phar /usr/bin/phar8.1 update-alternatives --set phar.phar /usr/bin/phar.phar8.1 update-alternatives --set phpize /usr/bin/phpize8.1 update-alternatives --set php-config /usr/bin/php-config8.1 ### OPTIONAL SQLITE3 SUPPORT apt install php5.6-sqlite3 php7.0-sqlite3 php7.1-sqlite3 php7.2-sqlite3 php7.3-sqlite3 php7.4-sqlite3 php8.0-sqlite3 php8.1-sqlite3 ### OPTIONAL REDIS SUPPORT sudo apt install redis-server php5.6-redis php7.0-redis php7.1-redis php7.2-redis php7.3-redis php7.4-redis php8.0-redis php8.1-redis # APACHE HTTP2 + PHP-FPM + SSL + REWRITE + BROTLI a2dismod php5.6 php7.0 php7.1 php7.2 php7.3 php7.4 php8.0 php8.1 mpm_prefork a2enconf php5.6-fpm php7.0-fpm php7.1-fpm php7.2-fpm php7.3-fpm php7.4-fpm php8.0-fpm php8.1-fpm a2enmod actions fcgid alias proxy_fcgi rewrite ssl http2 mpm_event brotli # INSTALL MYSQL apt install mysql-client-8.0 mysql-server-8.0
Configurare l'ambiente LAMP su Ubuntu - Step 2
Qui andremo a modificare le configurazioni di base di Apache e Mysql per poter lavorare localmente.
- Aprire il file /etc/apache2/envvars con
nano
e modificare APACHE_RUN_USER e APACHE_RUN_GROUP settandoli, al posto chewww-data
, con il proprio nome utente - Aprire il file /etc/apache2/ports.conf con
nano
e modificare ogni occorrenza diListen
con Listen 127.0.0.1 (esempio: 127.0.0.1:80 127.0.0.1:443) - Lanciare
service apache2 restart
per applicare le modifiche alla config di Apache. - Aprire il file /etc/mysql/mysql.conf.d/mysqld.cnf e aggiungere queste righe (sostituisci [LF] con delle andate a capo) nella sezione
[mysqld]
, (per intenderci, sotto la riga# datadir = /var/lib/mysql
) :bind-address = 127.0.0.1 [LF] skip-networking [LF] sql_mode=NO_ENGINE_SUBSTITUTION [LF] default-authentication-plugin=mysql_native_password [LF] collation-server = utf8_unicode_ci [LF] character-set-server = utf8
- (opzionale) Per completezza, al fondo di questo file è presente una configurazione di fine-tuning per un sistema con almeno 16GB di RAM. Volendo, si può direttamente copia-incollare quella configurazione.
- Lanciare
service mysql restart
per applicare le modifiche alla config di Mysql. - Lanciare
mysql_secure_installation
per creare la password di root per mysql (usare qualcosa di semplice, perchè serve solo localmente), rimuovere l'accesso per gli utenti anonimi, le tabelle temporanee, e disabilitare il login remoto al demone Mysql. - Eseguire
mysql -u root
e lanciare i comandi di seguito: CREATE USER 'admin'@'%' IDENTIFIED BY 'x';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
Ovviamente, le query mysql relative allo username e password da creare come utente privilegiato possono essere modificate. Nell'esempio sopra riportato viene creato un utente con username admin
e password x
. Ricordarsi che stiamo configurando un ambiente di sviluppo locale, e fintanto che non viene "aperto" al mondo esterno, non dobbiamo preoccuparci di usare politiche corrette per la sicurezza.
Creare dei VirtualHost funzionanti sulla propria installazione locale - Step 3
Per creare dei VirtualHost
è sufficiente utilizzare questi due script che velocizzano la configurazione.
Come fase esemplificativa, verrà mostrato come creare un VirtualHost specifico per PhpMyAdmin, che comunque è necessario per poter lavorare.
A questo punto, se ancora loggati come l'utente root
, uscire dall'utente root
e tornare in modalità utente.
sudo mkdir /etc/apache2/certs2/ cd ~/ mkdir utils cd utils/ nano create-staging-environment.php (copiare da sotto il contenuto del file) nano create-ssl-cert.sh (copiare da sotto il contenuto del file) chmod +x create-ssl-cert.sh cd ~/ nano lamp.sh (copiare da sotto il contenuto del file) chmod +x lamp.sh wget https://files.phpmyadmin.net/phpMyAdmin/5.1.1/phpMyAdmin-5.1.1-all-languages.zip unzip phpMyAdmin-5.1.1-all-languages.zip rm -f phpMyAdmin-5.1.1-all-languages.zip mv phpMyAdmin-5.1.1-all-languages phpmyadmin
Ora abbiamo creato la directory radice per l'installazione di phpmyadmin. Non resta che configurare un VirtualHost funzionante.
Lanciare quindi il comando sudo php create-staging-environment.php
e seguire le istruzioni. Queste istruzioni si applicano a tutti i progetti web che si vogliono installare sul sistema.
Nell'esempio, il virtualhost per PhpMyAdmin verrà settato come local.phpmyadmin.biz
. Ovviamente, modificare le risposte seguendo il proprio nome utente. Rispondere alle domande dello script come segue:
maurizio@FISSO:~$ cd ~/utils/ maurizio@FISSO:~/utils$ sudo php create-staging-environment.php ### STAGING ENVIRONMENT CREATOR ### Enter a valid local domain name: local.phpmyadmin.biz Enter a valid directory in the filesystem for the DocumentRoot: /home/maurizio/phpmyadmin/ Enter a valid PHP version (5.6, 7.1, 7.2, 7.3, 7.4, 8.0 or 8.1): 7.4 Do you need HTTPS support (yes/no/y/n) ? y
Ora, bisogna modificare il file hosts di Windows per inserire il puntamento locale al dominio local.phpmyadmin.biz
. Per farlo, modificare il file C:\Windows\System32\drivers\etc\hosts
aggiungendo la regola 127.0.0.1 local.phpmyadmin.biz
.
Dopodichè, aprire una command line di Windows in modalità privilegiata e lanciare ipconfig /flushdns
Fatto! Ora è possibile navigare sul proprio browser all'indirizzo https://local.phpmyadmin.biz/setup/ per proseguire il setup go PhpMyAdmin.
Per creare altri VirtualHost per altri progetti, utilizzare sempre le stesse istruzioni seguite per il setup di PhpMyAdmin. Basterà far puntare il VirtualHost alla directory giusta del proprio progetto, e definire un nome di dominio fittizio che sarà reindirizzato via HOSTS verso 127.0.0.1
Ottimizzare l'esperienza Linux - Step 4
Per ottimizzare l'installazione LAMP e l'esperienza utente sulla console dei comandi di Linux, seguire questi passaggi:
- Seguire le istruzioni di installazione di
https://github.com/slomkowski/bash-full-of-colors
- Lanciare
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
per installare NVM (per sviluppo NodeJS/React) - Lanciare
cd ~/utils/ && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && php composer-setup.php && php -r "unlink('composer-setup.php');"
per installare una versione locale di composer all'interno della directory /utils/ - Creare una coppia di chiavi pubblica/privata con il comando
ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/nome_chiave -C "utente@computer"
- Comunicare il contenuto della chiave pubblica al proprio team, che la userà per esempio per abilitare l'accesso ad un repository GIT privato.
- Copia-incollare il contenuto dello snippet bash_local all'interno di
~/.bash_local
modificando la variabile $NOME_UTENTE con il nome dell'utente scelto
Note importanti:
- E' possibile fare il reset della macchina Linux con il comando
wslrestart
che è stato aliasato in~/.bash_local
. Così facendo si resetta completamente il sottosistema WSL2. - Ogni volta che si esegue il login alla macchina virtuale, bisognerà lanciare il comando
~/lamp.sh
per avviare i servizi Apache, PHP-FPM e Mysql. Questo è necessario perchè l'ambiente LAMP non è stato installato come servizio di sistema (per intenderci, con systemd).
Installare VS Code per accedere ai file di progetto su WSL2 - Step 5
VS Code è totalmente integrato e compatibile con WSL2, nativamente.
Questo incrementa la produttività e semplifica tantissimo lo sviluppo.
Per installare e configurare VS Code con WSL2 è sufficiente:
- Installare VS Code scaricandolo da
https://code.visualstudio.com/
- Aprire VS Code e premere la combinazione di comandi
CTRL + SHIFT + x
- Installare l'estensione Remote - WSL
- Riavviare VS Code
- Aprire una console di Ubuntu, e portarsi su una directory a piacere, ad esempio
~/utils/
- Lanciare il comando
code .
e lasciare che il sistema installi quello che gli serve - Voilà, ora è possibile modificare i file presenti su Ubuntu direttamente da VS Code!
Ottimizzare lo sviluppo web con le estensioni giuste di VS Code - Step 6
Portarsi su una console di Ubuntu e lanciare questi comandi:
cd ~/
mkdir .composer && cd .composer/
nano composer.json
e inserire questo contenuto all'interno:
{ "require": { "squizlabs/php_codesniffer": "^3.5", "friendsofphp/php-cs-fixer": "^2.16" } }
- Lanciare
composer install
- Ora abbiamo a disposizione i binari di php-cs-fixer e php codesniffer, ci serviranno per la config di VS Code
- Aprire VS Code, e portarsi su un progetto residente dentro Ubuntu per rimanere in "modalità WSL2"
- Premere
CTRL + SHIFT + x
, cercare php cs fixer e installare la versione del plugin di junstyle (https://github.com/junstyle/vscode-php-cs-fixer.git) - Installare le seguenti estensioni: GitLens (Eric Amodio, https://github.com/eamodio/vscode-gitlens), Git History (Don Jayamanne, https://github.com/DonJayamanne/gitHistoryVSCode), PHP Intelephense (Ben Mewburn, https://github.com/bmewburn/vscode-intelephense), Prettier - Code Formatter (Prettier, https://github.com/prettier/prettier-vscode), PHP DocBlocker (Nail Brayfield, https://github.com/neild3r/vscode-php-docblocker), Twig Language (mblode, https://github.com/mblode/vscode-twig-language), markdownlint (David Anson, https://github.com/DavidAnson/vscode-markdownlint)
- Installare il seguente pacchetto icone: Material Icon Theme (Philipp Kief, https://github.com/PKief/vscode-material-icon-theme)
- Premere la combinazione di tasti
CTRL + SHIFT + p
, digitare preferenze, e cliccare su Preferenze: Apri Impostazioni (JSON) - Copia-incollare la configurazione riportata nello snippet vscode-json-config
Contenuto dello snippet "vscode-json-config"
Ovviamente bisogna modificare la path di php-cs-fixer.executablePath secondo il proprio nome utente.
{ "window.menuBarVisibility": "toggle", "window.zoomLevel": 0.2, "explorer.confirmDelete": false, "explorer.confirmDragAndDrop": false, "workbench.iconTheme": "material-icon-theme", "workbench.colorTheme": "Quiet Light", "workbench.colorCustomizations": { "editorCursor.foreground": "#444" }, "workbench.editor.showTabs": true, "terminal.integrated.fontFamily": "monospace", "terminal.integrated.lineHeight": 0.8, "terminal.integrated.enableBell": false, "terminal.integrated.letterSpacing": -0.1, "terminal.integrated.fontSize": 16, "editor.fontWeight": "600", "editor.cursorStyle": "line", "editor.cursorBlinking": "phase", "editor.rulers": [130], "editor.formatOnSave": true, "editor.minimap.enabled": false, "editor.wordWrap": "on", "editor.insertSpaces": true, "editor.tabSize": 4, "html.format.contentUnformatted": "pre,code,textarea", "html.format.endWithNewline": false, "html.format.extraLiners": "head, body, /html", "html.format.indentHandlebars": false, "html.format.indentInnerHtml": false, "html.format.maxPreserveNewLines": null, "html.format.preserveNewLines": true, "html.format.wrapLineLength": 130, "html.format.wrapAttributes": "auto", "telemetry.enableCrashReporter": false, "telemetry.enableTelemetry": false, "prettier.trailingComma": "all", "prettier.endOfLine": "auto", "prettier.singleQuote": true, "prettier.useTabs": true, "prettier.tabWidth": 4, "prettier.printWidth": 130, "prettier.jsxBracketSameLine": true, "prettier.semi": false, "[php]": { "editor.formatOnSave": true, "editor.defaultFormatter": "junstyle.php-cs-fixer" }, "[js]": { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascript]": { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[css]": { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[jsx]": { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[twig]": { "editor.formatOnSave": true, "editor.defaultFormatter": "mblode.twig-language" }, "php.suggest.basic": false, "php.validate.enable": true, "typescript.updateImportsOnFileMove.enabled": "never", "git.enableSmartCommit": true, "git.autofetch": true, "git.confirmSync": false, "php-cs-fixer.executablePath": "/home/$NOME_UTENTE/.composer/vendor/bin/php-cs-fixer", "php-cs-fixer.executablePathWindows": "", //eg: php-cs-fixer.bat "php-cs-fixer.onsave": false, "php-cs-fixer.rules": "@PSR2", "php-cs-fixer.config": ".php_cs;.php_cs.dist", "php-cs-fixer.allowRisky": false, "php-cs-fixer.pathMode": "override", "php-cs-fixer.exclude": [], "php-cs-fixer.autoFixByBracket": true, "php-cs-fixer.autoFixBySemicolon": false, "php-cs-fixer.formatHtml": false, "php-cs-fixer.documentFormattingProvider": true, "php-cs-fixer.lastDownload": 0, "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "php-docblocker.returnGap": true, "php-docblocker.qualifyClassNames": true, "php-docblocker.author": { "name": "NOME SVILUPPATORE", "email": "EMAIL@SVILUPPATORE.BIZ" }, "diffEditor.ignoreTrimWhitespace": false }
Contenuto dello snippet ".bash_local"
alias casa="cd /home/$NOME_UTENTE" alias composer="/usr/bin/php7.4 -d allow_url_fopen=1 /home/$NOME_UTENTE/utils/composer.phar" alias php="/usr/bin/php7.4 -d allow_url_fopen=1 -d memory_limit=1024M" alias php74="/usr/bin/php7.4 -d allow_url_fopen=1 -d memory_limit=1024M" alias apt="sudo apt-get" alias ls="ls -lash --color=auto --group-directories-first" alias cd..="cd .." alias ..="cd ../../" alias ...="cd ../../../" alias ....="cd ../../../../" alias .....="cd ../../../../" alias .4="cd ../../../../" alias .5="cd ../../../../.." alias ports="sudo netstat -tulanp" alias wslrestart="history -a && cmd.exe /C wsl --shutdown" alias tic="git" alias npmclean="npm ci" alias npmcheck="ncu" gitremove() { git branch -d "$@" git push origin --delete "$@" } hugefiles() { du -a "$@" | sort -n -r | head -n 100 } hugedirs() { cd "$@" && du -hsx -- * | sort -rh | head -100 } export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
Contenuto dello script "lamp.sh"
#!/usr/bin/env bash echo "### Starting MYSQL 8 ..." sudo service mysql start echo "### Starting PHP-FPM 5.6, 7.*, 8.*" [ -d /var/run/php/ ] || sudo mkdir /var/run/php/ sudo service php5.6-fpm start sudo service php7.0-fpm start sudo service php7.1-fpm start sudo service php7.2-fpm start sudo service php7.3-fpm start sudo service php7.4-fpm start sudo service php8.0-fpm start sudo service php8.1-fpm start echo "### Starting Apache Server ..." sudo service apache2 start
Contenuto dello script "create-staging-environment.php"
IMPORTANTE: Dopo il copia-incolla in create-staging-environment.php
, ricordarsi di modificare le stringhe ##NOME_UTENTE## in modo che contengano il nome utente scelto in fase di setup di Ubuntu..
<?php if (php_sapi_name() !== "cli") { message('ERROR: This script can only be run from the CLI.', 'e'); exit(); } if (posix_getuid() !== 0) { message('ERROR: This script can only be run as ROOT or sudo.', 'e'); exit(); } if (!is_dir('/etc/apache2/certs2/')) { message('ERROR: You need to create the directory /etc/apache2/certs2/ as root prior of executing this script.', 'e'); exit(); } define('APACHE_SITES_AVAILABLE_DIR', '/etc/apache2/sites-available/'); define('APACHE_CERTS_DIR', '/etc/apache2/certs2/'); define('APACHE_CERT_SELFSIGNED_SCRIPT', './create-ssl-cert.sh'); define('PHP_FPM_CONFIG_DIR', '/etc/php/#VER#/fpm/pool.d/'); define('APACHE_MAX_CONF_INDEX', getApacheSitesAvailableMaxIndex()); message('### STAGING ENVIRONMENT CREATOR ###'); // 1. ask for the local domain name $work = true; while ($work) { $domain = readline('Enter a valid local domain name: '); $domain = strtolower(str_replace(['http://', 'https://', 'www.'], '', $domain)); if (filter_var('http://' . $domain, FILTER_VALIDATE_URL)) { $work = false; define('DOMAIN', $domain); } else { message('Error. Retry.', 'e'); } } // 2. ask for the local directory that will be served as the DocumentRoot $work = true; while ($work) { $document_root = readline('Enter a valid directory in the filesystem for the DocumentRoot: '); if (is_dir($document_root)) { $work = false; define('DOCUMENT_ROOT', rtrim($document_root, '/')); } else { message('Error. Retry.', 'e'); } } // 3. ask for the PHP version for PHP-FPM $work = true; while ($work) { $php_version = readline('Enter a valid PHP version (5.6, 7.0, 7.1, 7.2, 7.3, 7.4, 8.0 or 8.1): '); if (in_array($php_version, ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'])) { $work = false; define('PHPVER', $php_version); } else { message('Error. Retry.', 'e'); } } // 4. ask for HTTPS support $work = true; while ($work) { $https_support = readline('Do you need HTTPS support (yes/no/y/n) ? '); if (in_array(strtolower($https_support), ['yes', 'no', 'y', 'n'])) { $work = false; if (in_array(strtolower($https_support), ['yes', 'y'])) { define('HTTPS_SUPPORT', true); } else { define('HTTPS_SUPPORT', false); } } else { message('Error. Retry.', 'e'); } } // 5. perform actions $apache_conf_stream = getApacheConf(); $php_fpm_conf_stream = getPhpFpmConf(); $apache_conf_file = APACHE_SITES_AVAILABLE_DIR . APACHE_MAX_CONF_INDEX . '-' . DOMAIN . '.conf'; $php_fpm_conf_file = str_replace('#VER#', PHPVER, PHP_FPM_CONFIG_DIR) . DOMAIN . '.conf'; if (file_put_contents($apache_conf_file, $apache_conf_stream)) { message('Apache configuration written correctly, going to enable the website', 's'); exec('a2ensite ' . basename($apache_conf_file)); if (file_put_contents($php_fpm_conf_file, $php_fpm_conf_stream)) { message('PHP-FPM configuration written successfully', 's'); if (HTTPS_SUPPORT) { message('Going to CD into ' . APACHE_CERTS_DIR); exec('cd ' . APACHE_CERTS_DIR); message('Going to call the self-signed cert script ' . APACHE_CERT_SELFSIGNED_SCRIPT . ' with domain "' . DOMAIN . '"'); exec(APACHE_CERT_SELFSIGNED_SCRIPT . ' ' . DOMAIN); } message('Going to exec "service apache2 force-reload"'); exec('service apache2 force-reload'); message('Going to exec "service php' . PHPVER . '-fpm restart"'); exec('service php' . PHPVER . '-fpm restart'); } else { message('Cannot write PHP-FPM configuration', 'e'); } } else { message('Cannot write Apache configuration', 'e'); } function message(string $string, string $type = 'i') { switch ($type) { case 'e': //error echo "\033[31m$string \033[0m\n"; break; case 's': //success echo "\033[32m$string \033[0m\n"; break; case 'w': //warning echo "\033[33m$string \033[0m\n"; break; case 'i': //info echo "\033[36m$string \033[0m\n"; break; default: echo "$string\n"; break; } } function getApacheSitesAvailableMaxIndex() : string { $files = glob(APACHE_SITES_AVAILABLE_DIR . '*.conf'); if ($files && count($files) > 0) { $max_index = 0; foreach ($files as $file) { $file = basename($file); if (preg_match('/^([0-9]+).*\.conf$/ui', $file, $matches)) { $index = intval($matches[1]); if ($index >= $max_index) { $max_index = $index; } } } return str_pad($max_index + 1, 3, '0', STR_PAD_LEFT); } return '001'; } function getApacheConf() { $domain = DOMAIN; $document_root = DOCUMENT_ROOT; $phpver = PHPVER; $newline = "\\n"; $conf_http = <<<HTML <VirtualHost 127.0.0.1:80> ServerName $domain ServerAlias www.$domain DocumentRoot $document_root ServerAdmin admin@localhost.net UseCanonicalName Off Options -ExecCGI -Includes RemoveHandler cgi-script .cgi .pl .plx .ppl .perl CustomLog \${APACHE_LOG_DIR}/$domain combined CustomLog \${APACHE_LOG_DIR}/$domain-bytes_log "%{%s}t %I .$newline%{%s}t %O ." # Enable HTTP2 Protocols h2 http/1.1 <FilesMatch \.php$> # Apache 2.4.10+ can proxy to unix socket SetHandler "proxy:unix:/var/run/php/php$phpver-fpm-$domain.sock|fcgi://localhost/" </FilesMatch> <IfModule mod_brotli.c> AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css text/javascript application/x-javascript application/javascript application/json application/x-font-ttf application/vnd.ms-fontobject image/x-icon </IfModule> <Directory $document_root/> Options -Indexes +FollowSymLinks AllowOverride All order allow,deny allow from all Require all granted </Directory> ##AUTOREWRITE## </VirtualHost> HTML; $conf_https = <<<HTML <IfModule mod_ssl.c> <VirtualHost 127.0.0.1:443> ServerName $domain ServerAlias www.$domain DocumentRoot $document_root ServerAdmin admin@localhost.net UseCanonicalName Off Options -ExecCGI -Includes RemoveHandler cgi-script .cgi .pl .plx .ppl .perl CustomLog \${APACHE_LOG_DIR}/ssl-$domain combined CustomLog \${APACHE_LOG_DIR}/ssl-$domain-bytes_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" # Enable HTTP2 Protocols h2 http/1.1 <FilesMatch "\.(cgi|shtml|phtml|php)$"> SSLOptions +StdEnvVars </FilesMatch> <Directory $document_root/> Options -Indexes +FollowSymLinks AllowOverride All order allow,deny allow from all Require all granted </Directory> <IfModule mod_brotli.c> AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css text/javascript application/x-javascript application/javascript application/json application/x-font-ttf application/vnd.ms-fontobject image/x-icon </IfModule> <FilesMatch \.php$> # Apache 2.4.10+ can proxy to unix socket SetHandler "proxy:unix:/var/run/php/php$phpver-fpm-$domain.sock|fcgi://localhost/" </FilesMatch> SSLEngine on SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP SSLCertificateFile "/etc/apache2/certs2/$domain.crt" SSLCertificateKeyFile "/etc/apache2/certs2/$domain.key" </VirtualHost> </IfModule> HTML; if (HTTPS_SUPPORT) { return str_replace( '##AUTOREWRITE##', 'RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^/(.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]', $conf_http ) . chr(10) . chr(10) . $conf_https; } else { return str_replace('##AUTOREWRITE##', '', $conf_http); } } function getPhpFpmConf() { $domain = DOMAIN; $document_root = DOCUMENT_ROOT; $phpver = PHPVER; $php_fpm_conf = <<<HTML [$domain] user = ##NOME_UTENTE## group = ##NOME_UTENTE## listen = /var/run/php/php$phpver-fpm-$domain.sock listen.owner = ##NOME_UTENTE## listen.group = ##NOME_UTENTE## php_admin_value[disable_functions] = apache_child_terminate,apache_get_modules,apache_getenv,apache_note,apache_setenv,define_syslog_variables,disk_free_space,diskfreespace,dl,fpassthru,get_current_user,getmyuid,highlight_file,passthru,pclose,pcntl_exec,pfsockopen,php_uname,pcntl_alarm,pcntl_fork,pcntl_get_last_error,pcntl_signal,pcntl_getpriority,pcntl_setpriority,pcntl_strerror,pcntl_signal_dispatch,pcntl_sigprocmask,pcntl_waitpid,pcntl_wait,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_wexitstatus,pcntl_wifexited,pcntl_wifsignaled,pcntl_wifstopped,pcntl_wstopsig,pcntl_wtermsig,popen,show_source,socket_select,socket_strerror,stream_select,syslog,symlink php_admin_flag[allow_url_fopen] = off pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 chdir = / catch_workers_output = yes php_flag[display_errors] = off php_admin_value[error_log] = $document_root/php$phpver-fpm-errors.log php_admin_flag[log_errors] = on php_admin_value[post_max_size] = 128M php_admin_value[upload_max_filesize] = 128M php_admin_value[memory_limit] = 1024M php_value[memory_limit] = 1024M php_value[short_open_tag] = On HTML; return $php_fpm_conf; }
Contenuto dello script "create-ssl-cert.sh"
#!/usr/bin/env bash # Ask for the base domain BASE_DOMAIN="$1" if [ -z "$BASE_DOMAIN" ]; then echo "Usage: $(basename $0) <domain>" exit 11 fi fail_if_error() { [ $1 != 0 ] && { unset PASSPHRASE exit 10 } } # Generate a passphrase export PASSPHRASE=$(head -c 500 /dev/urandom | tr -dc a-z0-9A-Z | head -c 128; echo) # Days for the cert to live DAYS=3650 # Generated configuration file CONFIG_FILE="config.txt" cat > $CONFIG_FILE <<-EOF [req] default_bits = 2048 prompt = no default_md = sha256 x509_extensions = v3_req distinguished_name = dn [dn] C = IT ST = Italy L = Torino O = Acme Corp OU = The Dev Team emailAddress = webmaster@$BASE_DOMAIN CN = $BASE_DOMAIN [v3_req] subjectAltName = @alt_names [alt_names] DNS.1 = *.$BASE_DOMAIN DNS.2 = $BASE_DOMAIN EOF # The file name can be anything FILE_NAME="$BASE_DOMAIN" # Remove previous keys echo "Removing existing certs like $FILE_NAME.*" if ls /etc/apache2/certs2/$FILE_NAME.* 1> /dev/null 2>&1; then rm -rf /etc/apache2/certs2/$FILE_NAME.* fi echo "Generating certs for $BASE_DOMAIN" # Generate our Private Key, CSR and Certificate # Use SHA-2 as SHA-1 is unsupported from Jan 1, 2017 openssl req -new -x509 -newkey rsa:2048 -sha256 -nodes -keyout "/etc/apache2/certs2/$FILE_NAME.key" -days $DAYS -out "/etc/apache2/certs2/$FILE_NAME.crt" -passin pass:$PASSPHRASE -config "$CONFIG_FILE" # OPTIONAL - write an info to see the details of the generated crt openssl x509 -noout -fingerprint -text < "/etc/apache2/certs2/$FILE_NAME.crt" > "/etc/apache2/certs2/$FILE_NAME.info" # Protect the key chmod 400 "/etc/apache2/certs2/$FILE_NAME.key" # Remove the config file rm -f $CONFIG_FILE
Contenuto del file di config Mysql "mysqld.conf"
Questo file è riportato per comodità. Non è necessario usarlo, ma è fortemente consigliato nel caso si abbia a disposizione una macchina con almenot 16GB di RAM.
# # The MySQL database server configuration file. # # One can use all long options that the program supports. # Run program with --help to get a list of available options and with # --print-defaults to see which it would actually understand and use. # # For explanations see # http://dev.mysql.com/doc/mysql/en/server-system-variables.html # Here is entries for some specific programs # The following values assume you have at least 32M ram [mysqld] # # * Basic Settings # user = mysql # pid-file = /var/run/mysqld/mysqld.pid # socket = /var/run/mysqld/mysqld.sock # port = 3306 # datadir = /var/lib/mysql # If MySQL is running as a replication slave, this should be # changed. Ref https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_tmpdir # tmpdir = /tmp # # Instead of skip-networking the default is now to listen only on # localhost which is more compatible and is not less secure. bind-address = 127.0.0.1 skip-networking sql_mode=NO_ENGINE_SUBSTITUTION default-authentication-plugin=mysql_native_password collation-server = utf8_unicode_ci character-set-server = utf8 # # * Fine Tuning # # sort_buffer_size = 256000000 (orig) # key_buffer_size = 16M (orig) # max_allowed_packet = 64M # thread_stack = 256K # thread_cache_size = -1 # This replaces the startup script and checks MyISAM tables if needed # the first time they are touched myisam-recover-options = BACKUP # my fine tuning max_connections = 20 table_open_cache = 2048 thread_stack = 32M thread_cache_size = 8 max_allowed_packet = 16M max_heap_table_size = 128M binlog_cache_size = 2M sort_buffer_size = 16M join_buffer_size = 16M tmp_table_size = 128M key_buffer_size = 512M read_buffer_size = 4M read_rnd_buffer_size = 32M bulk_insert_buffer_size = 64M myisam_sort_buffer_size = 128M innodb_buffer_pool_size = 2G innodb_lock_wait_timeout = 150 # table_open_cache = 4000 # # * Logging and Replication # # Both location gets rotated by the cronjob. # # Log all queries # Be aware that this log type is a performance killer. # general_log_file = /var/log/mysql/query.log # general_log = 1 # # Error log - should be very few entries. # log_error = /var/log/mysql/error.log # # Here you can see queries with especially long duration # slow_query_log = 1 # slow_query_log_file = /var/log/mysql/mysql-slow.log # long_query_time = 2 # log-queries-not-using-indexes # # The following can be used as easy to replay backup logs or for replication. # note: if you are setting up a replication slave, see README.Debian about # other settings you may need to change. # server-id = 1 # log_bin = /var/log/mysql/mysql-bin.log # binlog_expire_logs_seconds = 2592000 max_binlog_size = 100M # binlog_do_db = include_database_name # binlog_ignore_db = include_database_name