Virtuelles Hosting mit Proftpd und MySQL (Inkl. Quota) auf Fedora 9

Version 1.0
Autor: Falko Timme


Diese Anleitung veranschaulicht, wie man einen Proftpd Server installiert, der virtuelle Benutzer einer MySQL Datenbank verwendet anstelle von wirklichen Benutzern. Dies ist um einiges leistungsfähiger und ermöglicht es, Tausende von ftp Benutzern auf nur einer Maschine zu haben. Weiterhin werde ich die Anwendung von Quota in diesem Setup beschreiben.

Zur Administration der MySQL Datenbank kannst Du webbasierte Tools wie phpMyAdmin verwenden, das in dieser Anleitung ebenfalls installiert wird. phpMyAdmin ist eine angenehme grafische Oberfläche, was bedeutet, dass Du nicht mit der Kommandozeile rumbasteln musst.

Diese Anleitung basiert auf Fedora 9. Du solltest bereits ein Fedora 9 Basissystem installiert haben, was in den ersten sieben Kapiteln dieser Anleitung beschrieben wird: http://www.howtoforge.com/perfect-server-fedora9
Diese Anleitung ist ein praktischer Leitfaden in welchem kein theoretisches Hintergrundwissen abgedeckt wird. Dies wird in zahlreichen anderen Dokumenten im Netz behandelt.

Diese Anleitung ist ohne jegliche Gewähr. Ich möchte an dieser Stelle darauf hinweisen, dass dies nicht der einzige Weg ist, ein solches System einzurichten. Es gibt viele Möglichkeiten ans Ziel zu kommen - dies ist der Weg, den ich gewählt habe. Ich kann keine Garantie übernehmen, dass dies auch bei Dir funktioniert!

1 Vorbemerkung

In dieser Anleitung verwende ich den Hostnamen server1.example.com mit der IP Adresse 192.168.0.100. Diese Einstellungen können bei Dir abweichend sein, deshalb müssen sie an entsprechender Stelle angepasst werden.

2 MySQL und phpMyAdmin installieren

Das kann alles mit nur einem Befehl installiert werden:

yum install mysql mysql-server phpMyAdmin httpd

Hiernach wird die Datei /etc/httpd/conf.d/phpMyAdmin.conf editiert, um von allen IP Adressen auf phpMyAdmin zugreifen zu können. Standardmässig kann nur von 127.0.0.1. zugegriffen werden. Bitte kommentiere folgenden Bereich aus:

<Directory /usr/share/phpMyAdmin/>
order deny,allow
deny from all
allow from 127.0.0.1
</Directory>

...so dass die Datei folgendermassen aussieht:

vi /etc/httpd/conf.d/phpMyAdmin.conf

# phpMyAdmin - Web based MySQL browser written in php
# # Allows only localhost by default # # But allowing phpMyAdmin to anyone other than localhost should be considered # dangerous unless properly secured by SSL Alias /phpMyAdmin /usr/share/phpMyAdmin Alias /phpmyadmin /usr/share/phpMyAdmin #<Directory /usr/share/phpMyAdmin/> # order deny,allow # deny from all # allow from 127.0.0.1 #</Directory> # This directory does not require access over HTTP - taken from the original # phpMyAdmin upstream tarball # <Directory /usr/share/phpMyAdmin/libraries> Order Deny,Allow Deny from All Allow from None </Directory> # This configuration prevents mod_security at phpMyAdmin directories from # filtering SQL etc. This may break your mod_security implementation. # #<IfModule mod_security.c> # <LocationMatch "/phpMyAdmin/(.+)"> # SecRuleInheritance Off # </LocationMatch> #</IfModule>
Dann erstellen wir die System Startup Links für MySQL und Apache, so dass beide automatisch starten, sobald das System hochfährt, und starten beide Dienste:

chkconfig --levels 235 mysqld on
/etc/init.d/mysqld start

chkconfig --levels 235 httpd on
/etc/init.d/httpd start

Erstelle ein Passwort für den MySQL Benutzer root (ersetze yourrootsqlpassword mit einem selbst ausgewählten Passwort):

mysqladmin -u root password yourrootsqlpassword
mysqladmin -h server1.example.com -u root password yourrootsqlpassword

3 Proftpd mit MySQL Unterstützung installieren

Für Fedora gibt es ein fertig konfiguriertes proftpd-mysql Paket. Es wird folgendermassen installiert:

yum install proftpd-mysql

