Web sites hosting (discussion)
Discussions, thoughts and details about WebSite.
A (bit more) secure PHP
Apache's mod_php
is only able to run PHP scripts as the Apache user
(on Debian : www-data
). But we want one UID per website, and a quite
good isolation.
External information :
- a good comparison
- robots.org.uk about Apache security, another great comparison
Apache2 + mod_php
Good performance, but all sites run under a shared UID and the whole
security depends on safe_mode
and open_basedir
, which we maybe
don't want to try... well, actually, why not, inside a VServer.
Apache2 + suexec'ing PHP running as CGI
All these solutions are performance hogs : running in pure CGI mode, a PHP interpreter is loaded every time a PHP script is run :/
suPHP
- http://www.suphp.org/
- un module Apache + un binaire setuid root qui s'occupe de changer l'UID de PHP au besoin
- looks like a suExec clone, with no apparent enhancement
- 0.6.1 brings the possibility to chroot to a common (whole
server-wide) directory such as
/var/www
; along with proper permissions (o-rwx) this gives great sites isolation
Information sources :
- http://nico.tuxfamily.org/PHP/Suphp-Php4-Et-Php5-Avec-Apache-2-Sous-Debian
- patch enhancing the chroot mode : http://lists.marsching.biz/pipermail/suphp/2006-February/001224.html
php-cgi + suExec
- More or less the same performance and security as suPHP.
Apache2 + mpm-itk
- http://home.samfundet.no/~sesse/mpm-itk/
- 2.2.3-01-1 in etch
- supposedly experimental, but already used in prod. by folks
- we can't have a php.ini per site, but we can set our various
vhost-specific php variables (
session.save_path
, etc.) in Apache conf usingphp_admin_value
: http://fr.php.net/manual/fr/ini.php#ini.list and http://fr.php.net/manual/fr/configuration.changes.php - like suExec, but is compatible with mod_php and al ! cf http://mitka.us/articles/mpm-itk/
- is it really faster to fork a Apache child on every request than to load a new php cgi interpreter ?
Apache2 + suExec + a CGI dispatch daemon
If chrooting is wanted, a proper chroot must be build with php inside for every website :
- mod_chroot and suExec's chroot : perfect site isolation if o-rwx permissions on files and directories ; see http://permalink.gmane.org/gmane.comp.apache.mod-chroot.general/197
- mod_security has its own way to chroot apache : see here. Additional interest would be to avoid long and boring CMS patching process when a security hole appear by just adding some rules.
If chrooting is not wanted, things are not that hard to setup.
suExec wants the wrapper scripts to be owned by the user running the script, which we don't want : else, a simple PHP script would be allowed to modify the wrapper. Either suExec must be compiled with such checks disabled, or a workaround has to be used : immutable bit and ACLs are the main options, as explained on http://ckdake.com/projects/documentation/php_security/.
These solutions are supposed to be either a bit slower or a bit faster than mod_php.
mod_fastcgi
- homepage
- example configuration : http://www.seaoffire.net/fcgi-faq.html
- no upstream development for a long time
- supports external socket files
mod_fcgid
- http://fastcgi.coremail.cn
- compatible with suExec, suPHP, and fastcgi-mode PHP
http://typo3.org/development/articles/using-php-with-mod-fcgid/page/1/ and http://www.cosmocode.de/en/blogs/gohr/20070516093908/ : mod_fcgid with suExec on Debian etch
- does not support external socket
- needs suExec
mod_scgi
- PHP ne supporte pas encore SCGI
- supporte socket externe (à vérifier)
- peu utilisé, peu de doc
- exemple
mod_cgid
- ???
lighttpd with builtin FastCGI
- does not support name-based virtualhosts for SSL :/
- would maybe be a good choice for the "admin" server
- no .htaccess support, sometimes needs CMS customization
- often used being Apache mod_proxy
- PHP with per-site UID :
- fundamentals about FastCGI external spawning : http://trac.lighttpd.net/trac/wiki/Docs:ModFastCGI#external-spawning
- the
PHPRC
trick : http://trac.lighttpd.net/trac/ticket/971 - execwrap : suphp-like wrapper
- an detailed howto : http://trac.lighttpd.net/trac/wiki/HowToSetupFastCgiIndividualPermissions
- mod_fastcgi
- un tuto
- optimisation
Nginx
- chouette doc de config avancée : https://calomel.org/nginx.html
syslog
sans patcher
"suffit" de le faire logguer dans un named pipe, et au choix, soit de faire forwarder le contenu par un cat|machin.sh, soit de faire lire ce pipe à un démon syslog.
l'idée vient de : http://admin-monkey.com/doku.php?id=nginx
en patchant
y’a un patch qui semble maintenu. testé, pas réussi à faire marcher.
Module Fcgi
- exemple du wiki
- directives de cache du backend prises en compte à partir de 0.7.48 (dans lenny-bpo, squeeze)
- marche bien
PHP
- http://blog.hbis.fr/2009/03/18/nginx-fastcgi-php/
- exemple du wiki
- facile de désactiver PHP dans certains dossiers (
IMG
, etc.)
Mutualisé
- http://blog.hbis.fr/2009/06/18/nginx-vhosts/
cache
voir aussi :
- purger le cache : http://wiki.nginx.org/Nginx3rdPartyModules#Cache_Purge_Module
module fastcgi
http://wiki.nginx.org/NginxHttpFcgiModule
a des paramètres de cache, à creuser.
module proxy
http://wiki.nginx.org/NginxHttpProxyModule
- idée : mettre son répertoire de cache en ramdisk
modules memcached
- http://wiki.nginx.org/NginxHttpMemcachedModule
- http://wiki.nginx.org/NginxHttpMemcModule
- non: savent seulement lire depuis memcached, ou causer son protocole, mais pas tenir un cache à jour
remove_ip
doit bien y avoir un module pour changer des variables d’état HTTP à la volée
fastcgi_param
permet-il de mettre REMOTE_IP = 127.0.0.1 ou un truc comme ça ?
content negotiation
apparemment, ne supporte pas Content Negotiation (ikiwiki+po).
même avec proxy_pass
vers un Apache qui lui le supporte, ça n'a pas
l'air de fonctionner, car il cause HTTP/1.0 au backend :/
vrac
- logguer les requêtes particulièrement longues (lentes) : http://wiki.nginx.org/NginxHttpLogRequestSpeed (3rd party)
- fournir url pour invalider tel ou tel bout du cache : http://labs.frickle.com/nginx_ngx_cache_purge/
Cherokee
- un convaincu
- supporte TLS, vhosts, fastcgi, syslog, reverse proxy, etc.
- interface de conf web très complète, mais... si les fichiers de conf sont bien documentés, il est recommandé de ne pas les modifier à la main... sauf pour scripter, etc.
- reste à traduire les htaccess livrés par les CMS
- ne supporte pas Content Negotiation: bug report
SSL vs. vhosts
Supporte SNI, mais si le client ne supporte pas ?
FPM
- microdoc sur le wiki
- http://blog.myprod.net/2010/08/14/apache2-suexec-fastcgi-php-5-3-3-fpm-cache-opcode-apc/
- pas buildé dans le paquet Squeeze, mais se réactive trivialement + recompilation du paquet
Apache
Apache sait faire générer sa conf par un programme Perl, avec les PerlSections.
Nous choisissons cette solution, extrêmement flexible, plutôt qu'une des autres solutions :
DNS
Type du dns_enregistrement parent d'un web_site : A, mais pas forcément chez nous. C'est pourquoi on stocke, dans la table dns_records, les champs A qui pointent vers nous mais dont ne gérons pas le DNS, tout va bien.
Un CNAME peut-il être enregistrement parent d'un site web ? Cas possibles :
- CNAME externe/interne -> fqdn hébergé chez nous y compris DNS -> A interne
Alors enregistrement parent = ce A interne - CNAME externe/interne -> fqdn hébergé chez nous seulement au niveau web sous forme d'un A externe
Alors enregistrement parent = ce A externe - CNAME externe/interne -> fqdn hébergé chez nous seulement au niveau web sous forme d'un autre CNAME externe
Retour à la case départ.
Donc non.
Sauf que e raisonnement ci-dessus ne fonctionne que si un CNAME induit une redirection, càd si les requêtes web reçues sont adressées au fqdn destination (content).
Or... c'est faux. Par conséquent, oui, dans la théorie, un CNAME géré ailleurs mais pointant sur nous pourrait être enregistrement parent d'un site web. Sauf que ça complique beaucoup le schéma SQL, et donc, le modèle de franGiPane interdit ça.
NSS
We've got one UID per site, so we need "real" Unix users.
Il faut donc utiliser des vrais/faux users locaux, grâce à libnss-pgsql : <file:///usr/share/doc/libnss-pgsql1/nss-pgsql.html>.
TODO : gaffe à ce que ça implique :
- shell=/bin/false suffit ?
- PAM : ajouter un check à tous les services utilisant pam_unix ; appeler pam_shells dans /etc/pam.d/common-* devrait suffire
- services n'utilisant pas PAM mais NSS directement ? oulala... 'fin apparemment ça n'arrivera pas, ouais ouais le monde est bien fait.
Pour ce qui est des relations d'appartenance à un groupe, notre cas est beaucoup plus simple que le cas général ; en effet, un web_master n'administre qu'un web_site, et par conséquent, au sens NSS, un user n'appartient qu'à un groupe. Ainsi, dans /etc/nss-pgsql.conf, nous pourrons mettre :
passwdtable = ftp_passwd
grouptable = ftp_group
groupmembertable = ftp_passwd
group_member = login
querypasswd = SELECT login,passwd,uid,gid,gecos,homedir,shell FROM ftp_passwd
querygroup = SELECT name,passwd,gid FROM ftp_group
querymembers = SELECT login FROM ftp_passwd WHERE gid=%d
queryids = SELECT gid FROM ftp_passwd WHERE false
Attention ! /etc/nss-pgsql.conf
doit être lisible par les users qui doivent s'en servir, et il contient le mot de passe d'accès à la table contenant les passwords ftp (hashés)... il s'agit donc d'étanchéifier tout ça.
Postfix, par exemple, met du temps à se lancer s'il ne peut lire ce fichier. Pas grave, na.
nss-mysql a un truc pour éviter ce problème, et Lunar bosse sur un patch apportant la même fonctionnalité à nss-pgsql : un peu le même principe que pour /etc/{passwd,shadow}
, en fait.
TODO : tester ce patch
Remote web site editing
The web sites admins need to edit their sites files with a FTP-like method, without any password or bit of data travelling in cleartext over the Internet.
After studying the various solutions, we finally decided to setup a lightweight VServer dedicated to webmasters, hence its name : webmasters
. The webmasters are given ssh access to this VServer. This solution is described on WebSite.
PHP working directories
Every site have its own upload_tmp_dir
and session.save_path
, located in web:/var/tmp/frangipane/$DOMAIN/$SITE/php/{upload,sessions
.
CMS farm
We'd like to be able to host several sites on the same CMS install, such as SPIP, which will soon provide this functionnality :
- consider this centralized install as one web_site instance
- set
ftp_status
tooff
for this web_site object - every webmaster for these sites hosted on this common CMS install have to be web_master objects