Weby běžící pod vlastním uživatelem – Apache a peruser MPM

Provozovat webserver pro více aplikací s různými majiteli bez rozdělení vlastnických práv k souborům a běžícím procesům je docela hazard. Spustit každý web pod samostatným uživatelem můžete různými způsoby, já si vybral u Apache webserveru MPM peruser.

Na serverech využíváme primárně OS Linux –  distribuci CentOS. Součástí CentOSu peruser MPM není, je tedy třeba si ho přeložit ze zdrojového kódu. Zdrojový kód k peruser MPM lze stáhnout na domácí stránce projektu – www.peruser.org.

Překlad Apache ze zdrojového kódu řešíme „rebuildem“ RPM.  Stáhl jsem si originální src.rpm, upravil spec soubor a přidal do něj patch peruser MPM 0.4.0 MPM beta 2.

Upravený httpd.spec, zdrojový balíček připravený pro překlad a přeložené binárky přikládám ke stažení.

Po nainstalování apache z výše odkazovaných balíčků je nutné změnit používanou binárku  a tím i MPM z httpd.worker na httpd.peruser v souboru /etc/sysconfig/httpd. Změna se provede nastavením proměnné „HTTPD=/usr/sbin/httpd.peruser“.

Do konfiguračního soubouru apache /etc/httpd/conf/httpd.conf je nutné dopsat základní konfiguraci peruser MPM:

<IfModule peruser.c>
# Multiplexer pool
MinMultiplexers 3
MaxMultiplexers 10
ProcessorWaitTimeout 2 20

# Fork limits
ServerLimit 256
MaxClients 256
MaxRequestsPerChild 400

# Processor defaults
MinProcessors       4
MinSpareProcessors  4
MaxProcessors       128

# Timeouts
IdleTimeout 180
ExpireTimeout 3600
</IfModule>

Popis jednotlivých voleb je k nalezení v dokumentaci http://www.peruser.org/trac/peruser/wiki/PeruserDocumentation

Pro každého virtualhosta, kterého vytvoříte, je nutné specifikovat pod jakým uživatelem poběží.

<VirtualHost webserver:80>
  ServerName zdenda.com
  RewriteEngine On
  RewriteOptions Inherit
  DocumentRoot /var/www/zdenda.com/public_html
  <Directory /var/www/zdenda.com/public_html>
    AllowOverride All
  </Directory>
  Processor zdenda.com zdenda.com
  ServerEnvironment zdenda.com zdenda.com
  MaxProcessors 128
</VirtualHost>