Danach erstellen wir eine ftp-Gruppe (ftpgroup) sowie Benutzer (ftpuser), mit dem alle unsere virtuellen Benutzer verknüpft werden. Ersetze die Gruppen- und BenutzerID 2001 mit einer Nummer, die auf Deinem System frei ist:

groupadd -g 2001 ftpgroup
useradd -u 2001 -s /bin/false -d /bin/null -c "proftpd user" -g ftpgroup ftpuser

4 MySQL Datenbank für Proftpd erstellen

Wir erstellen nun eine Datenbank mit der Bezeichnung ftp sowie einen MySQL Benutzer proftpd, welchen der Proftpd Dämon später verwenden wird, um sich mit der ftp Datenbank in Verbindung zu setzen:

mysql -u root -p


create database ftp;
GRANT SELECT, INSERT, UPDATE, DELETE ON ftp.* TO 'proftpd'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT, INSERT, UPDATE, DELETE ON ftp.* TO 'proftpd'@'localhost.localdomain' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;

Ersetze die Zeile password mit einem von Dir ausgewählten Passwort für den MySQL Benutzer proftpd. Auf der MySQL Kommandozeile erstellen wir die benötigten Datenbanktabellen :

USE ftp;


CREATE TABLE ftpgroup (
groupname varchar(16) NOT NULL default '',
gid smallint(6) NOT NULL default '5500',
members varchar(16) NOT NULL default '',
KEY groupname (groupname)
) TYPE=MyISAM COMMENT='ProFTP group table';

CREATE TABLE ftpquotalimits (
name varchar(30) default NULL,
quota_type enum('user','group','class','all') NOT NULL default 'user',
per_session enum('false','true') NOT NULL default 'false',
limit_type enum('soft','hard') NOT NULL default 'soft',
bytes_in_avail int(10) unsigned NOT NULL default '0',
bytes_out_avail int(10) unsigned NOT NULL default '0',
bytes_xfer_avail int(10) unsigned NOT NULL default '0',
files_in_avail int(10) unsigned NOT NULL default '0',
files_out_avail int(10) unsigned NOT NULL default '0',
files_xfer_avail int(10) unsigned NOT NULL default '0'
) TYPE=MyISAM;

CREATE TABLE ftpquotatallies (
name varchar(30) NOT NULL default '',
quota_type enum('user','group','class','all') NOT NULL default 'user',
bytes_in_used int(10) unsigned NOT NULL default '0',
bytes_out_used int(10) unsigned NOT NULL default '0',
bytes_xfer_used int(10) unsigned NOT NULL default '0',
files_in_used int(10) unsigned NOT NULL default '0',
files_out_used int(10) unsigned NOT NULL default '0',
files_xfer_used int(10) unsigned NOT NULL default '0'
) TYPE=MyISAM;

CREATE TABLE ftpuser (
id int(10) unsigned NOT NULL auto_increment,
userid varchar(32) NOT NULL default '',
passwd varchar(32) NOT NULL default '',
uid smallint(6) NOT NULL default '5500',
gid smallint(6) NOT NULL default '5500',
homedir varchar(255) NOT NULL default '',
shell varchar(16) NOT NULL default '/sbin/nologin',
count int(11) NOT NULL default '0',
accessed datetime NOT NULL default '0000-00-00 00:00:00',
modified datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (id),
UNIQUE KEY userid (userid)
) TYPE=MyISAM COMMENT='ProFTP user table';

quit;

Wie Du gesehen hast, haben wir mit dem Befehl quit; die MySQL Kommandozeile verlassen und sind zurück auf die Linux Kommandozeile.

Übrigens: Ich gehe davon aus, dass der Hostname des ftp Servers server1.example.com ist, dann kann auf phpMyAdmin unter http://server1.example.com/phpMyAdmin/ zugegriffen werden. Es kann die IP Adresse anstatt von server1.example.com im Browser genutzt werden, um sich als proftpd einzuloggen. Dann kannst Du Dir die Datenbank ansehen. Später kann phpMyAdmin zur Verwaltung des Proftpd Servers genutzt werden.

5 Proftpd konfigurieren

Öffne /etc/proftpd.conf und kommentiere die Zeilen AuthPAMConfig und AuthOrder aus:

vi /etc/proftpd.conf

