Installare LibreBooking in una sottodirectory (con WordPress in root)

Questa guida spiega come installare e far funzionare LibreBooking (fork di MRBS) in una sottodirectory di un sito, con WordPress installato nella root. L’obiettivo tipico è raggiungere l’app a un URL come https://esempio.it/prenotazioni/ servendo i file pubblici dalla cartella Web/ dell’applicazione.

Punti chiave da ricordare:

  • La parte pubblica di LibreBooking è in Web/.
  • Nel file config/config.php imposta $conf['script']['url'] coerente con l’URL pubblico.
  • Le cartelle tpl/ e tpl_c/ devono essere scrivibili dal web server (Smarty compila i template in tpl_c/).

Prerequisiti

  • Server web (Apache o nginx) con PHP (consigliato PHP-FPM) e MySQL/MariaDB.
  • Estensioni PHP comuni: mysqli o pdo_mysql, mbstring, intl, json, xml.
  • mod_rewrite attivo su Apache e AllowOverride All dove serve.

Struttura delle cartelle

/var/www/html/
├── index.php                 ← WordPress (root del sito)
├── wp-content/ …
└── prenotazioni/             ← LibreBooking
    ├── Web/                  ← entrypoint pubblico
    │   └── index.php
    ├── config/
    │   ├── config.dist.php
    │   └── config.php
    ├── tpl/                  ← template sorgente
    └── tpl_c/                ← cache Smarty (scrivibile)

Database

CREATE DATABASE librebooking CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'lb_user'@'localhost' IDENTIFIED BY 'password_sicura';
GRANT ALL PRIVILEGES ON librebooking.* TO 'lb_user'@'localhost';
FLUSH PRIVILEGES;

Configurazione di LibreBooking

Copia config/config.dist.php in config/config.php e imposta almeno:

<?php
$conf['script']['url'] = 'https://esempio.it/prenotazioni/Web';

$conf['db']['type']     = 'mysqli';
$conf['db']['host']     = 'localhost';
$conf['db']['name']     = 'librebooking';
$conf['db']['user']     = 'lb_user';
$conf['db']['password'] = 'password_sicura';

date_default_timezone_set('Europe/Rome'); 

Permessi delle cartelle

Imposta i permessi per l’utente del web server (es. www-data, apache, nginx):

cd /var/www/html/prenotazioni
mkdir -p tpl tpl_c
sudo chown -R www-data:www-data tpl tpl_c
sudo chmod -R 755 tpl tpl_c
# Durante l'installazione, se necessario:
sudo chown -R www-data:www-data config
sudo chmod -R 775 config

WordPress in root: regole di esclusione

Nel .htaccess della root (dove c’è WordPress), aggiungi una regola che bypassi la sottocartella prima del blocco WP:

RewriteEngine On
RewriteRule ^prenotazioni/ - [L]

# BEGIN WordPress


RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]


# END WordPress

.htaccess nella sottodirectory di LibreBooking

Nel file /var/www/html/prenotazioni/.htaccess usa destinazioni relative (senza / iniziale) per redirigere verso Web/. In una .htaccess di sottodirectory, lo slash iniziale indirizzerebbe la radice del vHost, causando 404/loop.

RewriteEngine On

# Durante i test usa 302; a regime usa 301

RewriteRule ^$ Web/ [R=302,L]
RewriteRule !^Web/ Web/$0 [R=302,L]

Options -Indexes

Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"


# Non inserire direttive php_value qui se usi PHP-FPM


Require all denied
 

Alternativa nginx (con PHP-FPM)

Servire esplicitamente /prenotazioni/Web/

server {
    listen 80;
    server_name esempio.it;
    root /var/www/html;
    index index.php index.html;

    location /prenotazioni/Web/ {
        index index.php;
        try_files $uri $uri/ /booking/Web/index.php?$args;
        location ~* \.(ini|dist|md|lock|env|ya?ml)$ { deny all; }
        autoindex off;
    }

    location ~ ^/prenotazioni/Web/.*\.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.4-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include snippets/fastcgi-php.conf;
    }

location ~ \.php$ {
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include snippets/fastcgi-php.conf;
}

location ~* .(ini|dist|md|lock|env|yml|yaml)$ { deny all; }
autoindex off;

} 

Alias “pulito” /prenotazioni/ → cartella fisica /prenotazioni/Web/

server {
    listen 80;
    server_name esempio.it;

location /prenotazioni/ {
    alias /var/www/html/prenotazioni/Web/;
    index index.php index.html;

    try_files $uri $uri/ /index.php$args;

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        # Con alias va impostato manualmente:
        fastcgi_param SCRIPT_FILENAME /var/www/html/prenotazioni/Web/$fastcgi_script_name;
        include snippets/fastcgi-php.conf;
    }
}

location ~* .(ini|dist|md|lock|env|yml|yaml)$ { deny all; }
autoindex off;

} 

Se usi l’alias per nascondere /Web/, imposta $conf['script']['url'] a https://esempio.it/prenotazioni/ per coerenza.

Smoke test

  1. Crea prenotazioni/Web/ping.txt con contenuto ok e visita /prenotazioni/Web/ping.txt: deve dare 200.
  2. Visita /prenotazioni/: deve redirigere a /prenotazioni/Web/ (302 finché testi).
  3. Crea prenotazioni/Web/phpinfo.php con <?php phpinfo(); e verifica che PHP risponda.

Troubleshooting: 500 vs 404

  • 500 (Internal Server Error): spesso direttive non permesse in .htaccess (php_value con FPM), moduli mancanti (Header senza mod_headers), permessi insufficenti su tpl_c/ o config/, estensioni PHP non caricate.
  • 404: in genere la richiesta finisce su WordPress (manca la regola di bypass in root) o le regole di prenotazioni/.htaccess usano destinazioni con / iniziale.

Controlla i log del server:

# Apache (Debian/Ubuntu)
tail -n 100 /var/log/apache2/error.log

# Apache (RHEL/CentOS)

tail -n 100 /var/log/httpd/error_log

# nginx

tail -n 100 /var/log/nginx/error.log 

Best practice di sicurezza

  • Esporre pubblicamente solo la cartella Web/ (o un alias che la mappi), non l’intera app.
  • Bloccare l’accesso a file sensibili (.env, .dist, .ini, ecc.).
  • Evitare chmod 777; preferire owner o group corretti.
  • Non usare php_value in .htaccess con PHP-FPM; configurare in php.ini o nel pool FPM.
  • Impostare session.autostart = 0 e date.timezone coerente.

Note importanti su rewrite in .htaccess

  • In una .htaccess di sottodirectory le sostituzioni dovrebbero essere relative (niente / iniziale). Esempio corretto: RewriteRule !^Web/ Web/$0.
  • La regola di bypass in root per WordPress evita che le richieste a /prenotazioni/ cadano nell’index.php del CMS.

Checklist finale

  • mod_rewrite attivo e AllowOverride All dove serve.
  • Regola di bypass in root: RewriteRule ^prenotazioni/ - [L] sopra il blocco WordPress.
  • In prenotazioni/.htaccess destinazioni senza / iniziale verso Web/.
  • tpl/ e tpl_c/ scrivibili dal web server.
  • $conf['script']['url'] coerente con l’URL pubblico esposto.
  • Redirect 302 → 301 solo quando tutto funziona e la cache del browser è pulita.
Torna su