Directory structuren

Auteur Twisted Bytes op 27 November 2015

Wij hebben bij Twisted Bytes een bepaald idee over de directory structuur die voor webhosting handig is. Omdat we er af en toe vragen over krijgen en omdat er een blog over onze Vagrant box voor development aan zit te komen gaan we het uitleggen.

 

Standaard structuur

Dit is een voorbeeld van de meest eenvoudige versie van onze standaard directory structuur:

/var/www/vhosts/[klant-id]/[site-naam]
├── logs
│   ├── php
│   │   └── [site-naam]-slow.log
│   │   └── [site-naam]-error.log
│   └── web
│       ├── [site-naam]_access.log
│       └── [site-naam]_error.log
├── private
│   ├── databases.ini
│   ├── php-sessions
│   └── php-tmp
├── site
│   └── docroot
└── .ssh
    ├── authorized_keys
    └── sftp_authorized_keys

Deze standaard structuur gebruiken wij voor de meeste hosting, de tekst tussen de haken ([ ]) wordt uiteraard bepaald door de informatie die in de haken staan. We plaatsen alle sites in een structuur die geschikt is voor 1 site op een server, maar ook voor meerdere sites van meerdere klanten op een server. Dit maakt het eenduidig voor alle servers en klanten.

Elke klant krijgt bij ons een intern id wat alleen voor de hosting gebruikt wordt. Het heeft de vorm: TBXXX-YYYY. Hierin zitten 2 factoren: hoofdklant (XXX) en subklant (XXXX). Een voorbeeld van zo’n id is: TB012-033. De reden van deze stap in de de directory is dat we ook toegang kunnen geven op het niveau van het klant-id. Met die toegang is het mogelijk om bij meerdere sites tegelijk te komen of data tussen sites van dezelfde klant te delen.

Dan is er de directory van de site zelf. De directory heeft een naam: [site-naam]. In de praktijk is dat de domeinnaam van de site: www.example.com. Dit is de homedirectory van de website. Alles van de website staat hierin.

 

Homedirectory structuur

In de homedirectory staan standaard 4 directories:

  • logs
  • private
  • site
  • .ssh

De logs directory wordt gebruikt voor het wegschrijven van de log bestanden van de diverse diensten specifiek voor deze site. Dat komt in de praktijk neer op php en de webserver. Maar als er andere diensten zijn worden die hier ook toegevoegd. Het is uiteraard mogelijk om zelf directories toe te voegen voor bijvoorbeeld de SilverStripe of laravel log.

De private directory is een structuur die “geheime” informatie bevat. Zoals in het eerste overzicht te zien is staan daar de php-tmp en php-sessions directories en een databases.ini bestand. De php-tmp is de map waar php de tijdelijke bestanden zal wegschrijven tijdens het uploaden of het aanmaken van een tijdelijk bestand met bijvoorbeeld de functie tmpfile(). Het databases.ini bestand bevat de lijst van databases die gemaakt zijn voor deze site. Dit bestand is uit te lezen met de PHP functie parse_ini_file(). Een voorbeeld van het gebruik ervan voor SilverStripe.

$database_info = parse_ini_file($_SERVER["HOME"] . '/private/databases.ini', true);
$database_config = array_shift($database_info);

define("SS_DATABASE_CLASS","MySQLPDODatabase");
define("SS_DATABASE_SERVER",$database_config['hostname']);
define("SS_DATABASE_PASSWORD",$database_config['password']);
define("SS_DATABASE_USERNAME",$database_config['username']);
define("SS_DATABASE_NAME",$database_config['database']);

unset($database_info);
unset($database_config);

Het voordeel is dat je geen databasenaam of wachtwoorden meer nodig hebt voor het plaatsen van een site. Het lijkt op de $_ENV methode om de database gegevens te publiceren. Wij hebben voor deze methode gekozen ipv de $_ENV omdat dit overal te gebruiken is, ook vanaf de commandline.

De .ssh directory is voor de standaard ssh bestanden en voor de SFTP login via ssh-key. In deze directory komen de bestanden authorized_keys en sftp_authorized_keys. Beide bestanden hebben hetzelfde doel, alleen is de sftp_authorized_keys voor de SFTP toegang. De SFTP server ondersteund alleen het standaard formaat van ssh-keys ipv het door openssh gebruikte eigen formaat.

Als laatste is er de site directory. Daarin staat de docroot directory waar de publieke bestanden van een site geplaatst moet worden. Dat is bijvoorbeeld de index.php, .htaccess voor rewrite-en naar de index.php voor de pretty-url’s en de assets zoals CSS, javascript en plaatjes. Uiteraard kan de hele site in de docroot geplaatst worden. De trend is om een site te scheiden in een publiek deel dat vanaf internet aangesproken kan worden en een privaat deel dat alleen door de code aangesproken kan worden. Dat is ook precies de reden waarom de docroot in een “site” directory staat. De “site” directory kan gebruikt worden voor het private deel van de site.

 