[...]
# Use pam to authenticate (default) and be authoritative #AuthPAMConfig proftpd #AuthOrder mod_auth_pam.c* mod_auth_unix.c [...]
Etwas weiter runter in der selben Datei, werden folgende Zeilen direkt unter dem <IfModule mod_dso.c>...</IfModule> Absatz eingefügt:
[...]
# SQL authentication Dynamic Shared Object (DSO) loading # See README.DSO and howto/DSO.html for more details. #<IfModule mod_dso.c> # LoadModule mod_sql.c # LoadModule mod_sql_mysql.c # LoadModule mod_sql_postgres.c #</IfModule> LoadModule mod_sql.c LoadModule mod_sql_mysql.c LoadModule mod_quotatab.c LoadModule mod_quotatab_sql.c # The passwords in MySQL are encrypted using CRYPT SQLAuthTypes Plaintext Crypt SQLAuthenticate users groups # used to connect to the database # databasename@host database_user user_password SQLConnectInfo ftp@localhost proftpd password # Here we tell ProFTPd the names of the database columns in the "usertable" # we want it to interact with. Match the names with those in the db SQLUserInfo ftpuser userid passwd uid gid homedir shell # Here we tell ProFTPd the names of the database columns in the "grouptable" # we want it to interact with. Again the names match with those in the db SQLGroupInfo ftpgroup groupname gid members # set min UID and GID - otherwise these are 999 each SQLMinID 500 # create a user's home directory on demand if it doesn't exist SQLHomedirOnDemand on # Update count every time user logs in SQLLog PASS updatecount SQLNamedQuery updatecount UPDATE "count=count+1, accessed=now() WHERE userid='%u'" ftpuser # Update modified everytime user uploads or deletes a file SQLLog STOR,DELE modified SQLNamedQuery modified UPDATE "modified=now() WHERE userid='%u'" ftpuser # User quotas # =========== QuotaEngine on QuotaDirectoryTally on QuotaDisplayUnits Mb QuotaShowQuotas on SQLNamedQuery get-quota-limit SELECT "name, quota_type, per_session, limit_type, bytes_in_avail, bytes_out_avail, bytes_xfer_avail, files_in_avail, files_out_avail, files_xfer_avail FROM ftpquotalimits WHERE name = '%{0}' AND quota_type = '%{1}'" SQLNamedQuery get-quota-tally SELECT "name, quota_type, bytes_in_used, bytes_out_used, bytes_xfer_used, files_in_used, files_out_used, files_xfer_used FROM ftpquotatallies WHERE name = '%{0}' AND quota_type = '%{1}'" SQLNamedQuery update-quota-tally UPDATE "bytes_in_used = bytes_in_used + %{0}, bytes_out_used = bytes_out_used + %{1}, bytes_xfer_used = bytes_xfer_used + %{2}, files_in_used = files_in_used + %{3}, files_out_used = files_out_used + %{4}, files_xfer_used = files_xfer_used + %{5} WHERE name = '%{6}' AND quota_type = '%{7}'" ftpquotatallies SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4}, %{5}, %{6}, %{7}" ftpquotatallies QuotaLimitTable sql:/get-quota-limit QuotaTallyTable sql:/get-quota-tally/update-quota-tally/insert-quota-tally RootLogin off RequireValidShell off [...]
Bitte überprüfe ob die Zeile password mit dem echten Passwort für den MySQL Benutzer proftpd in der Zeile SQLConnectInfo ersetzt wurde!

Nun erstellen wir die System Startup Links für Proftpd und starten es:

chkconfig --levels 235 proftpd on
/etc/init.d/proftpd start

6 Datenbank füllen und testen

Um die Datenbank zu füllen, wird die MySQL Kommandozeile verwendet:

mysql -u root -p

USE ftp;

Als erstes erstellen wir einen Eintrag in der Tabelle ftpgroup. Es enthält den Gruppennamen, die GruppenID sowie den Benutzernamen der FTP Gruppe/Benutzers den wir am Ende des zweiten Schrittes erstellt haben (ersetze die GruppenID entsprechend wenn Du eine andere als 2001 nutzt):

INSERT INTO `ftpgroup` (`groupname`, `gid`, `members`) VALUES ('ftpgroup', 2001, 'ftpuser');

Das war es schon für die Tabelle ftpgroup, es müssen hier keine weiteren Einträge erstellt werden. Immer wenn ein neuer virtueller Benutzer angelegt wird, geschieht das in der Tabelle ftpquotalimits und ftpuser. Erstellen wir unseren ersten Benutzer exampleuser mit einer Quota von 15MB und dem Passwort secret (Achtung, wir befinden uns immer noch auf der MySQLKommandozeile):

