Die Überschrift sagt es bereits -- es geht darum, einen Ubuntu-Server für den Einsatz als Web-/Emailserver auf einem bei Hetzner angemieteten Server zu installieren. Ich schreibe hier einfach mal in Stichworten mit, damit ich später nicht so viel Arbeit habe, wenn ich noch so einen Server installieren muss. Bei der Hardware handelt es sich um einen im August 2009 bei Hetzner angemieteten "Root Server EQ 4".
Vielleicht hilft es ja auch jemandem der hier mitliest -- aber eigentlich ist folgende Auflistung nur für mich selbst gedacht. Die Auflistung als Verschachtelte Liste, sollte mir genügen um so einen Server noch einmal installiert zu bekommen.
Inhalt
- Serverguide
- Paketquellen auf den neuesten Stand bringen und System upgraden
- Midnight Commander installieren
- screenrc anpassen
- rcconf installieren
- Passwort für "root" einstellen
- Neuen Benutzer zum Arbeiten anlegen
- Die Datei /etc/bash.bashrc anpassen
- Skripte-Ordner erstellen und zum Pfad hinzufügen
- findstring-Tool
- NICHT installieren
- MySQL-Server installieren
- phpMyAdmin installieren
- Netzwerk: Zusätzliche IP-Adressen einstellen
- Webmin installieren
- Zeitsynchronisation (NTP) installieren und konfigurieren
- unattended-upgrades installieren
- apticron installieren
- Nagios (Serverüberwachung) installieren und konfigurieren
- SMART installieren
- jnettop und iftop installieren
- Emailsystem mit Postfix und Cyrus
- Spamassassin
- Backup
- Erweiterung: PostgreSQL-Backup
- Ordnerstruktur für Home-Ordner nach /etc/skel
- Apache konfigurieren
- Apache weniger Informationen
- ProFTP installieren
- Logrotate
- mod_wsgi installieren
- CherryPy und Cheetah installieren
- Webalizer installieren
- Awstats installieren
- Horde Groupware Webmail Edition
- Squirrelmail installieren und konfigurieren
- Interessante Ideen
- Weitere ToDo's
Serverguide
Paketquellen auf den neuesten Stand bringen und System upgraden
aptitude update aptitude full-upgrade
Midnight Commander installieren
aptitude install mc
konfigurieren nicht vergessen
screenrc anpassen
Beispiel: screenrc
cd /etc mv screenrc screenrc_original wget http://halvar.at/krimskrams3/linux/screenrc
Meine screenrc habe ich mir von Gentoo geliehen und ein wenig angepasst.
rcconf installieren
aptitude install rcconf
Damit kann man auf einfache Weise einstellen, welche Daemons beim Start des Systems gestartet werden sollen.
Passwort für "root" einstellen
passwd
Neuen Benutzer zum Arbeiten anlegen
adduser <Benutzername>
sudoers bearbeiten:
root<-->ALL=(ALL) ALL %sudo ALL=NOPASSWD: ALL
Neuen Benutzer zur Gruppe "sudo" hinzufügen:
usermod --groups sudo --append <neuer Benutzername>
Die Datei /etc/bash.bashrc anpassen
rm, cp und mv etwas entschärfen:
alias rm='rm -i' alias cp='cp -i' alias mv='mv -i'
Ich will, dass sich dir genau so verhält:
alias dir='ls -al --color --group-directories-first'
"bash completion" aktivieren. Ich weiß zwar bis heute nicht was das bringt, aber folgende Zeilen sind dafür zuständig:
if [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
Skripte-Ordner erstellen und zum Pfad hinzufügen
mkdir /scripts cd /etc/profile.d touch scriptpath.sh mcedit scriptpath.sh
#!/bin/sh PATH=$PATH:/scripts export PATH
findstring-Tool
cd /scripts touch findstring mcedit findstring
#!/bin/sh
#
# Sucht nach Dateien in denen der Suchstring vorkommt
#
find -type f -exec grep -iq "${1}" {} \; -print
chmod +x findstring
NICHT installieren
..., da später die aktuelleste Version händisch installiert wird:
- cherrypy
- mod_wsgi
- cheetahtemplate
MySQL-Server installieren
aptitude install mysql-server mysql-client
Nach der Installation wird nach dem MySQL-"root"-Passwort gefragt. Das ist nicht das Passwort für den Unix-Benutzer, sondern für den MySQL-Benutzer root@localhost.
Auf UTF-8 umstellen
/etc/mysql/my.cnf:
[mysqld]:
collation_server = utf8_unicode_ci character_set_server = utf8
phpMyAdmin installieren
aptitude install phpmyadmin
Während der Installation muss das MySQL-"root"-Passwort und ein neues MySQL Anwendungspasswort für phpMyAdmin angegeben werden.
Netzwerk: Zusätzliche IP-Adressen einstellen
Früher hatte ich das immer direkt in der Datei /etc/network/interfaces mit eth0:1 usw. erledigt. Aber diesmal nimmt der Computer die zusätzlichen IP-Adressen immer erst nach einem Neustart des Netzwerkes (/etc/init.d/network restart) an. Das ist natürlich nicht tragbar. Deshalb habe ich mich dafür entschieden, die zustätzlichen IP-Adressen mit ifconfig ... add ... zu setzen. Und damit dieser Befehl auch immer zum richtigen Zeitpunkt ausgeführt wird, habe ich diesen im Ordner /etc/network/if-up.d in eine neue Datei gelegt.
Neue Datei im Ordner /etc/network/if-up.d erstellen:
cd /etc/network/if-up.d touch additional-addresses chmod +x additional-addresses
/etc/network/if-up.d/additional-addresses:
#! /bin/bash PATH=/sbin:/bin ifconfig eth0 add <neue IP-Adresse> ifconfig eth0 add <neue IP-Adresse> ifconfig eth0 add <neue IP-Adresse>
Webmin installieren
Installationsdatei (deb-Paket) herunterladen
Abhängigkeiten installieren:
aptitude install libnet-ssleay-perl libauthen-pam-perl \ libauthen-pam-perl libio-pty-perl libio-pty-perl libmd5-perl \ libmd5-perl
Webmin selbst kann dann mit dpkg installiert werden:
dpkg -i webmin_x.xxx_all.deb
Webmin über den Browser konfigurieren
Thema einstellen
Sprache einstellen
Unnötige Module löschen:
z.B: ADSL-Client, CD-Brenner, Druckerverwaltung, Exim Mailserver, Heartbeat-Monitor, LILO - Boot-Konfiguration, QMail Mailserver, Sendmail Mailserver, WU-FTP FTP-Server, NIS-Client und -Server, Systemzeit, Volume-Management (LVM)
Das Systemzeit-Modul wird auch entfert, da ich das lieber direkt von Ubuntu erledigen lassen möchte. Webmin soll hier nicht rein pfuschen. Siehe weiter unten: "Zeitsynchronisation"
Zeitsynchronisation (NTP) installieren und konfigurieren
http://doc.ubuntu.com/ubuntu/serverguide/C/NTP.html
aptitude install ntp
Zeitserver in deiner Nähe sind unter http://www.pool.ntp.org/ zu finden.
Die zu verwendenden Zeitserver werden in der Datei /etc/ntp.conf eingestellt:
server de.pool.ntp.org server at.pool.ntp.org server ch.pool.ntp.org
Das Skript /etc/network/if-up.d/ntpdate wird immer dann ausgeführt, wenn das Netzwerk aktiviert wird. Das heißt, dass schon in der Standard- Einstellung des Ubuntu-Servers bei jedem Start des Servers die Uhrzeit eingestellt wird. Das hier genannte Skript ruft den Befehl ntpdate-debian auf. Die Einstellungen für diesen Befehl befinden sich in der Datei /etc/default/ntpdate.
Der Daemon ntpd ist dazu da, die Systemzeit im Hintergrund ständig in ganz kleinen Schritten an die reale Zeit anzupassen.
unattended-upgrades installieren
aptitude install unattended-upgrades
Nachdem der Emailserver installiert wurde, muss die Datei /etc/apt/apt.conf.d/50unattended-upgrades angepasst werden, dass Emails bei Störung an den Admin geschickt werden.
apticron installieren
aptitude install apticron
apticron will configure a cron job to email an administrator information about any packages on the system that need updated as well as a summary of changes in each package.
http://doc.ubuntu.com/ubuntu/serverguide/C/automatic-updates.html
Nagios (Serverüberwachung) installieren und konfigurieren
aptitude install nagios3
Die Einstellungen befinden sich unter /etc/nagios3
Passwortdatei für den Zugriff auf die Nagios-Seite erstellen:
htpasswd -c /etc/nagios3/htpasswd.users <Benutzername>
Evt. muss man Nagios und den Apachen neu starten:
/etc/init.d/nagios3 restart /etc/init.d/apache2 restart
Die Nagios-Seite ist nun unter http://<Domäne>/nagios3 erreichbar
SMART installieren
Festplattenüberwachung
aptitude install smartmontools
Die Daten können mit dem Kommandozeilenprogramm smartctl oder über Webmin ausgelesen werden.
jnettop und iftop installieren
Beides sind Überwachungsprogramme um feststellen zu können, wieviel so an Daten über die Netzwerkkarten übertragen werden.
aptitude install jnettop iftop
Emailsystem mit Postfix und Cyrus
Das Emailsystem ist so geplant: Postfix empfängt die Email und legt diese in die eigene Queue. Dann wird die Email an Spamassassin übergeben. Dabei werden noch keine Zuordnungen zu irgendwelchen Emailboxen gemacht. Der Header wird nicht verändert. Spamassassin scannt die Email, schreibt den Spam-Level in den Emailheader und gibt die Email wieder an Postfix zurück. Jetzt legt Postfix fest, wohin die Email ausgeliefert werden soll. Postfix übergibt die Email an Cyrus. Cyrus übernimmt die Email und ordnet sie in das zuständige Postfach ein. Ist eine Sieve-Regel definiert, dann ist die dafür zuständig, das die Email evt. in einen speziellen Ordner wie z.B. den Spam-Ordner des Benutzers verschoben wird.
"saslauthd" wird nicht als Daemon benötigt. Es wird direkt auf die SASL-Datenbank zugegriffen.
Hinweis
Zuerst wird ein funktionierender Verbund aus Postfix und Cyrus eingerichtet. Erst wenn diese Kombination getestet wurde und funktioniert, wird Spamassassin als Filter aktiviert. Wie man Spamassassin aktiviert, wird weiter unten erklärt.
Postfix, Cyrus und SASL installieren und konfigurieren
aptitude install postfix postfix-doc aptitude install sasl2-bin aptitude install cyrus-imapd-2.2 aptitude install cyrus-pop3d-2.2 aptitude install cyrus-admin-2.2
Erklärungen zu den SASL-Postfix-Einstellungen sind unter http://www.postfix.org/SASL_README.html zu finden.
/etc/cyrus.conf:
imap cmd="imapd -U 30" listen="imap" prefork=0 maxchild=100 pop3 cmd="pop3d -U 30" listen="pop3" prefork=0 maxchild=50 #nntp cmd="nntpd... (wird nicht benötigt) lmtpunix cmd="lmtpd" listen="/var/run/cyrus/socket/lmtp" prefork=0 maxchild=20
/etc/imapd.conf:
altnamespace: yes admins: cyrus sieveusehomedir: false allowplaintext: yes sasl_pwcheck_method: auxprop lmtpsocket: /var/run/cyrus/socket/lmtp
altnamespace: yes kümmert sich darum, dass die IMAP-Ordner nicht unterhalb des INBOX-Ordners sind. Ich empfinde das im Thunderbird als angenehmer. Aber das ist reine Geschmackssache.
/etc/postfix/master.cf:
Man kann zum Debuggen "-v" als Parameter an "smtpd" anhängen. Das sollte man aber wirklich nur zum Debuggen verwenden. Mit tail -f /var/log/syslog kann man mitverfolgen, was der Server so tut, wenn man vesucht, darüber ein Email zu verschicken.
debuggen:
smtp inet n - - - - smtpd -v
normal:
smtp inet n - - - - smtpd
/etc/postfix/main.cf:
smtpd_sasl_auth_enable = yes smtpd_sasl_local_domain = <SASL-Domäne> smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination broken_sasl_auth_clients = yes virtual_alias_domains = <Domänen die angenommen werden sollen> virtual_alias_maps = hash:/etc/postfix/virtual mailbox_transport = lmtp:unix:/var/run/cyrus/socket/lmtp
Mit smtpd_sasl_local_domain wird eingestellt, welche Domäne von SASL beim Durchsuchen der SASL-Datenbank verwendet wird. Diese Domäne ist (glaube ich) der Hostname des Servers. Den findet man mit cat /etc/hostname heraus. Ansonsten, wenn man schon einen Benutzer in die SASL-Datenbank (mit saslpasswd2 -c <Benutzername>) geschrieben hat, dann kann man mit sasldblistusers2 herausfinden, welches die Standarddomäne für SASL ist. Gibt man diese Einstellung nicht oder falsch an, dann bekommt man so nette Debugmeldungen von Postfix wie z.B. "...no secret in database...". Nicht lachen, das hat mich mindestens vier Stunden gekostet, bis ich das heraus fand.
Datei-Zugriffsrechte für Postfix einstellen
Postfix erlauben, auf den LMTP-Socket und die SASL-DB zuzugreifen:
adduser postfix mail adduser postfix sasl
Hardlink für Postfix (chroot) zur SASL-DB erstellen:
ln /etc/sasldb2 /var/spool/postfix/etc/sasldb2
Postfix und Cyrus neu starten
/etc/init.d/postfix restart /etc/init.d/cyrus2.2 restart
Admin-Benutzer für Cyrus erstellen
saslpasswd2 -c cyrus
sicheres Passwort für den Benutzer vergeben und merken
Mit sasldblistusers2 kann man prüfen ob der Benutzer erfolgreich erstellt wurde und welcher Domäne er zugewiesen wurde. Diese Domäne muss in /etc/postfix/main.cf als Einstellung smtpd_sasl_local_domain gesetzt werden, falls das noch nicht passiert ist.
Test-Emailaccount erstellen und ausprobieren
Zum Testen habe ich mir die Subdomain "test.halvar.at" erstellt und auf die primäre IP-Adresse des Servers zeigen lassen. Auch der MX-Eintrag für "test.halvar.at" zeigt auf diese Adresse.
Die neue Domäne muss in /etc/postfix/main.cf eingetragen werden:
virtual_alias_domains = test.halvar.at
Damit wird der Benutzer in der SASL-DB erstellt:
saslpasswd2 -c testertest
Das Passwort wird interaktiv abgefragt.
Weiter geht's mit dem Erstellen des Postfaches:
cyradm --user cyrus localhost localhost> cm user.testertest localhost> setacl user.testertest testertest all (optional, siehe Hinweis weiter unten) localhost> quit
Mit setacl werden die Zugriffsrechte des Benutzers auf das Postfach eingestellt. Statt "all" kann man die Berechtigungen auch detaillierter angeben:
- l: Lookup (visible to LIST/LSUB/UNSEEN)
- r: Read (SELECT, CHECK, FETCH, PARTIAL, SEARCH, COPY source)
- s: Seen (STORE SEEN)
- w: Write flags other than SEEN and DELETED
- i: Insert (APPEND, COPY destination)
- p: Post (send mail to mailbox)
- c: Create and Delete mailbox (CREATE new sub-mailboxes, RENAME or DELETE mailbox)
- d: Delete (STORE DELETED, EXPUNGE)
- a: Administer (SETACL)
Hinweis
Das habe ich erst später gemerkt: setacl user.testertest... ist nicht notwendig, da dem Benutzer testertest automatisch alle Berechtigungen zugewiesen werden.
Jetzt muss man Postfix noch mitteilen, dass Emails an tester@test.halvar.at an das Postfach testertest übergeben werden sollen. Das kann man im Webmin mit "Postfix/Virtuelle Domänen" erledigen. Siehe:

Das erzeugt in der Datei /etc/postfix/virtual folgenden Eintrag:
tester@test.halvar.at testertest
Man kann das jetzt weiter spinnen, indem man z.B. auch für "root" einen Eintrag erstellt und diesen über die /etc/aliases zu diesem Postfach leitet.
/etc/postfix/virtual:
root@test.halvar.at testertest
/etc/aliases:
root: root@test.halvar.at
Spamassassin
Spamassassin wird als Filter für Postfix aktiviert. Dazu werden die Emails, die über SMTP (inet) hereinkommen, an den Spamassassin-Client (spamc) übergeben. spamc parst die Email (die Arbeit macht spamd) und schreibt den Spam-Status in den Header. Dann sendet spamc die Email (mit sendmail) wieder an Postfix zurück. Da Postfix die lokalen Emails nicht filtert, wird das Email von Postfix direkt an Cyrus übergeben.
aptitude install spamassassin re2c libc6-dev gcc make
Lesestoff
- http://spamassassin.apache.org/
- http://wiki.mobbing-gegner.de/Linux/SpamAssassin/Links (deutsche Links)
- http://wiki.debianforum.de/PostfixSpamassassinCyrus
- http://wiki.apache.org/spamassassin/UsingSpamAssassin
- http://wiki.apache.org/spamassassin/ThirdPartySoftware
- http://www.oreilly.de/german/freebooks/spamvirger/ (deutsches Buch)
- http://wiki.apache.org/spamassassin/IntegratedInPostfixWithAmavis
Spamassassin-Server aktivieren und konfigurieren
Spamassassin läuft zwar auch als einfaches Kommandozeilenprogramm, aber schneller geht's als Server (spamd).
/etc/default/spamassassin:
ENABLED=1 CRON=1
/etc/spamassassin/local.cf:
report_safe 0
Spamassassin-Benutzer erstellen
Mit diesem Befehl wird ein Benutzer erstellt, der sich nicht einloggen kann, da ein "!" als Passwort eingestellt wird.
adduser spamassassin
Spamassassin speichert Einstellungen im Home-Ordner dieses Benutzers und das Programm spamc wird in dessen Kontext ausgefürt.
Spamassassin in Postfix integrieren
/etc/postfix/master.cf:
smtp inet n - - - - smtpd
-o content_filter=spamassassin
spamassassin unix - n n - - pipe
user=spamassassin
null_sender=
argv=/usr/bin/spamc -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
Spam automatisch in einen eigenen IMAP-Ordner verschieben
Zuerst muss ein entsprechender IMAP-Ordner für den Benutzer erstellt werden.
cyradm --user cyrus localhost localhost> cm user.testertest.Spam localhost> quit
Dann muss man eine Textdatei mit der Sieve-Regel erstellen. Diese wird dann mit dem Programm sievehell in den Sieve-Ordner des Benutzers kopiert und aktiviert.
mkdir /etc/sieve_templates touch /etc/sieve_templates/spam
/etc/sieve_templates/spam:
require "fileinto";
if header :contains "X-Spam-Level" "******" {
fileinto "Spam";
stop;
}
Mehr Informationen über Sieve-Regeln bekommst du hier:
- http://www.ietf.org/rfc/rfc3028.txt
- http://cyrusimap.web.cmu.edu/twiki/bin/view/Cyrus/SpecificationsAndStandards#sieve.txt
Mit dem Programm sieveshell kopiert man nun die Vorlage in den Sieve-Ordner des Benutzers:
sieveshell --user=testertest --authname=cyrus localhost
Man wird nach dem Passwort für den Cyrus-Benutzer gefragt.
> put /etc/sieve_templates/spam > activate spam > quit
Das Programm sieveshell kann auch mit einem Skript als Parameter aufgerufen werden. Siehe man sieveshell.
Backup
Ziel ist es, zuerst einmal alle wichtigen Daten eine Woche lang auf Lager zu halten. Falls mal eine Datei gelöscht wird, kann man diese bis zu einer Woche rückwirkend wieder herstellen.
Zweites Ziel ist es, eine Notfallsicherung auf dem Hetzner-Backup-Server zu halten, damit ein totaler Systemausfall (z.B. Festplattencrash oder Controllerfehler) nicht den Totalverlust aller Daten bedeutet.
Die zu sichernden Ordner sind (diesesmal):
- etc
- home
- root
- scripts
- var/log
- var/spool
Gesichert wird in den /backup-Ordner. Zum Sichern wird tar eingesetzt. Es soll einstellbar sein, wie lange rückwirkend gesichert wird.
Zum Verschlüsseln der Sicherungen, bevor diese zum FTP-Server übertragen werden, dient CCrypt:
aptitude install ccrypt
Programm: copy_to_ftp.py
Dieses kleine Programm kopiert die letzten Sicherungen zum Backup-FTP-Server von Hetzner. Das Programm ist einfach aufgebaut. Man muss nur ein paar Konstanten anpassen und die Passwörter für den FTP-Zugang und zum Verschlüsseln der Sicherungen in zwei Textdateien hinterlegen.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import ftplib
from cStringIO import StringIO
import subprocess
import tempfile
FTP_HOST = "<IP-Adresse des FTP-Backup-Servers>"
FTP_USER = "<Benutzername fuer den FTP-Backup-Server>"
FTP_PASS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ftppasswd")
FTP_PASS = file(FTP_PASS_FILE, "r").readline().strip()
CCRYPT_PASS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ccryptpasswd")
PLACEHOLDER = "_placeholder"
CCRYPT = "/usr/bin/ccrypt"
MYSQL_SOURCE_DIR = "/backup/mysql"
MYSQL_SOURCE_CURRENT_FILE = "/backup/mysql/.current"
MYSQL_DEST_DIR = "mysql"
MYSQL_DEST_CURRENT_FILE = "current"
MYSQL_DEST_MAX_BACKUPS = 10
FILES_SOURCE_DIR = "/backup/files"
FILES_SOURCE_CURRENT_FILE = "/backup/files/.current"
FILES_DEST_DIR = "files"
FILES_DEST_CURRENT_FILE = "current"
FILES_DEST_MAX_BACKUPS = 2
def copy_to_ftp(
source_dir, source_current_file, dest_dir, dest_current_file, dest_max_backups
):
# Verbinden
ftp = ftplib.FTP(FTP_HOST, FTP_USER, FTP_PASS)
# Platzhalter-Datei im Root-Ordner erstellen/ueberscheiben
ftp.storbinary("STOR %s" % os.path.join("/", PLACEHOLDER), StringIO())
# Basisordner erstellen
if (
os.path.join("/", dest_dir) not in
(os.path.join("/", item) for item in ftp.nlst("/"))
):
ftp.mkd(dest_dir)
# Platzhalter-Datei im Basis-Ordner erstellen/ueberscheiben
ftp.storbinary(
"STOR %s" % os.path.join("/", dest_dir, PLACEHOLDER),
StringIO()
)
# QUELLE Current-Datei auslesen
source_current = int(file(source_current_file, "r").readline().strip())
# ZIEL Current-Datei auslesen
dest_current_file_path = os.path.join("/", dest_dir, dest_current_file)
if dest_current_file_path in ftp.nlst(os.path.join("/", dest_dir)):
current_file = StringIO()
ftp.retrbinary("RETR %s" % dest_current_file_path, current_file.write)
current_file.seek(0)
try:
dest_current = int(current_file.readline().strip()) + 1
except ValueError:
dest_current = 1
else:
dest_current = 1
if dest_current > dest_max_backups:
dest_current = 1
# Pfade herausfinden
full_source_dir = os.path.join(source_dir, str(source_current))
full_dest_dir = os.path.join("/", dest_dir, str(dest_current))
# Zielordner löschen
if full_dest_dir in ftp.nlst(os.path.join("/", dest_dir)):
for full_filename in ftp.nlst(full_dest_dir):
ftp.delete(full_filename)
ftp.rmd(full_dest_dir)
# Zielordner und Platzhalter-Datei erstellen
ftp.mkd(full_dest_dir)
ftp.storbinary(
"STOR %s" % os.path.join(full_dest_dir, PLACEHOLDER),
StringIO()
)
# Dateien des Quellordner durchlaufen
for filename in os.listdir(full_source_dir):
# Verbindung schliessen
try:
ftp.quit()
ftp.close()
except: pass
# Pfade
full_source_filename = os.path.join(full_source_dir, filename)
full_dest_filename = os.path.join(full_dest_dir, filename + ".cpt")
print "Copy to FTP:", full_source_filename
# Datei verschluesseln
tmp_file = tempfile.TemporaryFile()
args = [CCRYPT, "--encrypt", '--keyfile=%s' % CCRYPT_PASS_FILE]
proc = subprocess.Popen(
args, stdout = tmp_file, stdin = file(full_source_filename, "rb"),
stderr = subprocess.PIPE
)
(stdout_str, stderr_str) = proc.communicate()
if stderr_str:
for line in stderr_str.splitlines():
print " ", line.rstrip()
# Verbindung neu oeffnen
ftp = ftplib.FTP(FTP_HOST, FTP_USER, FTP_PASS)
# Datei in den Zielordner kopieren
tmp_file.seek(0)
ftp.storbinary("STOR %s" % full_dest_filename, tmp_file)
tmp_file.close()
# Ziel Current-Datei erstellen/ueberschreiben
current_file = StringIO()
current_file.write(str(dest_current))
current_file.seek(0)
ftp.storbinary("STOR %s" % dest_current_file_path, current_file)
# Platzhalter-Dateien entfernen
try:
ftp.delete(os.path.join(full_dest_dir, PLACEHOLDER))
except ftplib.error_perm:
pass
try:
ftp.delete(os.path.join(dest_dir, PLACEHOLDER))
except ftplib.error_perm:
pass
try:
ftp.delete(os.path.join("/", PLACEHOLDER))
except ftplib.error_perm:
pass
# Fertig
try:
ftp.quit()
ftp.close()
except: pass
def copy_mysql():
copy_to_ftp(
MYSQL_SOURCE_DIR, MYSQL_SOURCE_CURRENT_FILE, MYSQL_DEST_DIR,
MYSQL_DEST_CURRENT_FILE, MYSQL_DEST_MAX_BACKUPS
)
def copy_files():
copy_to_ftp(
FILES_SOURCE_DIR, FILES_SOURCE_CURRENT_FILE, FILES_DEST_DIR,
FILES_DEST_CURRENT_FILE, FILES_DEST_MAX_BACKUPS
)
def main():
# Letzte MYSQL-Sicherung zum FTP-Server kopieren
copy_mysql()
# Letzte FILES-Sicherung zum FTP-Server kopieren
copy_files()
if __name__ == "__main__":
main()
Konstante: FTP_HOST
Hier trägt man die IP-Adresse des Backup-FTP-Servers von Hetzner ein.
Konstante: FTP_USER
Hier trägt man den Benutzernamen fuer den Backup-FTP-Server von Hetzner ein.
Datei: ftppasswd
In dieser Datei befindet sich das Passwort für den FTP-Zugang zum Backup-Server von Hetzner. Diese Datei sollte sich im selben Ordner befinden wie das copy_to_ftp.py-Programm.
Diese Datei darf nur für "root" lesbar sein:
chown root:root ftppasswd chmod 600 ftppasswd
Datei: ccryptpasswd
In dieser Datei befindet sich das Passwort zum Verschlüsseln der Sicherungsdateien. Diese Datei sollte sich im selben Ordner befinden wie das copy_to_ftp.py-Programm.
Diese Datei darf nur für "root" lesbar sein:
chown root:root ccryptpasswd chmod 600 ccryptpasswd
Programm: backup_mysql.py
Dieses Programm liest aus, welche Datenbanken es gibt und sichert jede Datenbank in eine eigene Dump-Datei (SQL). Die Sicherungen werden mit gzip gepackt. Nach den mit MAX_BACKUPS eingestellten Sicherungen wird die älteste Sicherung überschrieben.
#!/usr/bin/env python
# coding: utf-8
import os
import sys
import subprocess
import shutil
import stat
MAX_BACKUPS = 50
BACKUP_DIR = "/backup/mysql"
CURRENT_FILE = "/backup/mysql/.current"
MYSQL_ROOTPW_FILE = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "mysqlrootpasswd"
)
MYSQL = "/usr/bin/mysql"
MYSQLDUMP = "/usr/bin/mysqldump"
GZIP = "/bin/gzip"
def main():
# MySQL-Root-Passwort auslesen
password = file(MYSQL_ROOTPW_FILE, "r").readline().strip()
# Current-Datei auslesen
if os.path.isfile(CURRENT_FILE):
try:
current = int(file(CURRENT_FILE, "r").readline().strip()) + 1
except ValueError:
current = 1
else:
current = 1
if current > MAX_BACKUPS:
current = 1
# Pfad für Sicherung
dest_dir = os.path.join(BACKUP_DIR, str(current))
if os.path.isdir(dest_dir):
shutil.rmtree(dest_dir, ignore_errors = True)
os.makedirs(dest_dir)
os.chmod(BACKUP_DIR, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
os.chmod(dest_dir, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
args = [MYSQL, "--user=root", "--password=%s" % password]
proc = subprocess.Popen(args, stdin = subprocess.PIPE, stdout = subprocess.PIPE)
proc.stdin.write("SHOW DATABASES;")
proc.stdin.close()
proc.stdout.readline()
for line in proc.stdout:
dbname = line.strip()
print "Backup:", dbname
# Dateiname zusammensetzen
sql_file_name = os.path.join(dest_dir, dbname + ".sql")
# Sichern
cmd = MYSQLDUMP + ' --user="root" --password="%s" %s > %s'
cmd = cmd % (password, dbname, sql_file_name)
os.system(cmd)
# Zippen
cmd = GZIP + " %s" % sql_file_name
os.system(cmd)
# Current-Datei neu schreiben
f = file(CURRENT_FILE, "w")
f.write(str(current))
f.close()
if __name__ == "__main__":
main()
Datei: mysqlrootpasswd
In dieser Datei befindet sich das Passwort des MySQL-Root-Benutzers. Diese Datei sollte sich im selben Ordner befinden wie das backup_mysql.py-Programm.
Diese Datei darf nur für "root" lesbar sein:
chown root:root mysqlrootpasswd chmod 600 mysqlrootpasswd
Programm: backup_files.py
Dieses Programm sichert alle Ordner, die in der Konstante SOURCE_PATHS angegeben werden, in den Zielordner (BACKUP_DIR). Nach den mit MAX_BACKUPS eingestellten Sicherungen wird die älteste Sicherung überschrieben.
Zum Sichern wird tar verwendet.
#!/usr/bin/env python
# coding: utf-8
import os
import sys
import subprocess
import shutil
import stat
TAR = "/bin/tar"
MAX_BACKUPS = 7
BACKUP_DIR = "/backup/files"
CURRENT_FILE = "/backup/files/.current"
SOURCE_PATHS = [
"/etc",
"/home",
"/root",
"/scripts",
"/var/log",
"/var/spool",
]
def main():
# Current-Datei auslesen
if os.path.isfile(CURRENT_FILE):
try:
current = int(file(CURRENT_FILE, "r").readline().strip()) + 1
except ValueError:
current = 1
else:
current = 1
if current > MAX_BACKUPS:
current = 1
# Pfad für Sicherung
dest_dir = os.path.join(BACKUP_DIR, str(current))
if os.path.isdir(dest_dir):
shutil.rmtree(dest_dir, ignore_errors = True)
os.makedirs(dest_dir)
os.chmod(BACKUP_DIR, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
os.chmod(dest_dir, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
# Ordner sichern
for path in SOURCE_PATHS:
print "Backup:", path
# Dateiname zusammensetzen
file_name = os.path.join(
dest_dir, path.replace(os.sep, "_")[1:] + ".tar.gz"
)
# Sichern
args = [TAR, "--create", "--file=%s" % file_name, "--gzip", path]
proc = subprocess.Popen(
args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT
)
for line in proc.stdout:
if not (
"Removing leading" in line or
"socket ignored" in line
):
print " ", line.rstrip()
# Current-Datei neu schreiben
f = file(CURRENT_FILE, "w")
f.write(str(current))
f.close()
if __name__ == "__main__":
main()
Tägliche Sicherung aller Dateien inkl. Datenbanken
Diese Sicherung sollte, auf Grund der doch recht massiven Arbeit, die beim Sichern vom Server zu verrichten ist, nur einmal am Tag durchgeführt werden. Am Besten dann, wenn der Server sowiso kaum ausgelastet ist.
Zuerst müssen die Dateien gesichert und dann zum SQL-Server übertragen werden. Danach werden die Datenbanken gesichert und ebenfalls zum SQL-Server übertragen. Ich habe dafür ein kleines Skript geschrieben, welches von Cron täglich in der Nacht ausgeführt wird.
Programm: backup_full_daily.py
#!/usr/bin/env python
# coding: utf-8
import backup_files
import backup_mysql
import copy_to_ftp
def main():
# Dateien sichern und zum FTP-Server übertragen
backup_files.main()
copy_to_ftp.copy_files()
# MySQL-Datenbanken sichern und zum FTP-Server übertragen
backup_mysql.main()
copy_to_ftp.copy_mysql()
if __name__ == "__main__":
main()
/etc/crontab
SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root ... # Taegliches Backup 50 1 * * * root /scripts/backup_full_daily.py # Vereinzelte MySQL-Backups 43 10 * * * root /scripts/backup_mysql.py 43 16 * * * root /scripts/backup_mysql.py
Info:
man 5 crontab
Erweiterung: PostgreSQL-Backup
Backup-Benutzer erstellen
Dazu muss man zuerst von "root" zum "postgres"-Benutzer wechseln:
su - postgres
Als "postgres"-Benutzer kann man sich jetzt an die DB anmelden:
psql localhost
Im psql-Programm kann man nun mit folgenden Befehlen einen Backup-Benutzer erstellen und das Passwort vergeben:
CREATE USER backupuser WITH SUPERUSER; \password backupuser
Man wird nun nach dem Passwort des backupuser-Benutzers gefragt.
Passwortdatei
Man kann an die im Backup-Programm benötigten Kommandozeilenprogramme psql und pg_dump kein Passwort direkt als Parameter übergeben (was auch gut ist). Stattdessen kann man mit Hilfe der Umgebungsvariable PGPASSFILE den Pfad zu einer Textdatei übergeben, die das Passwort enthält.
Die Textdatei /scripts/pgpassfile muss folgende Struktur aufweisen:
hostname:port:database:username:password
Das sieht bei mir z.B. so aus:
localhost:*:*:backupuser:DasPasswort
Dann sollte man sich noch darum kümmern, dass niemand außer root auf die Datei zugreifen kann:
cd /scripts chown root:root pgpassfile chmod 600 pgpassfile
Das Programm /scripts/backup_postgresql.py:
#!/usr/bin/env python
# coding: utf-8
import os
import sys
import subprocess
import shutil
import stat
MAX_BACKUPS = 50
BACKUP_DIR = "/backup/postgresql"
CURRENT_FILE = "/backup/postgresql/.current"
BACKUP_USER = "backupuser"
PGPASSFILE = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "pgpassfile"
)
PSQL = "/usr/bin/psql"
PG_DUMP = "/usr/bin/pg_dump"
GZIP = "/bin/gzip"
def main():
# Umgebungsvariable PGPASSFILE
os.environ["PGPASSFILE"] = PGPASSFILE
# Current-Datei auslesen
if os.path.isfile(CURRENT_FILE):
try:
current = int(file(CURRENT_FILE, "r").readline().strip()) + 1
except ValueError:
current = 1
else:
current = 1
if current > MAX_BACKUPS:
current = 1
# Pfad für Sicherung
dest_dir = os.path.join(BACKUP_DIR, str(current))
if os.path.isdir(dest_dir):
shutil.rmtree(dest_dir, ignore_errors = True)
os.makedirs(dest_dir)
os.chmod(BACKUP_DIR, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
os.chmod(dest_dir, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
args_db = [
PSQL, "--username=%s" % BACKUP_USER, "--dbname=postgres", "--tuples-only",
"--command=SELECT datname FROM pg_database WHERE (datname NOT LIKE 'template_');"
]
proc_db = subprocess.Popen(args_db, stdout = subprocess.PIPE)
for line in proc_db.stdout:
dbname = line.strip()
if not dbname:
continue
print "Backup:", dbname
# Dateiname zusammensetzen
sql_file_name = os.path.join(dest_dir, dbname + ".sql")
# Sichern
args_dump = [
PG_DUMP, "--encoding=utf-8", "--no-owner", "--username=%s" % BACKUP_USER,
"--format=plain", "--file=%s" % sql_file_name, dbname
]
proc_dump = subprocess.Popen(args_dump)
proc_dump.communicate()
# Zippen
cmd = GZIP + " %s" % sql_file_name
os.system(cmd)
# Current-Datei neu schreiben
f = file(CURRENT_FILE, "w")
f.write(str(current))
f.close()
if __name__ == "__main__":
main()
Ordnerstruktur für Home-Ordner nach /etc/skel
Beim Erstellen eines Unix-Benutzers wird für den zugehörigen Home-Ordner eine Kopie des Ordners /etc/skel gemacht. Alle Ordner und Dateien, die bei fast allen Benutzern gleich sind, kann man dort erstellen. Das erleichtert die Arbeit ein wenig.
Apache konfigurieren
Es gibt normale "virtuelle Domänen" und einige deren Datenübertragung mit SSL geschützt werden muss (z.B. Shops). Darum kümmere ich mich später. Dann gibt es noch den Sonderfall "meine eigene Homepage". Die läuft mit CherryPy (http://cherrypy.org/) und soll per mod_wsgi (http://code.google.com/p/modwsgi/) in den Apachen eingebunden werden. Später kommt vielleicht noch Zope hinzu, welches per mod_proxy hinter dem Apachen werkeln soll.
Mit der Installation von phpMyAdmin wurde bereits PHP installiert. PHP ist also kein Thema mehr. Es gibt vielleicht noch ein paar kleine Anpassungen in der INI-Datei oder in den Einstellungen der virtuellen Domänen. Aber ich rechne hier nicht mit großen Schwierigkeiten.
Die Einstellungen des Apachen befinden sich im Ordner /etc/apache2.
Im Ordner /etc/apache2/conf.d/ sind Apache-Konfigurationen, die von Programmen beim Installieren abgelegt werden. phpMyAdmin oder auch nagios haben sich über diesen Ordner in den Apachen eingeklinkt. Alle Dateien, dieses Ordners werden an die Datei /etc/apache2/apache2.conf angehängt -- sind also eine Ergänzung der Apache-Konfigurationsdatei.
Die Datei /etc/apache2/apache2.conf ist die Haupt-Konfigurationsdatei des Apachen.
Apache-Module aktivieren
Im Ordner mods-available sind die Konfigurationen und Ladeanweisungen für die installierten Apache-Module abgelegt. Möchte man ein Modul aktivieren, dann verlinkt man die zum gewünschten Modul gehörenden Dateien in den mods-enabled-Ordner. Beim Verlinken sollte man absolute Pfade verwenden.
Ich finde es einfacher ln -s zu verwenden als immer wieder nach dem dafür vorgesehenen Apache-Programm zu suchen. Ja, das gibt es. Es heißt -- warte, ich muss mal nachsehen -- a2enmod. :-)
IP-Adresse(n) und Port(s) des Apache-Servers einstellen
Dafür ist die Datei /etc/apache2/ports.conf zuständig. Hier wird eingestellt, an welchen IP-Adressen und Ports der Apache als Server arbeiten soll. Diese Datei sieht bei mir im Moment so aus:
Listen 188.40.88.80:80
NameVirtualHost 188.40.88.80:80
<IfModule mod_ssl.c>
# SSL name based virtual hosts are not yet supported, therefore no
# NameVirtualHost statement here
Listen 188.40.88.80:443
</IfModule>
Eines ist aber klar: sie wird sich im Laufe der weiteren Konfiguration auf jeden Fall noch ändern.
Apache-Sites
Man kann für jede virtuelle Domäne eine Konfigurationsdatei erstellen. Diese legt man in den Ordner sites-available. Verlinkt man die Konfigurationsdatei mit einem symbolischen Link in den Ordner sites-enabled, dann wird die Konfiguration nach einem Neustart des Apachen aktiv. Zum Verlinken kann man ln -s, oder das Apache-Programm a2ensite verwenden. Nimmt man ln -s, dann kann man zusätzlich den Namen (und somit die Sortierung) der Links bestimmen.
Die Datei /etc/apache2/sites-available/default muss man kaum verändern. Man sollte aber die Emailadresse des Server-Admins korrekt einstellen.
Virtuelle Testdomäne erstellen
Für die Emails habe ich mir bereits die Testdomäne test.halvar.at eingerichtet. Sie zeigt auf die IP-Adresse des neuen Servers. Diese kann jetzt auch zum Testen des Apachen verwendet werden.
Zuerst erstelle ich den Linux-Benutzer test_halvar_at und folgende zugehörigen Ordner:
- /home/test_halvar_at/awstats
- /home/test_halvar_at/public
- /home/test_halvar_at/public/cgi-bin.
- /home/test_halvar_at/log
- /home/test_halvar_at/webalizer
Der public-Ordner wird der Root-Ordner der Website. Dann erstelle ich dort noch die Datei index.html und schreibe "Hallo Welt - test.halvar.at" rein. Das genügt um später feststellen zu können, ob der Apache die richtige Datei ausliefert.
Dann erstelle ich die Konfigurationsdatei für die Testdomäne. Ich kopiere mir dazu die default-Datei und passe sie nach meinen Vorstellungen an.
/etc/apache2/sites-available/test_halvar_at
#
# test.halvar.at
#
<VirtualHost 188.40.88.80:80>
ServerAdmin gerold.penz@aon.at
ServerName test.halvar.at
ServerAlias www.test.halvar.at
DocumentRoot /home/test_halvar_at/public
<Directory /home/test_halvar_at/public>
Order allow,deny
Allow from all
Options Indexes MultiViews
IndexOptions FancyIndexing VersionSort HTMLTable NameWidth=* FoldersFirst XHTML
AddDefaultCharset utf-8
AllowOverride All
</Directory>
<Directory /home/test_halvar_at/public/cgi-bin>
AllowOverride None
Options +ExecCGI -Indexes -MultiViews
Order allow,deny
Allow from all
AddHandler cgi-script .cgi .pl .py
</Directory>
# Possible values include: debug, info, notice, warn, error, crit, alert, emerg.
LogLevel info
ErrorLog /home/test_halvar_at/log/apache_error.log
CustomLog /home/test_halvar_at/log/apache_access.log combined
</VirtualHost>
Aktiviert wird diese Konfiguration mit:
a2ensite test_halvar_at /etc/init.d/apache2 stop /etc/init.d/apache2 start
Ein Aufruf der Adresse http://test.halvar.at/ im Browser, zeigt dann, ob alles funktioniert hat. :-)
Zum Testen des cgi-bin-Ordners, erstelle ich dort eine Datei mit dem Namen hallowelt.py. Diese muss unbedingt als "ausführbar" gekennzeichnet werden, sonst funktioniert es nicht.
cd /home/test_halvar_at/public/cgi-bin touch hallowelt.py chmod +x hallowelt.py
Das Testprogramm sieht so aus:
#!/usr/bin/env python
# coding=utf-8
import time
print "Content-type: text/plain"
print
print "Hallo Welt!"
print
print "Es ist jetzt %s Uhr." % time.strftime("%H:%M:%S")
Ein Aufruf der Adresse http://test.halvar.at/cgi-bin/hallowelt.py im Browser, sollte jetzt in etwa dieses hier zu tage bringen:
Hallo Welt! Es ist jetzt 20:53:34 Uhr.
Ja! :-) Es funktioniert.
Somit ist der Apache getestet. Das Einrichten von virtuellen Domänen funktioniert. Jetzt kann ich mit der Arbeit beginnen und die echten "virtuellen Domänen" einrichten. :-)
Apache weniger Informationen
Der Apache gibt ziemlich viele Informationen bei jedem Response und in den eigenen Fehlermeldungen über sich preis. Das zu unterbinden, erschwert es vielleicht den Crackern, herauszufinden, welches OS und welche Apache-Version auf dem Server läuft.
Das kann man mit zwei Einstellungen in folgender Datei ändern.
/etc/apache2/conf.d/security:
ServerTokens Prod ServerSignature Off
ProFTP installieren
aptitude install proftpd
Beim Installieren wird man gefragt, ob der Server "standalone" oder "from_inetd" ausgeführt werden soll. --> "standalone"
Die Einstellungen können über Webmin vorgenommen werden. Hier würde ich einstellen, dass Benutzer nur auf ihre Home-Ordner zugreifen dürfen.
Benutzer für den FTP-Zugang müssen als Unix-Benutzer angelegt werden. Man kann die Benutzer aber einschränken, indem man ihnen /bin/false als Shell zuweist und "!" oder "*" als Passwort in /etc/shadow vergibt.
Als Befehl zum Hinzufügen der Benutzer empfehle ich useradd. Denn damit wird kein Home-Ordner angelegt und als Passwort wird "!" vergeben.
## Den Home-Ordner kann man in /etc/passwd auf /nonexistent einstellen.
Das Passwort kann dann im Webmin-Fenster "Authentisierung" zugewiesen werden. So ist der Unix-Benutzer nur auf FTP beschränkt, denn für andere Anwendungen hat er kein gültiges Passwort.
Im Webmin kann man über den Punkt "Pro-Verzeichnis-Optionen hinzufügen für..." Optionen angeben, die vom Ordner abhängig sind. Ich habe hier jeden Home-Ordner vermerkt und über das Fenster "Benutzer und Gruppen" (der Pro-Verzeichnis-Option) eingestellt, dass egal wer darauf zugreift, die hochgeladenen Dateien dem Besitzer des Home-Ordners gehören.
Logrotate
Dieses Programm ist dafür zuständig, dass Logdateien nicht bis ins Nirwana anwachsen.
/etc/logrotate.d/homedirs:
/home/*/log/*.log {
weekly
missingok
rotate 52
compress
delaycompress
notifempty
create 640 root root
sharedscripts
postrotate
if [ -f "`. /etc/apache2/envvars ; echo ${APACHE_PID_FILE:-/var/run/apache2.pid}`" ]; then
/etc/init.d/apache2 reload > /dev/null
fi
endscript
}
mod_wsgi installieren
http://code.google.com/p/modwsgi/
Quellcode herunterladen und in einen Ordner entpacken. Dann in diesen entpackten Ordner wechseln.
aptitude install apache2-dev aptitude install python-dev ./configure make make install
/etc/apache2/mods-available/wsgi.load:
Das ist die Datei zum Einbinden des Modules in den Apachen.
LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so
Nach dem Erstellen der Datei kann man das neue Modul mit folgendem Befehl einbinden:
a2enmod wsgi
CherryPy und Cheetah installieren
aptitide install python-setuptools easy_install cherrypy easy_install cheetah
Webalizer installieren
Apache Logfile-Analyse
aptitude install webalizer
Die Konfigurationsdatei /etc/webalizer/webalizer.conf musste ich etwas anpassen, damit nicht jeder Spider/Robot mitgezählt wird. Außerdem musste noch die Ausgabe des Content-Type auf "utf-8" umgestellt werden. Mit AllSites, AllURLs, usw. kann man einstellen, dass nicht nur die ersten Top-Ergebnisse angezeigt werden. Ganz wichtig ist die Einstellung Incremental yes. Ist diese Einstellung nicht gesetzt, dann funktioniert das kleine Programm nicht, mit dem ich die Statisiken generieren lasse.
Diese Einstellungen habe ich hinzugefügt:
HTMLHead <META NAME="Content-Type" CONTENT="text/html; Charset=utf-8"> Incremental yes HideURL *.ico HideURL *.jpeg AllSites yes AllURLs yes AllReferrers yes AllAgents yes AllSearchStr yes AllUsers yes IgnoreAgent webcrawler IgnoreAgent Jyxobot IgnoreAgent betaBot IgnoreAgent Yeti IgnoreAgent search.msn.com IgnoreAgent Baiduspider IgnoreAgent msnbot IgnoreAgent Java IgnoreAgent ia_archiver IgnoreAgent Eurobot IgnoreAgent Gigabot IgnoreAgent rdfbot IgnoreAgent libwww-perl IgnoreAgent Googlebot-Image IgnoreAgent anonymous IgnoreAgent eZ Publish Link Validator IgnoreAgent DoCoMo IgnoreAgent Python-urllib IgnoreAgent librabot IgnoreAgent netEstate IgnoreAgent nutch/Nutch IgnoreAgent BaiduImagespider IgnoreAgent OOZBOT IgnoreAgent librabot IgnoreAgent yacybot IgnoreAgent Googlebot IgnoreAgent Wget IgnoreAgent Xenu IgnoreAgent curl IgnoreAgent findlinks IgnoreAgent page_test IgnoreAgent iCcrawler IgnoreAgent Yahoo! Slurp IgnoreAgent Exabot IgnoreAgent Exabot-Images IgnoreAgent Twiceler IgnoreAgent Ask Jeeves IgnoreAgent YoudaoBot IgnoreAgent Yandex IgnoreAgent MJ12bot IgnoreAgent Twiceler IgnoreAgent KaloogaBot IgnoreAgent DotBot IgnoreAgent nutch-agent IgnoreAgent VEDENSBOT IgnoreAgent YoudaoBot IgnoreAgent SurveyBot IgnoreAgent atraxbot IgnoreAgent NaverBot IgnoreAgent VoilaBot IgnoreAgent Plukkie IgnoreAgent Moreoverbot IgnoreAgent Yahoo! SearchMonkey IgnoreAgent Websiteshadowbot IgnoreAgent envolk IgnoreAgent Speedy Spider IgnoreAgent Sosospider IgnoreAgent Sogou web spider IgnoreAgent Sogou-Test-Spider IgnoreAgent Spinn3r
Die Konfiguration sollte noch etwas besser durchdacht werden, aber für den Moment genügt es mir so. Die automatische Erstellung der Webalizer-Berichte habe ich früher mit Webmin eingerichtet. Dort ist das ziemlich komfortabel. Aber inzwischen habe ich mir ein kleines Programm geschrieben, welches für mich besser funktioniert. Dieses kleine Programm wird für jeden Benutzer ein oder zwei mal am Tag über die Datei /etc/crontab aufgerufen.
Hier das kleine Programm (/scripts/generate_webalizer_stats.py):
#!/usr/bin/env python
# coding=utf-8
#
# Generiert mit *webalizer* Zugriffsstatistiken
#
# Erwartet als Parameter den Benutzernamen und den Hostname
# Syntax: ``generate_webalizer_stats.py <benutzername> <web-domain>``
# z.B.: ``generate_webalizer_stats.py wallerforum_com www.wallerforum.com``
#
import os
import sys
import glob
import subprocess
WEBALIZER = "/usr/bin/webalizer"
def main():
username = sys.argv[1]
hostname = sys.argv[2]
userdir = os.path.join("/home", username)
logdir = os.path.join(userdir, "log")
destdir = os.path.join(userdir, "webalizer")
logfilenames = sorted(
glob.glob(os.path.join(logdir, "apache_access.log*")),
reverse = True
)
for logfilename in logfilenames:
args = [WEBALIZER, "-n", hostname, "-o", destdir, logfilename]
proc = subprocess.call(args)
if __name__ == "__main__":
main()
Es ist nichts Besonderes an diesem Programm. Das Programm erwartet als Parameter den Benutzernamen und den Hostnamen (Domäne) für die Website, deren Logdateien ausgewertet werden sollen. Das Skript ruft webalizer auf und übergibt die benötigten Parameter.
Die zugehörigen Einträge in der /etc/crontab sehen so aus:
# Webalizer 0 0,12 * * * halvar_at /scripts/generate_webalizer_stats.py halvar_at halvar.at 1 1,13 * * * lugt_halvar_at /scripts/generate_webalizer_stats.py lugt_halvar_at lugt.halvar.at 2 2,14 * * * horde_webmail /scripts/generate_webalizer_stats.py horde_webmail webmail.wallerforum.com ...
Awstats installieren
Genau so wie Webalizer ist Awstats ein Programm mit dem die Logdateien des Apachen analysiert werden können.
aptitude install awstats
Danach muss man für jeden Benutzer/Domäne eine Datei im /etc/awstats-Ordner anlegen. Die Dateinamen müssen so aussehen: awstats.<benutzername>.conf.
/etc/awstats/awstats.halvar_at.conf:
Include "/etc/awstats/awstats.conf" SiteDomain="halvar.at" HostAliases="localhost 127.0.0.1" DirData="/home/halvar_at/awstats" LogFile="cat /home/halvar_at/log/apache_access.log.1 /home/halvar_at/log/apache_access.log |"
Mit Include wird die Haupt-Konfigurationsdatei eingebunden. Mit LogFile=... wird festgelegt, welche Konfigurationsdateien in welcher Reihenfolge geparst werden. Mit dem Pipe-Zeichen (|) kann man statt einem Dateinamen auch einen Befehl angeben, der die Daten per Pipe an Awstats schickt.
[Weiter gehts mit dem Updaten der Statistiken und dem Erstellen der HTML-Seiten]
Hier gehts weiter...
Horde Groupware Webmail Edition
Notiz: Es wurde Deutsch als Sprache eingestellt. Dafür musste man im Linux die Sprache aktivieren /usr/...locale
Squirrelmail installieren und konfigurieren
(noch nicht erledigt)
aptitude install squirrelmail # squirrelmail-spam-buttons ???
Interessante Ideen
Jabber
Jabber auf dem Server installieren. Da fast alles Fischer auf dem Server sind, könnte das so eine Art Fischer-Chat werden.
Mögliche Clients:
Web-cyradm
...
Weitere ToDo's
Email-Installationsroutine (Usermin)
Floodcontrol: Dateien die älter als 1 Monat sind löschen
Email-Passwort per Usermin ändern lassen:
- Emailadresse (Benutzername)
- Altes Passwort
- zwei mal neues Passwort
- Ausgabe des Befehls sasldbpasswd2 anzeigen
PHP konfigurieren (Limits erhöhen)
MySQL konfigurieren (Limits erhöhen)
Apache: Memory-Cache und Datei-Cache konfigurieren. Alle Bilder könnten eigentlich bis zu einer gewissen Speichergrenze im Speicher verbleiben und direkt (ohne Festplattenzugriff) ausgeliefert werden.
Alles auf UTF-8 umstellen
Adminseiten mit Links erstellen:
- Squirrelmail
- Horde Webmail
- Horde Groupware
- phpMyAdmin
- Usermin
- Webalizer
- Awstats
- net2ftp
Webmin konfigurieren (/ip/ vom Log ausnehmen)
Awstats installieren und konfigurieren (/ip/ vom Log ausnehmen)
- Raid überwachen (http://halvar.at/krimskrams3/linux/show.raidstatus)
ERLEDIGT /etc/mdadm...
- Kann im Webmin eingestellt werden
- Hardware/Linux RAID
- Send Notifications to: Emailadresse
rkhunter und chkrootkit installieren und konfigurieren
Backup testen
Nagios konfigurieren
Spam und Ham lernen lassen
Spamassassin Whitelist lernen lassen
Nagios Server:
- so einstellen, dass mit den Daten auch etwas angefangen werden kann.
- Emailbenachrichtigung bei Fehler
