#Server configuration *Example virtual host configurations for popular web servers* - [Apache](#apache)[](.html) - [LightHttpd](#lighthttpd) (empty)[](.html) - [Nginx](#nginx)[](.html) ## Prerequisites * Shaarli is installed in a directory readable/writeable by the user * the correct read/write permissions have been granted to the web server _user and/or group_ * for HTTPS / SSL: * a key pair (public, private) and a certificate have been generated * the appropriate server SSL extension is installed and active Related guides: * [How to Create Self-Signed SSL Certificates with OpenSSL](http://www.xenocafe.com/tutorials/linux/centos/openssl/self_signed_certificates/index.php)[](.html) * [How do I create my own Certificate Authority?](https://workaround.org/certificate-authority)[](.html) ## Apache ### Minimal ```apache ServerName shaarli.my-domain.org DocumentRoot /absolute/path/to/shaarli/ ``` ### Debug - Log all the things! This configuration will log both Apache and PHP errors, which may prove useful to identify server configuration errors. See: * [Apache/PHP - error log per VirtualHost](http://stackoverflow.com/q/176) (StackOverflow)[](.html) * [PHP: php_value vs php_admin_value and the use of php_flag explained](PHP: php_value vs php_admin_value and the use of php_flag explained)[](.html) ```apache ServerName shaarli.my-domain.org DocumentRoot /absolute/path/to/shaarli/ LogLevel warn ErrorLog /var/log/apache2/shaarli-error.log CustomLog /var/log/apache2/shaarli-access.log combined php_flag log_errors on php_flag display_errors on php_value error_reporting 2147483647 php_value error_log /var/log/apache2/shaarli-php-error.log ``` ### Standard - Keep access and error logs ```apache ServerName shaarli.my-domain.org DocumentRoot /absolute/path/to/shaarli/ LogLevel warn ErrorLog /var/log/apache2/shaarli-error.log CustomLog /var/log/apache2/shaarli-access.log combined ``` ### Paranoid - Redirect HTTP (:80) to HTTPS (:443) See [Server-side TLS](https://wiki.mozilla.org/Security/Server_Side_TLS#Apache) (Mozilla).[](.html) ```apache ServerName shaarli.my-domain.org DocumentRoot /absolute/path/to/shaarli/ SSLEngine on SSLCertificateFile /absolute/path/to/the/website/certificate.crt SSLCertificateKeyFile /absolute/path/to/the/website/key.key AllowOverride All Options Indexes FollowSymLinks MultiViews Order allow,deny allow from all LogLevel warn ErrorLog /var/log/apache2/shaarli-error.log CustomLog /var/log/apache2/shaarli-access.log combined ServerName shaarli.my-domain.org Redirect 301 / https://shaarli.my-domain.org LogLevel warn ErrorLog /var/log/apache2/shaarli-error.log CustomLog /var/log/apache2/shaarli-access.log combined ``` ## LightHttpd ## Nginx ### Foreword Nginx does not natively interpret PHP scripts; to this effect, we will run a [FastCGI](https://en.wikipedia.org/wiki/FastCGI) service, to which Nginx's FastCGI module will proxy all requests to PHP resources.[](.html) Required packages: - [nginx](http://nginx.org)[](.html) - [php-fpm](http://php-fpm.org) - PHP FastCGI Process Manager[](.html) Official documentation: - [Beginner's guide](http://nginx.org/en/docs/beginners_guide.html)[](.html) - [ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html)[](.html) - [Pitfalls](http://wiki.nginx.org/Pitfalls)[](.html) Community resources: - [Server-side TLS (Nginx)](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) (Mozilla)[](.html) - [PHP configuration examples](http://kbeezie.com/nginx-configuration-examples/) (Karl Blessing)[](.html) ### Common setup Once Nginx and PHP-FPM are installed, we need to ensure: - Nginx and PHP-FPM are running using the _same user and group_ - both these user and group have - `read` permissions for Shaarli resources - `execute` permissions for Shaarli directories _AND_ their parent directories On a production server: - `user:group` will likely be `http:http`, `www:www` or `www-data:www-data` - files will be located under `/var/www`, `/var/http` or `/usr/share/nginx` On a development server: - files may be located in a user's home directory - in this case, make sure both Nginx and PHP-FPM are running as the local user/group! For all following examples, a development configuration will be used: - `user:group = john:users`, which corresponds to the following service configuration: ```ini ; /etc/php/php-fpm.conf user = john group = users [...][](.html) listen.owner = john listen.group = users ``` ```nginx # /etc/nginx/nginx.conf user john users; http { [...][](.html) } ``` ### Minimal _WARNING: Use for development only!_ ```nginx user john users; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; keepalive_timeout 20; index index.html index.php; server { listen 80; server_name localhost; root /home/john/web; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; location /shaarli/ { access_log /var/log/nginx/shaarli.access.log; error_log /var/log/nginx/shaarli.error.log; } location ~ (index)\.php$ { fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; } } } ``` ### Modular The previous setup is sufficient for development purposes, but has several major caveats: - every content that does not match the PHP rule will be sent to client browsers: - dotfiles - in our case, `.htaccess` - temporary files, e.g. Vim or Emacs files: `index.php~` - asset / static resource caching is not optimized - if serving several PHP sites, there will be a lot of duplication: `location /shaarli/`, `location /mysite/`, etc. To solve this, we will split Nginx configuration in several parts, that will be included when needed: ```nginx # /etc/nginx/deny.conf location ~ /\. { # deny access to dotfiles access_log off; log_not_found off; deny all; } location ~ ~$ { # deny access to temp editor files, e.g. "script.php~" access_log off; log_not_found off; deny all; } ``` ```nginx # /etc/nginx/php.conf location ~ (index)\.php$ { # filter and proxy PHP requests to PHP-FPM fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; } location ~ \.php$ { # deny access to all other PHP scripts deny all; } ``` ```nginx # /etc/nginx/static_assets.conf location ~* \.(?:ico|css|js|gif|jpe?g|png)$ { expires max; add_header Pragma public; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; } ``` ```nginx # /etc/nginx/nginx.conf [...][](.html) http { [...][](.html) root /home/john/web; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; server { # virtual host for a first domain listen 80; server_name my.first.domain.org; location /shaarli/ { access_log /var/log/nginx/shaarli.access.log; error_log /var/log/nginx/shaarli.error.log; } include deny.conf; include static_assets.conf; include php.conf; } server { # virtual host for a second domain listen 80; server_name second.domain.com; location /minigal/ { access_log /var/log/nginx/minigal.access.log; error_log /var/log/nginx/minigal.error.log; } include deny.conf; include static_assets.conf; include php.conf; } } ``` ### Redirect HTTP to HTTPS Assuming you have generated a (self-signed) key and certificate, and they are located under `/home/john/ssl/localhost.{key,crt}`, it is pretty straightforward to set an HTTP (:80) to HTTPS (:443) redirection to force SSL/TLS usage. ```nginx # /etc/nginx/nginx.conf [...][](.html) http { [...][](.html) index index.html index.php; root /home/john/web; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; server { listen 80; server_name localhost; return 301 https://localhost$request_uri; } server { listen 443 ssl; server_name localhost; ssl_certificate /home/john/ssl/localhost.crt; ssl_certificate_key /home/john/ssl/localhost.key; location /shaarli/ { access_log /var/log/nginx/shaarli.access.log; error_log /var/log/nginx/shaarli.error.log; } include deny.conf; include static_assets.conf; include php.conf; } } ```