INSERT INTO `ftpquotalimits` (`name`, `quota_type`, `per_session`, `limit_type`, `bytes_in_avail`, `bytes_out_avail`, `bytes_xfer_avail`, `files_in_avail`, `files_out_avail`, `files_xfer_avail`) VALUES ('exampleuser', 'user', 'true', 'hard', 15728640, 0, 0, 0, 0, 0);

INSERT INTO `ftpuser` (`id`, `userid`, `passwd`, `uid`, `gid`, `homedir`, `shell`, `count`, `accessed`, `modified`) VALUES (1, 'exampleuser', 'secret', 2001, 2001, '/home/www.example.com', '/sbin/nologin', 0, '', '');

quit;

(Bitte versichere Dich dass Du die Gruppen- und BenutzerID 2001 im letzten INSERT Befehl entsprechend geändert hast, solltest Du andere Werte als in dieser Anleitung benutzen!)

Öffne nun auf Deinem Arbeitsplaz Dein FTP Client Programm (etwas wie WS_FTP oder SmartFTP wenn Du Dich auf einem Windows System befindest oder gFTP auf einem Linux Desktop) und versuche Dich zu verbinden. Als Hostname verwendest Du server1.example.com (oder die IP Adresse des Systems), der Benutzername ist exampleuser und das Passwort ist secret.

Wenn Du Dich verbinden kannst, dann herzlichen Glückwunsch! Wenn nicht, ist etwas schief gelaufen.

Wenn Du nun Folgendes ausführst:

ls -l /home/

...solltest Du feststellen, dass das Verzeichnis /home/www.example.com (exampleusers Home Verzeichnis) automatisch erstellt wurde und dass es dem ftpuser und der ftpgroup (der Benutzer/die Gruppe, die wir am Ende von Schritt 2 angelegt haben) gehört:

[root@server1 ~]# ls -l /home/
total 4
drwxr-xr-x 2 ftpuser ftpgroup 4096 2008-07-01 18:08 www.example.com
[root@server1 ~]#

7 Administration der Datenbank