<VirtualHost webserver:80>
  ServerName zdenda.com
  ServerAlias *.zdenda.com
  RewriteEngine On
  RewriteOptions Inherit
  DocumentRoot /var/www/zdenda.com
  VirtualDocumentRoot /var/www/zdenda.com/subdomains/%1
  <Directory /var/www/zdenda.com/subdomains/*>
    AllowOverride All
  </Directory>
  Processor zdenda.com zdenda.com
  ServerEnvironment zdenda.com zdenda.com
  MaxProcessors 128
</VirtualHost>

Virtualhosta mám dvakrát, protože první virtualhost je pro zdenda.com a druhý pro *.zdenda.com.

Výpis procesů apache (ps axfu) ukazuje jak jak apache forkuje potomky s různými vlastníky  (Passenger potomek apache nám zajišťuje běh Redmine):

root     13462  0.0  0.0 399320 22480 ?        Ss   Aug21   0:01 /usr/sbin/httpd.peruser
root     13700  0.0  0.0 212444  1340 ?        Ssl  Aug21   0:00  \_ PassengerWatchdog
root     13703  0.0  0.0 813956  2100 ?        Sl   Aug21   0:19  |   \_ PassengerHelperAgent
root     13705  0.0  0.0  53888 10468 ?        Sl   Aug21   0:14  |   |   \_ Passenger spawn server
10000    27651  2.6  0.4 262016 112468 ?       S    10:22   0:08  |   |       \_ Passenger ApplicationSpawner: /var/www/domain.tld/subdomain/redmine
nobody   13710  0.0  0.0 146476  2300 ?        Sl   Aug21   0:00  |   \_ PassengerLoggingAgent
apache   13716  0.0  0.0 399456 11776 ?        S    Aug21   0:00  \_ /usr/sbin/httpd.peruser
apache   13758  0.0  0.0 399456 11776 ?        S    Aug21   0:00  \_ /usr/sbin/httpd.peruser
apache   13777  0.0  0.0 399456 11776 ?        S    Aug21   0:00  \_ /usr/sbin/httpd.peruser
apache   13794  0.0  0.0 399592 11968 ?        S    Aug21   0:00  \_ /usr/sbin/httpd.peruser
10002    14261  0.0  0.0 399456 12332 ?        S    00:59   0:00  \_ /usr/sbin/httpd.peruser
10002    14262  0.0  0.0 399456 11476 ?        S    00:59   0:00  \_ /usr/sbin/httpd.peruser
10002    14263  0.0  0.0 399456 11476 ?        S    00:59   0:00  \_ /usr/sbin/httpd.peruser
10002    14264  0.0  0.0 399456 11476 ?        S    00:59   0:00  \_ /usr/sbin/httpd.peruser
10014    24408  0.0  0.1 413296 28588 ?        S    08:02   0:00  \_ /usr/sbin/httpd.peruser
10011    26760  0.0  0.0 399456 12384 ?        S    09:42   0:00  \_ /usr/sbin/httpd.peruser
10011    27079  0.0  0.0 399456 12384 ?        S    09:56   0:00  \_ /usr/sbin/httpd.peruser
10014    27320  0.0  0.1 412884 28040 ?        S    10:07   0:00  \_ /usr/sbin/httpd.peruser
10000    27336  0.0  0.0 400124 14136 ?        S    10:08   0:00  \_ /usr/sbin/httpd.peruser
10014    27366  0.0  0.0 399456 11504 ?        S    10:09   0:00  \_ /usr/sbin/httpd.peruser
10014    27367  0.0  0.1 412852 27964 ?        S    10:09   0:00  \_ /usr/sbin/httpd.peruser
10008    27485  0.0  0.1 424332 39348 ?        S    10:14   0:00  \_ /usr/sbin/httpd.peruser

Pro založení virtualhosta je tedy třeba provést:

  • založit uživatele a skupinu v OS, uživateli dát shell rssh aby mohl nahrát data na web
  • vytvořit domácí adresář a nastavit správně oprávnění
  • vytvořit konfigurační soubor virtualhosta (každého vhosta dáváme do samostatného konf. souboru)

Pokud budete mít na serveru více virtualhostů, je vhodné si usnadnit jejich zakládání např. pomocí skriptu:

#!/bin/bash

ORIGDIR=$(pwd)
cd ${0%/*}

VHOSTDIR=/etc/httpd/vhosts.d/
VHOSTTEMPLATE=/etc/httpd/vhost.tpl

if [ -f "${0##*/}.conf" ]; then
  . "${0##*/}.conf"
fi

cd "$ORIGDIR"

usage() {
  cat >&2 <<EOF

Usage: ${0##*/} [switches] --domain domain.tld
  --help 			print help
  --domain domain.tld		domain

EOF
  [ $# -ge 1 ] && exit $1
}

params=$(
    getopt -n "${0##*/}" -o "" -l help,domain: -- "$@"
)
[ $? != 0 ] && usage 1 

eval set -- "$params"
unset params

while :
do
  case "$1" in
    --help) usage 0;;
    --domain) DOMAIN="${2}";;
    --) shift; break;;
  esac
  shift
done

for i in DOMAIN VHOSTDIR VHOSTTEMPLATE; do
  if [ -z "${!i}" ]; then
    echo "Hodnota $i neni definovana." >&2
    exit 1
  fi
done

if ! egrep -q -i '^([[:alnum:]]|-)+\.([[:alpha:]][[:alpha:]]+)$' <<< ${DOMAIN} ; then
  echo "Parametr --domain zrejme neobsahuje domenu 2. radu" >&2
  exit 1
fi

