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 🙂