In diesem Tutorial wollen wir einen „ISP-Fähigen“ FTP-Server aufsetzen, bei dem die Benutzer nicht auf dem System selbst sondern nur virtuell in einer mySQL Datenbank existieren.
Selbstverständlich gehört auch Quota-Support dazu.
Als besonderes Schmankerl werden wir noch SSL hinzufügen um verschlüsseltes FTPS zu realisieren.
Einleitung
Als Software kommt proftd unter einem CentOS System zum Einsatz, die Konfiguration auf anderen Systemen dürfte aber nahezu identisch sein.
Bei den grafischen Frontends ist es häufig so, dass diese nicht wirklich schön sind, man kann aber, besonders bei FTP auch ganz einfach selbst was darum programmieren. Für den start dürfte proftp administrator aber ausreichen.
Installation
[stextbox id=“note“ caption=“Hinweis“]Die Texte: GEHEIMES_PASSWORT, so wie GEHEIMES_USER_PASSWORT müssen natürlich mit deinem Passwort ersetzt werden![/stextbox]
Als erstes installieren wir die benötigen Komponenten (letztere dürfte in den meisten Fällen schon vorhanden sein:
yum install proftd mysql-server openssl |
yum install proftd mysql-server openssl
Nun legen wir noch einen Benutzer und eine Gruppe an, unter dem dann die virtuellen Benutzer laufen:
groupadd -g 10021 ftpusers
useradd -c 'Virtual FTP users' -m -d /home/ftp/ -g 10021 -u 10021 -s /bin/false -r vftp |
groupadd -g 10021 ftpusers
useradd -c 'Virtual FTP users' -m -d /home/ftp/ -g 10021 -u 10021 -s /bin/false -r vftp
[stextbox id=“warning“ caption=“Achtung“]Bitte zuerst abchecken ob die UID/GID: 10021 noch frei ist![/stextbox]
mySQL/Frontend
Nun muss
proftd-administrator auf einem webserver installiert werden. Wie das geht sollte klar sein, wenn nicht einfach der Beschreibung auf der proftpd administrator Webseite folgen. – Dieser Schritt ist optional, im prinzip kann man die user auch direkt in die Tabelle Eintragen, z.B. mit phpmyadmin.
Dann führt man folgende SQL Kommandos auf der Datenbank aus:
mysql -u root -p
mysql> create database proftpd;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON proftpd.* TO 'proftpd'@'localhost' IDENTIFIED BY '<GEHEIMES_PASSWORT>';
mysql> FLUSH PRIVILEGES;
mysql> use proftpd;
CREATE TABLE usertable (
userid text,
passwd text,
homedir text,
shell text,
uid int(11) NOT NULL auto_increment,
gid int(11) default NULL,
count int(11) NOT NULL default '0',
lastlogin datetime NOT NULL default '0000-00-00 00:00:00',
lastlogout datetime NOT NULL default '0000-00-00 00:00:00',
expiration datetime NOT NULL default '0000-00-00 00:00:00',
disabled tinyint(4) default '0',
det_name tinytext,
det_mail tinytext,
det_adress tinytext,
det_notes tinytext,
PRIMARY KEY (uid)
) TYPE=MyISAM;
CREATE TABLE grouptable (
groupname text,
gid int(11) NOT NULL auto_increment,
members text,
description tinytext,
PRIMARY KEY (gid),
UNIQUE KEY gid_2 (gid),
KEY gid (gid)
) TYPE=MyISAM;
CREATE TABLE xfer_stat (
userid text,
file text,
size bigint(20) default '0',
address_full text,
address_ip text,
command text,
timespent text,
time text,
cmd text,
dunno text
) TYPE=MyISAM;
CREATE TABLE `ftpquotalimits` (
`name` varchar(30) NOT NULL default '',
`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 'hard',
`bytes_in_avail` float NOT NULL default '0',
`bytes_out_avail` float NOT NULL default '0',
`bytes_xfer_avail` float 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',
PRIMARY KEY (`name`)
) 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` float NOT NULL default '0',
`bytes_out_used` float NOT NULL default '0',
`bytes_xfer_used` float 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;
INSERT INTO grouptable (gid, groupname, description) VALUES (10021, "users", "Ordinary users");
INSERT INTO usertable (userid, passwd, homedir, shell, uid, gid ) VALUES (10021, <GEHEIMES_USER_PASSWORT>, "/home/ftp/vftp", "/bin/false", 10021, 10021);
quit |
mysql -u root -p
mysql> create database proftpd;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON proftpd.* TO 'proftpd'@'localhost' IDENTIFIED BY '<GEHEIMES_PASSWORT>';
mysql> FLUSH PRIVILEGES;
mysql> use proftpd;
CREATE TABLE usertable (
userid text,
passwd text,
homedir text,
shell text,
uid int(11) NOT NULL auto_increment,
gid int(11) default NULL,
count int(11) NOT NULL default '0',
lastlogin datetime NOT NULL default '0000-00-00 00:00:00',
lastlogout datetime NOT NULL default '0000-00-00 00:00:00',
expiration datetime NOT NULL default '0000-00-00 00:00:00',
disabled tinyint(4) default '0',
det_name tinytext,
det_mail tinytext,
det_adress tinytext,
det_notes tinytext,
PRIMARY KEY (uid)
) TYPE=MyISAM;
CREATE TABLE grouptable (
groupname text,
gid int(11) NOT NULL auto_increment,
members text,
description tinytext,
PRIMARY KEY (gid),
UNIQUE KEY gid_2 (gid),
KEY gid (gid)
) TYPE=MyISAM;
CREATE TABLE xfer_stat (
userid text,
file text,
size bigint(20) default '0',
address_full text,
address_ip text,
command text,
timespent text,
time text,
cmd text,
dunno text
) TYPE=MyISAM;
CREATE TABLE `ftpquotalimits` (
`name` varchar(30) NOT NULL default '',
`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 'hard',
`bytes_in_avail` float NOT NULL default '0',
`bytes_out_avail` float NOT NULL default '0',
`bytes_xfer_avail` float 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',
PRIMARY KEY (`name`)
) 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` float NOT NULL default '0',
`bytes_out_used` float NOT NULL default '0',
`bytes_xfer_used` float 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;
INSERT INTO grouptable (gid, groupname, description) VALUES (10021, "users", "Ordinary users");
INSERT INTO usertable (userid, passwd, homedir, shell, uid, gid ) VALUES (10021, <GEHEIMES_USER_PASSWORT>, "/home/ftp/vftp", "/bin/false", 10021, 10021);
quit
proFTPd
Nun konfigurieren wir die Datei /etc/proftpd.conf wie folgt:
### Load Modules
LoadModule mod_sql.c
LoadModule mod_sql_mysql.c
LoadModule mod_quotatab.c
LoadModule mod_quotatab_sql.c
### Global Options
ServerName "FTP Server"
ServerIdent on "example.org FTP service ready."
ServerType standalone
DefaultServer on
Port 21
User ftp
Group ftp
MaxInstances 30 # To prevent DoS attacks, set the maximum number of child processes to 30
DeferWelcome off
MasqueradeAddress PUBLIC_IP_DES_SERVERS
PassivePorts 60000 60010
MultilineRFC2228 on # For compatibility with certain clients
TimeoutNoTransfer 600
TimeoutStalled 600
TimeoutIdle 1200
DisplayLogin /home/ftp/welcome.msg
DisplayChdir .message
#ListOptions "-lh"
ListOptions "+a"
DenyFilter \*.*/
#PathDenyFilter "\\.ftp)|\\.ht)[a-z]+$"
PathDenyFilter "(^|/)[-.]"
### FTPS/SSL connections
<IfModule mod_tls.c>
TLSEngine on
TLSLog /var/log/proftpd/tls.log
TLSProtocol SSLv3 TLSv1
TLSRequired off # Are clients required to use FTP over TLS when talking to this server?
# Server's certificate
TLSRSACertificateFile /usr/local/share/ssl/default.crt
TLSRSACertificateKeyFile /usr/local/share/ssl/default.key
TLSCACertificateFile /usr/local/share/ssl/default.ca # CA the server trusts
TLSVerifyClient off # Authenticate clients that want to use FTP over TLS?
# Allow SSL/TLS renegotiations when the client requests them, but
# do not force the renegotations. Some clients do not support
# SSL/TLS renegotiations; when mod_tls forces a renegotiation, these
# clients will close the data connection, or there will be a timeout
# on an idle data connection.
TLSRenegotiate none
TLSOptions NoCertRequest
</IfModule>
### User Options
DefaultRoot ~ ftpusers # chroot for members of the users group
# Umask 022 prevents new files and dirs (second parm) from being group and world writable.
Umask 027 027
AllowOverwrite on # Normally, we want files to be overwriteable.
# Only members of the users grou are allowd to login
<Limit LOGIN>
DenyGroup !ftpusers
</Limit>
# Deny root-login, but do not persist of a valid shell as we use virtual users
<Global>
RootLogin off
RequireValidShell off
</Global>
### Authentication
#PersistentPasswd off # Uncomment this if you are using NIS or LDAP to retrieve passwords
AuthOrder mod_sql.c
SQLAuthTypes Backend
SQLConnectInfo proftpd@localhost proftpd secret
SQLUserInfo usertable userid passwd uid gid homedir shell
SQLGroupInfo grouptable groupname gid members
SQLUserWhereClause "disabled=0 and (NOW()<=expiration or expiration=-1 or expiration=0)"
# Log the user logging in
SQLLog PASS counter
SQLNamedQuery counter UPDATE "lastlogin=now(), count=count+1 WHERE userid='%u'" usertable
# logout log
SQLLog EXIT time_logout
SQLNamedQuery time_logout UPDATE "lastlogout=now() WHERE userid='%u'" usertable
# display last login time when PASS command is given
SQLNamedQuery login_time SELECT "lastlogin from usertable where userid='%u'"
SQLShowInfo PASS "230" "Last login was: %{login_time}"
# xfer Log in mysql
SQLLog RETR,STOR transfer1
SQLNamedQuery transfer1 INSERT "'%u', '%f', '%b', '%h', '%a', '%m', '%T', now(), 'c', NULL" xfer_stat
SQLLOG ERR_RETR,ERR_STOR transfer2
SQLNamedQuery transfer2 INSERT "'%u', '%f', '%b', '%h', '%a', '%m', '%T', now(), 'i', NULL" xfer_stat
### 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
### Logging
# Define logging formats
LogFormat default "%h %l %u %t \"%r\" %s %b"
LogFormat auth "%v [%P] %h %t \"%r\" %s"
LogFormat write "%h %l %u %t \"%r\" %s %b"
# alle logins
ExtendedLog /var/log/proftpd/ftp_auth.log AUTH auth
# file/dir access
ExtendedLog /var/log/proftpd/ftp_access.log WRITE,READ write
# paranoid log (large logfiles!)
ExtendedLog /var/log/proftpd/ftp.log ALL default
### Directories
<Directory /srv/ftp/upload>
AllowOverwrite off
<Limit DELE RMD>
DenyAll
</Limit>
</Directory> |
### Load Modules
LoadModule mod_sql.c
LoadModule mod_sql_mysql.c
LoadModule mod_quotatab.c
LoadModule mod_quotatab_sql.c
### Global Options
ServerName "FTP Server"
ServerIdent on "example.org FTP service ready."
ServerType standalone
DefaultServer on
Port 21
User ftp
Group ftp
MaxInstances 30 # To prevent DoS attacks, set the maximum number of child processes to 30
DeferWelcome off
MasqueradeAddress PUBLIC_IP_DES_SERVERS
PassivePorts 60000 60010
MultilineRFC2228 on # For compatibility with certain clients
TimeoutNoTransfer 600
TimeoutStalled 600
TimeoutIdle 1200
DisplayLogin /home/ftp/welcome.msg
DisplayChdir .message
#ListOptions "-lh"
ListOptions "+a"
DenyFilter \*.*/
#PathDenyFilter "\\.ftp)|\\.ht)[a-z]+$"
PathDenyFilter "(^|/)[-.]"
### FTPS/SSL connections
<IfModule mod_tls.c>
TLSEngine on
TLSLog /var/log/proftpd/tls.log
TLSProtocol SSLv3 TLSv1
TLSRequired off # Are clients required to use FTP over TLS when talking to this server?
# Server's certificate
TLSRSACertificateFile /usr/local/share/ssl/default.crt
TLSRSACertificateKeyFile /usr/local/share/ssl/default.key
TLSCACertificateFile /usr/local/share/ssl/default.ca # CA the server trusts
TLSVerifyClient off # Authenticate clients that want to use FTP over TLS?
# Allow SSL/TLS renegotiations when the client requests them, but
# do not force the renegotations. Some clients do not support
# SSL/TLS renegotiations; when mod_tls forces a renegotiation, these
# clients will close the data connection, or there will be a timeout
# on an idle data connection.
TLSRenegotiate none
TLSOptions NoCertRequest
</IfModule>
### User Options
DefaultRoot ~ ftpusers # chroot for members of the users group
# Umask 022 prevents new files and dirs (second parm) from being group and world writable.
Umask 027 027
AllowOverwrite on # Normally, we want files to be overwriteable.
# Only members of the users grou are allowd to login
<Limit LOGIN>
DenyGroup !ftpusers
</Limit>
# Deny root-login, but do not persist of a valid shell as we use virtual users
<Global>
RootLogin off
RequireValidShell off
</Global>
### Authentication
#PersistentPasswd off # Uncomment this if you are using NIS or LDAP to retrieve passwords
AuthOrder mod_sql.c
SQLAuthTypes Backend
SQLConnectInfo proftpd@localhost proftpd secret
SQLUserInfo usertable userid passwd uid gid homedir shell
SQLGroupInfo grouptable groupname gid members
SQLUserWhereClause "disabled=0 and (NOW()<=expiration or expiration=-1 or expiration=0)"
# Log the user logging in
SQLLog PASS counter
SQLNamedQuery counter UPDATE "lastlogin=now(), count=count+1 WHERE userid='%u'" usertable
# logout log
SQLLog EXIT time_logout
SQLNamedQuery time_logout UPDATE "lastlogout=now() WHERE userid='%u'" usertable
# display last login time when PASS command is given
SQLNamedQuery login_time SELECT "lastlogin from usertable where userid='%u'"
SQLShowInfo PASS "230" "Last login was: %{login_time}"
# xfer Log in mysql
SQLLog RETR,STOR transfer1
SQLNamedQuery transfer1 INSERT "'%u', '%f', '%b', '%h', '%a', '%m', '%T', now(), 'c', NULL" xfer_stat
SQLLOG ERR_RETR,ERR_STOR transfer2
SQLNamedQuery transfer2 INSERT "'%u', '%f', '%b', '%h', '%a', '%m', '%T', now(), 'i', NULL" xfer_stat
### 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
### Logging
# Define logging formats
LogFormat default "%h %l %u %t \"%r\" %s %b"
LogFormat auth "%v [%P] %h %t \"%r\" %s"
LogFormat write "%h %l %u %t \"%r\" %s %b"
# alle logins
ExtendedLog /var/log/proftpd/ftp_auth.log AUTH auth
# file/dir access
ExtendedLog /var/log/proftpd/ftp_access.log WRITE,READ write
# paranoid log (large logfiles!)
ExtendedLog /var/log/proftpd/ftp.log ALL default
### Directories
<Directory /srv/ftp/upload>
AllowOverwrite off
<Limit DELE RMD>
DenyAll
</Limit>
</Directory>
[stextbox id=“note“ caption=“Hinweis“]Für FTPS musst du nun noch eine SSL Zertifikat erstellen und als:
/etc/ssl/default.key
/etc/ssl/default.crt
abspeichern.
Wie man solche Zertifikate erstellt wird im Workshop: ((Mit OpenVPN zwei Netzwerke verbinden|Mit OpenVPN zwei Netzwerke verbinden)) im Abschnitt: „Zertifizierungsstelle einrichten“ behandelt.
Falls du dies nicht möchtest, lösche einfach den SSL-Teil aus der Konfiguration heraus.[/stextbox]
Abschliessender Test
[stextbox id=“note“ caption=“Hinweis: Firewall“]Falls du Probleme beim Zugriff auf den FTP-Server hast: Vor allem bei „passive FTP“ muss man das iptables-Modul: nf_conntrack_ftp verwenden!
Bei Red Hat Systmen kannst du das unter: /etc/sysconfig/iptables-config Eintragen:
IPTABLES_MODULES="nf_conntrack_ftp" |
IPTABLES_MODULES="nf_conntrack_ftp"
[/stextbox]
Starte nun den proftpd Server:
Nun kannst di dich mit dem FTP verbinden:
ftp localhost
Connected to localhost (127.0.0.1).
220 ProFTPD 1.3.3c Server (CentOS) [78.46.19.250]
Name (localhost:root): vftp
331 Password required for vftp
Password: <GEHEIMES_USER_PASSWORT>
ftp> dir |
ftp localhost
Connected to localhost (127.0.0.1).
220 ProFTPD 1.3.3c Server (CentOS) [78.46.19.250]
Name (localhost:root): vftp
331 Password required for vftp
Password: <GEHEIMES_USER_PASSWORT>
ftp> dir