if find $VHOSTDIR -type f | xargs -- egrep -l "\ $DOMAIN\$" ; then
  echo "Virtualhost pro domenu $DOMAIN je jiz v systemu" >&2
  exit 1
fi

if getent passwd $DOMAIN > /dev/null; then
  echo "Uzivatel nebo skupina $DOMAIN jiz v systemu existuje, zalozte noveho virtualhosta rucne." >&2
  exit 1
else
  if ! useradd -c "Web $DOMAIN" -d "/home/web/$DOMAIN" -s /usr/bin/rssh -m -k /home/web/.skeleton -U "$DOMAIN"; then
    echo "Nepodarilo se zalozit uzivatele $DOMAIN:$DOMAIN, ktery je nutny pro beh webu." >&2
    echo "Virtualhost nebyl vytvoren." >&2
    exit 1
  fi
fi

if ! $(cat $VHOSTTEMPLATE | sed -e "s%__DOMAIN__%$DOMAIN%g" > $VHOSTDIR/$DOMAIN.conf); then
  userdel -r "$DOMAIN"
  echo "Pri vytvareni konfiguracniho souboru $VHOSTDIR/$DOMAIN.conf nastala chyba." >&2
  echo "Systemovy uzivatel $DOMAIN:$DOMAIN byl odstranen." >&2
  echo "Opravte chybu a zkuste vytvorit noveho virtualhosta." >&2
  exit 1
fi

if ! service httpd configtest 2>/dev/null; then
  echo "V konfiguraci apache je nekde chyba :-(" >&2
  service httpd configtest
  echo "Odstrante chybu a provedte reload konfigurace." >&2
  exit 1
else
  cat << __EOF__

==========================================
Virtualhost pro domenu $DOMAIN byl zalozen.

Web pobezi v systemu pod uzivatelem $DOMAIN:$DOMAIN
Domaci adresar uzivatele je v /var/www/$DOMAIN

Apache bude hledat data pro pristup na web v adresarich
/var/www/$DOMAIN/public_html pro domenu $DOMAIN (dom. 2. radu)
a v adresari /var/www/$DOMAIN/subdomains/XXX pro domeny XXX.$DOMAIN 

Uzivatel $DOMAIN ma do systemu prisup pres SSH pouze pro SCP/SFTP.
Plny pristup uzivatele do systemu je mozne povolit zmenou shellu na
/bin/bash prikazem "usermod -s /bin/bash $DOMAIN"

Odstraneni uzivatele, dat a vhosta ze systemu je mozne pomoci prikazu
"usermod -r $DOMAIN" a smazanim souboru /etc/httpd/vhosts.d/$DOMAIN.conf

Pro nasmerovani domeny na server pouzijte IP adresu `getent hosts neon| awk '{print $1}'`

==========================================
Provedte reload apache: "service httpd reload"
==========================================

__EOF__
  exit 0
fi

Šablona virtualhosta:

# cat /etc/httpd/vhost.tpl
<VirtualHost webserver:80>
  ServerName __DOMAIN__
  RewriteEngine On
  RewriteOptions Inherit
  DocumentRoot /var/www/__DOMAIN__/public_html
  <Directory /var/www/__DOMAIN__/public_html>
    AllowOverride All
  </Directory>
  Processor __DOMAIN__ __DOMAIN__
  ServerEnvironment __DOMAIN__ __DOMAIN__
  MaxProcessors 128
</VirtualHost>

<VirtualHost webserver:80>
  ServerName __DOMAIN__
  ServerAlias *.__DOMAIN__
  RewriteEngine On
  RewriteOptions Inherit
  DocumentRoot /var/www/__DOMAIN__
  VirtualDocumentRoot /var/www/__DOMAIN__/subdomains/%1
  <Directory /var/www/__DOMAIN__/subdomains/*>
    AllowOverride All
  </Directory>
  Processor __DOMAIN__ __DOMAIN__
  ServerEnvironment __DOMAIN__ __DOMAIN__
  MaxProcessors 128
</VirtualHost>

Použití skriptu je snadné, jako root stačí spustit „add_vhost.sh –domain domena.tld“ a skript vytvoří potřebnou konfiguraci.