Jeg havde en kunde der skulle bruge en relativt simpel opsætning med 3 webhoteller på en server, og pludselig kom der et spørgsmål jeg ikke havde forventet. “Hvad nu hvis en af mine sider bliver hacket, bliver de andre så også automatisk hacket?” og nej det gør de selvfølgelig ikke, det er logik … for en som mig. Men hvis man har brugt discount udbydere der afvikler alle websites med de samme privilegier og har set dem blive hacket et par gange kan jeg selvfølgelig godt forstå at man tror det er tilfældet.
Men det er det heldigvis ikke, en korrekt opsat webserver tilader ikke de individuelle brugere at tilgå hinandens data, så derfor besluttede jeg mig at skrive dette indlæg / denne guide til atsætte apache op.
En kort disclaimer er vel på sin plads: der er ikke nogen enkelt handling der kan gøre noget “sikkert”, ligesom sikkerhed ikke er absolut, alting udvikler sig og der skal laves cost-benefit analyser osv.osv. Men den her metode er ihvertfald et rigtigt godt udgangspunkt.
Kort beskrevet vil jeg sætte en Debian 6.0 op med Apache2, PHP, Fcgi, Suexec, Proftpd, Mysql og Phpmyadmin. Ud ad til vil det for en ordinær webudvikler ligne et ganske almindeligt webhotel, så brugeren behøver ikke tilegne til yderligere evner end dem han i forvejen har. Vi starter ud med en frisk installeret Debian 6.0 med SSH installeret, hvis ikke du selv kan finde ud af at lave den del så bør du finde en anden guide og starte der, det bliver ihvertfald ikke gennemgået her.
Grundlæggende opsætning af Apache med virtualhosts:
Den her del er det de fleste typisk laver når de sætter Apache op, så den går vi hurtige igennem. Jeg vil oprette site1.lab1.mikjaer.com og site2.lab1.mikjaer.com og så et default-webdir til sider der ikke matcher de to ovenstående.
Først installerer jeg apache og vim
root@lab1:~# apt-get install apache2 vim
Herefter bør webserveren køre, det kan bekræftes ved at besøge http://lab1.mikjaer.com nu mangler vi bare at opsætte et par virtuelle hosts, Debians initscripts er opbygget således at det faktisk er dejlig nemt, i /etc/apache2/sites-available ligger en fil der hedder default, den kopierer jeg til en ny fil der hedder site1:
root@lab1:~# cd /etc/apache2/sites-available/ root@lab1:/etc/apache2/sites-available# cp default site1
Derefter åbner jeg filen i min favoriteditor (vim), den ser således ud:
<VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /var/www <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /var/www/> Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ <Directory "/usr/lib/cgi-bin"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
Først retter jeg i linie 4 så DocumentRoot nu bliver /var/www/site1/htdocs dernæst i linie 9 så der står <Directory /var/www/site1/htdocs> og så retter jeg linie 24 og 30 så der står site1- foran log-filnavnene, så sletter jeg linie 16-22 og tilføjer “ServerName site1.lab1.mikjaer.com” lige efter linie 2, så ser filen således ud:
<VirtualHost *:80> ServerAdmin webmaster@localhost ServerName site1.lab1.mikjaer.com DocumentRoot /var/www/site1/htdocs <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /var/www/site1/htdocs> Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> ErrorLog ${APACHE_LOG_DIR}/site-error.log # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog ${APACHE_LOG_DIR}/site-access.log combined </VirtualHost>
Gem filen, og åben derefter /etc/apache2/sites-available/site1 som ser således ud:
<VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /var/www <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /var/www/> Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ <Directory "/usr/lib/cgi-bin"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
Tilføj lige efter linie 2 linien “ServerName lab1.mikjaer.com”, gem filen og opret herefter mappen /var/www/site1/htdocs med en midlertidig index.html fil i, aktiver det nye site og genstart apache således:
root@lab1:~# mkdir -p /var/www/site1/htdocs root@lab1:~# echo Dette er site1 > /var/www/site1/htdocs/index.html root@lab1:~# a2ensite site1 Enabling site site1. Run '/etc/init.d/apache2 reload' to activate new configuration! root@lab1:~# /etc/init.d/apache2 reload Reloading web server config: apache2.
Nu burde du kunne verificere at opsætningen indtil videre virker ved at gå ind på http://lab1.mikjaer.com og http://site1.lab1.mikjaer.com og konstatere at de to URL’s viser noget forskelligt. (du skal selvfølgelig have sat DNS op selv og sørge for at de subdomæner du har valgt peger på din servers IP Adresse).
Apache vælger VirtualHost efter først-til-mølle princippet, den første dekleration der matcher den url brugeren har skrevet bliver den aktuelle. Dvs hvis du først har *.domæne.dk og sidenhen har test.domæne.dk vil test.domæne.dk altså aldrig blive vist. Hvis ikke nogen matcher vises den første virtualhost, det er derfor at default config filen er prefixet med 000, netop fordi at så loades den altid først. Typisk ønsker du at erstatte den enten med dit primære site, eller en splash-screen der fortæller at siden ikke findes.
Privilege seperation med fcgi og suexec
Vi starter med at opgradere det setup vi har ligenu, vi skal bruge en php fortolker og de to Apache moduler, fcgid og suexec, kommandoen kommer ikke bag på de fleste:
root@lab1:~# apt-get install libapache2-mod-fcgid apache2-suexec-custom php5-cgi
Og så skal de aktiveres:
root@lab1:~# a2enmod fcgid suexec actions Module fcgid already enabled Enabling module suexec. Enabling module actions. Run '/etc/init.d/apache2 restart' to activate new configuration!
Og fcgid skal konfigureres, opret filen /etc/apache2/conf.d/php5-fcgid.conf og indsæt flg i den:
AddType application/x-httpd-php .php AddHandler php-fcgi .php Action php-fcgi /fcgi-bin/php5-fcgi Alias /fcgi-bin/ /var/www/ <Location /fcgi-bin/> SetHandler fcgid-script Options +ExecCGI </Location>
Filen /var/www/php5-fcgi oprettes ligeledes med flg. indhold:
#!/bin/sh exec /usr/bin/php5-cgi
Den første fil indeholder standard værdier for fcgid og php5-fcgi er den wrapper som bruges til at udføre php scripts med, det er også her det f.eks. er muligt at inkludere en specialtilpasset php.ini fil.
Så oprettes den bruger der skal eje og udføre site1’s filer og php-scripts:
root@lab1:~# adduser site1 Adding user `site1' ... Adding new group `site1' (1001) ... Adding new user `site1' (1001) with group `site1' ... Creating home directory `/home/site1' ... Copying files from `/etc/skel' ... Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully Changing the user information for site1 Enter the new value, or press ENTER for the default Full Name []: Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n] y
Brugeren skal have fjernet muligheden for at logge ind, dette gøres ved at sætte dens shell til /sbin/nologin og homedir skal sættes til /var/www/site1, fcgid wrapperen skal flyttes ind i brugerens homedir og til sidst skal brugeren tildeles rettighederne over /var/www/site1 som nu er dens homedir:
root@lab1:~# usermod site1 -s /sbin/nologin root@lab1:~# usermod site1 -d /var/www/site1 root@lab1:~# cp /var/www/php5-fcgi /var/www/site1/ root@lab1:~# chown -R site1:site1 /var/www/site1/ root@lab1:~# chmod 755 /var/www/php5-fcgi
Til sidst skal vi lige tilføje et par linier i /etc/apache2/sites-available/site1 for at aktivere suexec pluginet for site1’s virtualhost, det drejer sig om linie 17 og linie 18:
<VirtualHost *:80> ServerAdmin webmaster@localhost ServerName site1.lab1.mikjaer.com DocumentRoot /var/www/site1/htdocs <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /var/www/site1/htdocs> Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> Alias /fcgi-bin/ /var/www/site1/ SuexecUserGroup site1 site1 ErrorLog ${APACHE_LOG_DIR}/site-error.log # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog ${APACHE_LOG_DIR}/site-access.log combined </VirtualHost>
Til sidst for at teste slette vi den gamle index.html …
root@lab1:~# rm /var/www/site1/htdocs/index.html
… og opretter en index.php i /var/www/site1/htdocs/index.php
<? system("id"); ?>
Genstart apache:
root@lab1:~# /etc/init.d/apache2 restart Reloading web server config: apache2.
og naviger ind på http://site1.lab1.mikjaer.com/, resultatet skulle gerne se nogenlunde sådan her ud:
uid=1001(site1) gid=1001(site1) groups=1001(site1)
Hvis det ikke er tilfældet kan det hjælpe at kigge i /var/log/apache2/suexec.log som fortæller dig hvad der går galt, typisk handler det om forkerte rettigheder.
Nu kører dine php scrips med en specifik Unix bruger og du kan tildele en unik unix bruger pr. vhost, så har du faktisk klaret selve seperationen. Nu mangler du kun lidt brugervenligshed …
Opsæt ProFtpd, Mysql og Phpmyadmin
Igen, vi kører debian så no big deal her:
root@lab1:~# mysql -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 51 Server version: 5.1.61-0+squeeze1 (Debian) Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> create database site1; Query OK, 1 row affected (0.00 sec) mysql> grant all privileges on site1.* to "site1"@localhost identified by "site1kode"; Query OK, 0 rows affected (0.00 sec) mysql> quit Bye
Du kan teste database adgangen med:
root@lab1:~# mysql -usite1 -psite1kode site1 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 52 Server version: 5.1.61-0+squeeze1 (Debian) Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | site1 | +--------------------+ 2 rows in set (0.00 sec) mysql> quit Bye
Til sidst mangler vi at sætte ftp op, først tildeler vi brugeren en kode:
root@lab1:~# passwd site1 Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully
Og verificerer at koden IKKE virker til SSH Login:
root@lab1:~# ssh site1@localhost The authenticity of host 'localhost (127.0.0.1)' can't be established. RSA key fingerprint is c9:74:e4:8d:20:22:3d:94:96:41:b8:62:c7:37:2d:43. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'localhost' (RSA) to the list of known hosts. site1@localhost's password: Permission denied, please try again.
For at tillade ftp login redigerer vi i /etc/proftpd/proftpd.conf, og fjerner udkommenteringen (#-mærket) ved linie 37 så der står:
# # /etc/proftpd/proftpd.conf -- This is a basic ProFTPD configuration file. # To really apply changes reload proftpd after modifications. # # Includes DSO modules Include /etc/proftpd/modules.conf # Set off to disable IPv6 support which is annoying on IPv4 only boxes. UseIPv6 on # If set on you can experience a longer connection delay in many cases. IdentLookups off ServerName "Debian" ServerType standalone DeferWelcome off MultilineRFC2228 on DefaultServer on ShowSymlinks on TimeoutNoTransfer 600 TimeoutStalled 600 TimeoutIdle 1200 DisplayLogin welcome.msg DisplayChdir .message true ListOptions "-l" DenyFilter \*.*/ # Use this to jail all users in their homes # DefaultRoot ~ # Users require a valid shell listed in /etc/shells to login. # Use this directive to release that constrain. RequireValidShell off # Port 21 is the standard FTP port. Port 21
(bemærk, kun en del af filen er vist her)
Genstart proftp og test login via ftp:
root@lab1:~# /etc/init.d/proftpd restart Stopping ftp server: proftpd. Starting ftp server: proftpd. root@lab1:~# ftp localhost Connected to localhost. 220 ProFTPD 1.3.3a Server (Debian) [::ffff:127.0.0.1] Name (localhost:root): site1 331 Password required for site1 Password: 230 User site1 logged in Remote system type is UNIX. Using binary mode to transfer files. ftp> ls 200 PORT command successful 150 Opening ASCII mode data connection for file list drwxr-xr-x 2 site1 site1 4096 May 7 16:44 htdocs -rwxr-xr-x 1 site1 site1 33 May 7 16:35 php5-fcgi 226 Transfer complete ftp>
Til sidst kan du teste at phpmyadmin kører ved at gå ind på http://site1.lab1.mikjaer.com/phpmyadmin/ , standard indstillingen i Debian er at phpmyadmin kan tilgåes på alle domæner ved at skrive /phpmyadmin bagefter.
Jeg håber du kan bruge guiden, jeg ved at jeg tager 5-7.000kr for at lave sådan en opsætning, så hvis du kan selv har du da ihvertfald sparet det 🙂
Har du nogen spørgsmål eller noget du gerne vil have uddybet? Så skriv en kommetar 🙂