Variaties op de standaard structuur

De structuur zoals beschreven is gebaseerd op lange ervaring met het opzetten van website hosting omgevingen en de wensen van developers. Deze structuur werkt in veel gevallen erg goed en kan direct gebruikt worden. Soms zijn er echter redenen om hiervan af te wijken. Zoals een server voor staging of testen waar je snel en makkelijk een hele nieuwe site neer kan zetten.

Dynamic docroot

Het is soms handig als je alleen maar een directory hoeft te maken voor nieuwe site. Daarom hebben we een dynamic docroot variant. Wat dit doen is de site directory vervangen voor een domains directory. In die domains directory kun je vervolgens een directory maken met bijvoorbeeld de naam: test.example.com/docroot. De webserver is zo geconfigureerd dat bij het ontvangen van een request de goede docroot gekozen wordt. En doordat er nog steeds een docroot directory is kun je de publiek en privaat scheiding blijven houden.

Een voorbeeld structuur:

/var/www/vhosts/[klant-id]/[site-naam]
....
├── domains
│   └── test1.example.com
│   │   └── docroot
│   └── test2.example.com
│   │   └── docroot
│   └── www.another-example.com
│       └── docroot
....

Docroot als symlink

Nog een variant is dat de docroot niet verplicht een directory is, maar een symlink kan zijn. Standaard wordt de docroot door puppet gemaakt en moet het een directory zijn. Maar soms is het handig dat dat niet zo is. Bijvoorbeeld bij het “zero-downtime” deployen zoals capistrano en envoyer.io dat doen. Dat zijn git deploymethoden die met behulp van een docroot als symlink snel kunnen switchen tussen verschillende versies van de site.

Dat ziet er als volgt uit:

/var/www/vhosts/[klant-id]/[site-naam]
....
├── site
│   └── docroot -> current/docroot
│   └── current -> releases/20151125163633
│   └── shared
│       └── assets
│   └── releases
│       └── 20151125163633
│           └── docroot
│           └── vendor
│           └── composer.json
│       └── 20151123112356
│       └── 20151121092234
....

Deze structuur is wat ingewikkelder dan wat je vaak ziet, maar het wordt allemaal door een script opgebouwd volgens een vast principe. Tijdens deployment wordt een nieuwe directory met de huidige tijd als naam in de directory site/releases gemaakt. In die directory staat een volledige versie van de site. Alleen is de webserver niet op de hoogte van deze structuur. Die “weet” alleen van het path site/docroot af. Na een goede upload of checkout uit git in de releases directory wordt de “current” symlink veranderd zodat die wijst naar de nieuwe release, “releases/20151125163633” in dit geval. Doordat in de directory weer een subdirectory docroot aanwezig is blijft de link “site/docroot” geldig.

Met deze methode is het mogelijk om in een atomaire actie de site te switchen naar een nieuwe versie. En wij ondersteunen dit. Het is niet standaard, maar als je het aangeeft richten wij de server(s) zo in dat dit mogelijk is.

Public als docroot

De laatste variant is de docroot geen “docroot” noemen, maar iets anders. Een vaak gebruikte naam is bijvoorbeeld “public”. Dit kan uiteraard ook. En in alle varianten die besproken zijn.

 

Users

Een belangrijke eigenschap van onze directory structuur is dat de homedirectory ook echt een homedirectory van een systeem user is. Elke site bij ons draait als een eigen user. Dus PHP-FPM of HHVM draait als een user met de naam van de site. En bestanden die geupload worden zijn van die user.

De user is vervolgens onderdeel van de groep met de naam van de klant-id, zoals we die aan het begin besproken hebben. Zo kan de user met de naam van het klant-id ook bij de bestanden van zijn sites. En is het mogelijk dat bestanden die geschreven zijn door de ene site ook door een andere site gelezen kunnen worden. En dat allemaal zonder dat de veiligheid in het geding komt. Geen gedoe meer met bestanden die niet door PHP gelezen kunnen worden of alle bestanden maar chmod-den naar 0666 of alle directories naar 0777.

 

Tot slot

Wij hopen dat met deze uitleg onze ideeën over hoe de hosting directory structuur in elkaar zit te begrijpen zijn. We zijn tot deze structuur gekomen om aan de meest voorkomende eisen te voldoen.

Het kan echter zijn dat er een helemaal andere structuur nodig is. Dat kan en dat hebben we ook gedaan. Dus laat horen wat je er van vind! We zijn altijd blij met feedback.

Dit hele verhaal is ook van belang voor ons volgende blog over de Vagrant box: “twistedbytes/webserver”. Die maakt ook gebruik van de standaard structuur.

Tags: ,