Für die meisten Leute ist es einfacher, wenn sie ein grafisches Frontend für MySQL haben; daher kannst Du auch phpMyAdmin (in diesem Beispiel unter http://server1.example.com/phpMyAdmin/) verwenden, um die ftp Datenbank zu verwalten.


Immer wenn ein neuer Benutzer angelegt wird, müssen nur die Einträge in der Tabelle ftpquotalimits und ftpuser erstellt werden, so dass ich die Spalten dieser Tabelle hier erkläre:

ftpuser-Tabelle:

Die wichtigen Spalten sind folgende (alle anderen werden von MySQL oder Proftpd automatisch erstellt, fülle sie daher auf keinen Fall manuell aus!):
  • userid: Der Name des virtuellen Proftpd Benutzers (z. B. exampleuser).
  • passwd: Das unverschlüsselte Passwort des Benutzers.
  • uid: Die BenutzerID des FTP-Benutzers den wir am Ende des zweiten Schrittes erstellt haben (z.B. 2001).
  • gid: Die GruppenIDid der FTP-Gruppe die wir am Ende des zweiten Schrittes erstellt haben (z.B. 2001).
  • homedir: Das Home Verzeichnis des virtuellen Proftpd Benutzers (z. B. /home/www.example.com). Wenn es nicht existiert, wird es beim ersten Einloggen des Benutzers erstellt, sobald dieser per FTP zugreift. Der virtuelle Benutzer wird in seinem Home Verzeichnis gesperrt, d.h. er kann auf andere Verzeichnisse außerhalb seines Home Verzeichnisses nicht zugreifen.
  • shell: Hier kann man /sbin/nologin als Standard einsetzen.

ftp Quotabeschränkung-Tabelle:

Die wichtigen Spalten sind folgende (alle anderen werden von MySQL oder Proftpd automatisch erstellt, fülle sie daher auf keinen Fall manuell aus!):
  • name: Der Name des virtuellen Proftpd Benutzers (z. B. exampleuser).
  • quota_type: user oder group. Üblicherweise nutzen wir hier user.
  • per_session: true oder false. true bedeutet dass die Quotabeschränkung nur für eine Sitzung gültig sind. Hat der Benutzer beispielsweise eine Quota von 15 MB, und lädt 15 MB während der aktuellen Sitzung hoch, kann er keine Daten mehr hochladen. Wenn der Benutzer sich allerdings ausloggt und wieder einloggt, hat er wieder 15 MB zur Verfügung. false bedeutet dass der Benutzer 15 MB zur Verfügung hat, uanbhängig davon ob er sich ein- und ausloggt.
  • limit_type: hard oder soft. Eine hard Quotabeschränkung ist ein strikte Limitierung, während eine soft Quota temporär überschritten werden kann. Normalerweise wird hard benutzt.
  • bytes_in_avail: Upload Begrenzung in Bytes (z. B. 15728640 für 15 MB). 0 bedeutet unbeschränkt.
  • bytes_out_avail: Download Begrenzung in Bytes. 0 bedeutet unbeschränkt.
  • bytes_xfer_avail: Transfer-Beschränkung in Bytes. Die Summe der Up- und Downloads die einem Benutzer gestattet werden. 0 bedeutet unbeschränkt.
  • files_in_avail: Upload Begrenzung von Dateien.0 bedeutet unbeschränkt.
  • files_out_avail: Download Begrenzung von Dateien.0 bedeutet unbeschränkt.
  • files_xfer_avail: Transfer Begrenzung von Dateien.0 bedeutet unbeschränkt.
Die ftpquotatallies Tabelle wird von Proftpd intern zum Management von Quotas benutzt, daher dürfen die Einträge dort nicht verändert werden!

8 Anonymes FTP Konto

Wenn Du ein anonymes FTP Konto erstellen möchtest (ein FTP Konto, in das sich jeder ohne Passwort einloggen kann), gehe folgendermassen vor:

Zuerst erstellen wir einen Benutzer sowie eine Gruppe mit dem Namen anonymous_ftp. Der Benutzer hat das Home Verzeichnis /home/anonymous_ftp:

groupadd -g 2002 anonymous_ftp
useradd -u 2002 -s /bin/false -d /home/anonymous_ftp -m -c "Anonymous FTP User" -g anonymous_ftp anonymous_ftp

(Ersetze 2002 mit einer Gruppen-/BenutzerID das auf Deinem System frei ist.)

Einige Dateien die mit einem Punkt . beginnen sind mit dem letzten Befehl (useradd) im /home/anonymous_ftp Verzeichins erstellt worden. Sie werden nicht gebraucht und können daher gelöscht werden :

cd /home/anonymous_ftp
rm -f .bash_logout
rm -f .bash_profile
rm -f .bashrc
rm -f .gnome2
rm -f .zshrc

Dann erstellen wir das Verzeichnis /home/anonymous_ftp/incoming, welches anonymen Benutzern erlaubt Dateien hochzuladen:

mkdir /home/anonymous_ftp/incoming
chown anonymous_ftp:nobody /home/anonymous_ftp/incoming

Öffne /etc/proftpd.conf und hänge folgende Anweisungen an, ganz zum Ende:

vi /etc/proftpd.conf

[...]
<Anonymous ~anonymous_ftp> User anonymous_ftp Group nobody # We want clients to be able to login with "anonymous" as well as "ftp" UserAlias anonymous anonymous_ftp # Cosmetic changes, all files belongs to ftp user DirFakeUser on anonymous_ftp DirFakeGroup on anonymous_ftp RequireValidShell off # Limit the maximum number of anonymous logins MaxClients 10 # We want 'welcome.msg' displayed at login, and '.message' displayed # in each newly chdired directory. DisplayLogin welcome.msg DisplayFirstChdir .message # Limit WRITE everywhere in the anonymous chroot <Directory *> <Limit WRITE> DenyAll </Limit> </Directory> <Directory incoming> # Umask 022 is a good standard umask to prevent new files and dirs # (second parm) from being group and world writable. Umask 022 022 <Limit READ WRITE> DenyAll </Limit> <Limit STOR> AllowAll </Limit> </Directory> </Anonymous>
Proftpd wird nun neu gestartet:

/etc/init.d/proftpd restart

Nun können sich anonyme Benutzer einloggen. Sie können Dateien von /home/anonymous_ftp herunterladen, die Uploads sind jedoch auf /home/anonymous_ftp/incoming limitert (wurde eine Datei nach /home/anonymous_ftp/incoming hochgeladen, kann es von dort aus weder gelesen noch heruntergeladen werden; der Administrator des Servers muss es nach /home/anonymous_ftp ziehen, um es für andere zugänglich zu machen).

(Bitte merke: Du kannst nur ein anonymes ftp Konto pro IP Adresse haben!)

9 References

Mandrake 10.1 - Proftpd + MySQL Authentifizierung + Quotas Anleitung: http://www.khoosys.net/single.htm?ipg=848

10 Links