ProFTPd с виртуальными пользователями в MySQL

Постановка задачи: установить сервер proFTPd на сервер с платформой debian через ssh; в качестве альтернативного хранилища пользователей – использовать базу данных MySQL; настроить использование шифрованных паролей и использование сертификатов SSL для FTP-сервера; задействовать механизм назначения прав пользователей и групп; установить квоты произвольного типа (hard и soft); оптимизировать сервер, обеспечив защиту ftp сервера от атак, ошибок и сбоев; проверить работу сервера с русскоязычными названиями файлов; протестировать работу сервера из шелла cmd, браузеров и “проводника” windows.

Введение или матчасть

Несомненными лидерами среди FTP-серверов на сегодняшний день являются pure-ftpd, proftpd и vsftpd. Когда у Вас сотни пользователей и десятки доменов на сервере, неудобно на каждого заводить системного пользователя, поэтому в этой статье я сохранил методику настройки proftpd 1.3.4a с хранением списка виртуальных пользователей в MySQL.

Итак, приступаем к настроке сервера ftp – ProFTPD:

  1. Установка proftpd под Debian Lenny
  2. Настройка proftpd для работы с виртуальными пользователями в MySQL
  3. Тестирование начальной конфигурации
  4. Добавление виртуальных пользователей, расстановка прав
  5. Увеличиваем безопасность ftp-сервера (опционально)
  6. Добавляем сертификат SSL к серверу ProFTPD
  7. Шифруем Palintext пароли в БД

1. Установка proftpd под Debian Wheezy

# apt-cache search proftpd

proftpd-mod-mysql - versatile, virtual-hosting FTP daemon - MySQL module
proftpd - versatile, virtual-hosting FTP daemon

# apt-get install proftpd proftpd-mod-mysql

запустится конфигуратор – выбираем тип “самостоятельно” из предложенного , так как у нас предполагается нагруженный ftp сервер.

1
2
3
4
5
6
7
8
9
10
11
12
13
Preconfiguring packages ...
Selecting previously unselected package libfile-copy-recursive-perl.
...
Adding system user `proftpd' (UID 105) ...
Adding new user `proftpd' (UID 105) with group `nogroup' ...
Not creating home directory `/var/run/proftpd'.
Adding system user `ftp' (UID 106) ...
Adding new user `ftp' (UID 106) with group `nogroup' ...
Creating home directory `/srv/ftp' ...
`/usr/share/proftpd/templates/welcome.msg' -> `/srv/ftp/welcome.msg.proftpd-new'
[....] Starting ftp server: proftpd ok
Setting up proftpd-mod-mysql (1.3.4a-5+deb7u1) ...
Setting up proftpd-mod-vroot (0.9.2-2+b2) ...

2. Настройка proftpd для работы с виртуальными пользователями в MySQL

Обратите внимание на то, что было создано в вашей системе:

1
2
3
4
5
6
Adding system user `proftpd' (UID 105) ...
Adding new user `proftpd' (UID 105) with group `nogroup' ...
Not creating home directory `/var/run/proftpd'.
Adding system user `ftp' (UID 106) ...
Adding new user `ftp' (UID 106) with group `nogroup' ...
Creating home directory `/srv/ftp' ...

В частности, нас интересуют идентификаторы вновь созданных пользователей proftpd:

1
2
3
4
debian:/# cat /etc/passwd | grep ftp
proftpd:x:105:65534::/var/run/proftpd:/bin/false
ftp:x:106:65534::/srv/ftp:/bin/false

Запомним порядковый номер пользователя и группу proftpd (105, 65534), а также тип шелла – /bin/false. Домашний каталог нового пользователя – /srv/ftp.

Создадим файл для хранения логов сервера proftpd с базой MySQL и даём на него необходимые права:

1
2
debian:/# touch /var/log/proftpd/proftpd_sql.log
debian:/# chown proftpd:root /var/log/proftpd/proftpd_sql.log

Далее создаём БД, где будут храниться пользователи, ошибки и логи доступа к нашему серверу ftp.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
debian:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 75
Server version: 5.5.35-0+wheezy1-log (Debian)
Type 'help;' or '\h' for help.Type '\c' to clear the current input statement.
mysql> create database proftpd;
Query OK, 1 row affected (0.02 sec)
mysql> grant all on proftpd.* to 'proftpd'@'localhost' identified by 'proftpdPASSWORD';
Query OK, 0 rows affected (0.19 sec)
mysql> quit
Bye

Прежде чем создавать таблицы в БД, уточним какие таблицы нам нужны и какой функционал мы будем вкладывать в них. Нам понадобятся 6 таблиц:

  1. group_ftp – Таблица групп пользователей ProFTP и их членов
  2. users_ftp – Таблица пользователей сервера FTP
  3. quotalimits_ftp – Основная таблица квот доступа сервера FTP
  4. quotatallies_ftp – Интегральная таблица квот доступа сервера FTP
  5. errors_ftp – Логи ошибок работы сервера FTP
  6. access_ftp – Логи доступа к серверу FTP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
-- phpMyAdmin SQL Dump
-- version 2.11.8.1deb5+lenny7
--
-- Версия сервера: 5.0.51
-- Версия PHP: 5.2.6-1+lenny9
--
-- База данных: `proftpd`
--
-- --------------------------------------------------------
--
-- Структура таблицы `group_ftp`
--
CREATE TABLE IF NOT EXISTS `group_ftp` (
  `groupname` varchar(16) NOT NULL default '',
  `gid` int(11) NOT NULL default '65534',
  `members` varchar(16) NOT NULL default '',
  KEY `groupname` (`groupname`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Таблица групп пользователей ProFTP и их членов';
-- --------------------------------------------------------
--
-- Структура таблицы `users_ftp`
--
CREATE TABLE IF NOT EXISTS `users_ftp` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(20) NOT NULL,
  `password` varchar(50) NOT NULL,
  `descr` text character set koi8u NOT NULL,
  `groupname` varchar(24) NOT NULL,
  `uid` int(11) NOT NULL,
  `gid` int(11) NOT NULL,
  `homedir` varchar(50) NOT NULL,
  `shell` varchar(20) NOT NULL,
  `last_login` int(15) NOT NULL,
  `login_count` int(15) NOT NULL,
  `last_err_login` int(15) NOT NULL,
  `err_login_count` int(15) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Таблица пользователей сервера FTP';
--
-- Структура таблицы `access_ftp`
--
CREATE TABLE IF NOT EXISTS `access_ftp` (
  `id` int(32) NOT NULL auto_increment,
  `timestamp` int(15) NOT NULL,
  `user_name` varchar(64) NOT NULL,
  `file_and_path` tinytext NOT NULL,
  `bytes` int(15) NOT NULL default '0',
  `client_name` varchar(127) NOT NULL,
  `client_IP` varchar(15) NOT NULL,
  `client_command` varchar(5) NOT NULL,
  `send_time` varchar(9) NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Логи доступа к серверу FTP';
-- --------------------------------------------------------
--
-- Структура таблицы `errors_ftp`
--
CREATE TABLE IF NOT EXISTS `errors_ftp` (
  `id` int(32) NOT NULL auto_increment,
  `timestamp` int(15) NOT NULL,
  `user_name` varchar(64) NOT NULL,
  `file_and_path` tinytext NOT NULL,
  `client_name` varchar(127) NOT NULL,
  `client_IP` varchar(15) NOT NULL,
  `client_command` varchar(5) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Логи ошибок работы сервера FTP';
-- --------------------------------------------------------
--
-- Структура таблицы `quotalimits_ftp`
--
CREATE TABLE IF NOT EXISTS `quotalimits_ftp` (
  `id` int(32) NOT NULL auto_increment,
  `name` varchar(30) default NULL,
  `quota_type` enum('user','group','class','all') NOT NULL,
  `per_session` enum('false','true') NOT NULL,
  `limit_type` enum('soft','hard') NOT NULL,
  `bytes_in_avail` float NOT NULL,
  `bytes_out_avail` float NOT NULL,
  `bytes_xfer_avail` float NOT NULL,
  `files_in_avail` int(10) unsigned NOT NULL,
  `files_out_avail` int(10) unsigned NOT NULL,
  `files_xfer_avail` int(10) unsigned NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Основная таблица квот доступа сервера FTP';
-- --------------------------------------------------------
--
-- Структура таблицы `quotatallies_ftp`
--
CREATE TABLE IF NOT EXISTS `quotatallies_ftp` (
  `id` int(32) NOT NULL auto_increment,
  `name` varchar(30) NOT NULL,
  `quota_type` enum('user','group','class','all') NOT NULL,
  `bytes_in_used` float NOT NULL,
  `bytes_out_used` float NOT NULL,
  `bytes_xfer_used` float NOT NULL,
  `files_in_used` int(10) unsigned NOT NULL,
  `files_out_used` int(10) unsigned NOT NULL,
  `files_xfer_used` int(10) unsigned NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Интегральная таблица квот доступа сервера FTP';

[users_ftp]

id: уникальный номер
username: имя пользователя
password: пароль
descr: комментарий
groupname: группа
uid: uid
gid: gid
homedir: домашний каталог
shell: определяем шелл для пользователя
last_login: последний вход
login_count: количество входов
last_err_login: последний неудачный вход
err_login_count: количество неудачных входов

[quotalimits_ftp]

Добавить этот дамп БД можно любым доступным Вам способом (через phpMyadmin, webmin, через командную строку). Так как ftp сервер я ставлю в ряду первых, то phpMyAdmin (PMA) и Webmin еще не сконфигурирован, поэтому с учётом работы по ssh самым простым способом залить дамп-файл будет через перенаправление потока ввода:

1
2
debian:/# cd /srv/ftp/
debian:/# tee proftpd.sql

Копируем содержимое приведенного выше файла proftpd.sql в буфер обмена, нажимаем правую кнопку мыши в консоли putty и закрываем полученный файл с сохранением по Ctrl+C

Замечание: учтите только кодировку, в которой работает терминал putty. У меня это utf8, что совпадает с кодировкой БД, если же на вкладке настроек putty->window->Translation стоит отличная от utf8, то и кодировка файла созданного tee будет соответствующей.

Вносим дамп в БД:

1
2
debian:/# mysql -u proftpd -p proftpd < proftpd.sql
Enter password:

Теперь заполним созданную базу первичными данными для отладки. Создадим двух пользователей: demon с мягкой квотой в 1GB(1073741824 bytes), и admin – без квот.

Замечание: Обратите внимание, что оба этих пользователя будут относиться к виртуальной ftp-группе proftpd и наследовать ID-реального системного пользователя proftpd(105). Вы можете присваивать любой другой номер ID, не совпадающий с системными и создавать и помещать в любые другие группы, чтобы они не пересекались в “системном” пространстве.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
--
-- Дамп `users_ftp`, `group_ftp`, `quotatallies_ftp`, `quotalimits_ftp` для создания 2-х пользователей
--
USE `proftpd`;
INSERT INTO `users_ftp` (`id`, `username`, `password`, `descr`, `groupname`, `uid`, `gid`, `homedir`, `shell`, `last_login`, `login_count`, `last_err_login`, `err_login_count`) VALUES
(1, 'admin', '111', 'Администратор хостинга', 'proftpd', 105, 65534, '/var/www/public_html', '/bin/false', 0, 0, 0, 0),
(2, 'demon', '111', 'Администратор ftp хостинга', 'proftpd', 105, 65534, '/var/www/vhosts/site.ru', '/bin/false', 0, 0, 0, 0);
INSERT INTO `group_ftp` (`groupname`, `gid`, `members`) VALUES
('proftpd', 65534, 'admin, demon');
INSERT INTO `quotalimits_ftp` (`id`, `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
(1, 'demon', 'user', 'false', 'soft', 1073741824, 0, 0, 0, 0, 0);
INSERT INTO `quotatallies_ftp` (`id`, `name`, `quota_type`, `bytes_in_used`, `bytes_out_used`, `bytes_xfer_used`, `files_in_used`, `files_out_used`, `files_xfer_used`) VALUES
(1, 'demon', 'user', 0, 0, 0, 0, 0, 0);

Технический нюанс: Также обратите внимание, что при задействовании квот, необходимо внести записи в ДВЕ таблицы: quotalimits_ftp и quotatallies_ftp. Так как сам сервер у меня почему то отказался вносить эту запись самостоятельно при первом запуске. Тоесть, если Вы хотите задействовать квоты для пользователя – создавайте записи по аналогии в обоих таблицах – quotalimits_ftp и quotatallies_ftp, в одной устанавливайте квоту и тип, а в другой устанавливайте значение по нулям.

Замечание: Жёсткая квота (жесткий предел) жёстко оборвёт фаил при закачке по достижении заданного значения, мягкая квота (мягкий предел) позволит Вам дозакачать файл (что может привести к превышению на гигабайты!), а потом запретит закачивать, пока Вы не освободите достаточно места для операции.

Закачиваем в БД по аналогии с предыдущим дампом через перенаправление потока ввода:

1
2
debian:/# cd /home/ftp/
debian:/# tee proftpd_user.sql

Снова копируем содержимое приведенного выше файла proftpd_user.sql в буфер обмена, нажимаем правую кнопку мыши в консоли putty и закрываем полученный файл с сохранением по Ctrl+C. Вносим дамп в БД:

1
2
debian:/# mysql -u proftpd -p proftpd < proftpd_user.sql
Enter password:

Создаём директорию для пользователя `demon` и даём на неё права пользователю `proftpd`:

1
2
debian:/# mkdir -p /home/ftp/demon
debian:/# chown proftpd:nogroup  /home/ftp/demon

В версии ProFTPd 1.3.4a конфигурационные файлы поделены на несколько файлов. Проёдемся по ним по очереди, основной файл конфигурации /etc/proftpd/proftpd.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
debian:/# vim /etc/proftpd/proftpd.conf
ServerName  "ProFTPD Development server"
User    proftpd
Group   nogroup
TransferLog /var/log/proftpd/xferlog.log
SystemLog /var/log/proftpd/proftpd.log
# Нам надо чтобы ВСЕ пользователи по ftp были ограниченны своей домашней директорией, то надо раскомментировать
# следующую строку:
# DefaultRoot ~
# Здесь можете указать, кому можно иметь доступ ко всему серверу Можно указать отдельную группу
# или конкретных пользователей.
DefaultRoot ~ !demon
# Комментируем старый механизм квотирования
[...]
#<IfModule mod_quotatab.c>
#QuotaEngine off
#</IfModule>
[...]
# Alternative authentication frameworks
#
#Include /etc/proftpd/ldap.conf
Include /etc/proftpd/sql.conf
[...]

Теперь расскоментируем “альтернативный способ авторизации” наших клиентов в файле конфигурации /etc/proftpd/modules.conf:

1
debian:/# vim /etc/proftpd/modules.conf

… задействуем следующие модули:

1
2
3
4
5
6
7
8
9
10
[...]
# Install proftpd-mod-mysql or proftpd-mod-pgsql to use this
LoadModule mod_sql.c
[...]
# Install proftpd-mod-mysql to use this
LoadModule mod_sql_mysql.c
[...]
# Install proftpd-mod-pgsql or proftpd-mod-mysql to use this
LoadModule mod_quotatab_sql.c
[...]

В завершение разберемся, как устроен файл конфигурации /etc/proftpd/sql.conf… Принципиальных вариантов настройки SQL для этого сервера в интернете несколько. Основные отличия в использовании нестандартных полей в таблицах, чтобы расширить функциональность сервера. Например Вы можете использовать краткую форму указания параметров запроса для таблицы:

1
SQLUserInfo ftpuser userid passwd uid gid homedir shell

Или написать запрос самостоятельно, с указанием всех необходимых аргументов:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
debian:/# vim /etc/proftpd/sql.conf
#
# Proftpd configuration for SQL-based authentication.
# 20/04/2011
# (This is not to be used if you prefer a PAM-based SQL authentication)
#
<IfModule mod_sql.c>
#
# Choose a SQL backend among MySQL or PostgreSQL.
# Both modules are loaded in default configuration, so you have to specify the backend
# or comment out the unused module in /etc/proftpd/modules.conf.
# Use 'mysql' or 'poastgres' as possible values.
#
SQLBackend              mysql
# The passwords in MySQL are encrypted using CRYPT
# Тип авторизации (для начала будем хранить пароли открытым текстом, потом зашифруем)
SQLAuthTypes            Plaintext Crypt
# Кого и как аутентифицируем, можно указать конкретно группы,
# или создать группы для каждого клиента в таблице group_sql
SQLAuthenticate         users groups
# инфа для соединения с MySQL сервером:
# имя_БД@хост_где_БД:порт имя_пользователя_БД пароль
SQLConnectInfo proftpd@localhost:3306 proftpd proftpdPASSWORD
# 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 `users_ftp` `username` `password` `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 `group_ftp` `groupname` `gid` `members`
# set min UID and GID - otherwise these are 999 each
# Установите минимальный ID пользователя/группы который будет иметь возможность использовать наш FTP
SQLMinID        30
# Изменим пользователя и группу по умолчанию (65533:65533) на нашего пользователя 105(proftpd)
# и группу 65534(nogroup)
SQLDefaultUID   105
SQLDefaultGID   65534
# create a user's home directory on demand if it doesn't exist
CreateHome on
# Update count every time user logs in
# Записываем удачные логины в БД.
SQLLog PASS counter_login
SQLNamedQuery counter_login UPDATE "`last_login`=UNIX_TIMESTAMP(), `login_count`=`login_count`+1 \
WHERE `username`='%u'" `users_ftp`
# Записываем также неудачные логины в БД
SQLLog ERR_PASS counter_err
SQLNamedQuery counter_err UPDATE "`last_err_login`=UNIX_TIMESTAMP(), `err_login_count`=`err_login_count`+1 \
WHERE `username`='%U'" `users_ftp`
# Update modified everytime user uploads or deletes a file
# логируем что сохраняем работу с ftp данными
# %u - имя пользователя (с которым залогинился)
# %f - полный путь и имя файла который был скачан
# %b - число байт, которые были скачаны
# %h - имя клиента (из DNS), если не удалось разрешить - IP
# %a - IP-адрес клиента
# %m - имя команды полученной от клиента (RETR/STOR)
# %T - время (секунд) ушедшее на передачу файла клиенту
SQLLog RETR,STOR,DELE log_story_transfer
SQLNamedQuery log_story_transfer INSERT "'', UNIX_TIMESTAMP(),'%u', '%f', '%b', '%h', '%a', '%m', '%T'" `access_ftp`
# записываем ошибки при сохранении и чтении файлов
SQLLOG ERR_RETR,ERR_STOR,ERR_DELE,ERR_RMD,ERR_RNTO log_err_modify
SQLNamedQuery log_err_modify INSERT "'', UNIX_TIMESTAMP(), '%u', '%f', '%h', '%a', '%m'" `errors_ftp`
# Лог файл работы с SQL
SQLLogFile /var/log/proftpd/proftpd_sql.log
# User quotas
# Управление квотами
# ===========
QuotaEngine on
QuotaDirectoryTally on
# директива настраивает mod_quotatab принять каталоге операций (например, создание каталогов, удаление каталога)
# во внимание при подсчете
# Отображения информации квоты в мегабайтах
QuotaDisplayUnits Mb
# директиву можно использовать для включения / выключения mod_quotatab
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 quotalimits_ftp 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 quotatallies_ftp \
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}'" quotatallies_ftp
SQLNamedQuery insert-quota-tally INSERT "%{0}, %{1}, %{2}, %{3}, %{4}, %{5}, %{6}, %{7}" quotatallies_ftp
QuotaLimitTable sql:/get-quota-limit
QuotaTallyTable sql:/get-quota-tally/update-quota-tally/insert-quota-tally
QuotaLog /var/log/proftpd/proftpd_quota.log
RootLogin off
# Нужен ли реальный shell конектящимся юзерам (берутся из /etc/shells)
RequireValidShell off
</IfModule>

Примечание: Если вы не можете записать в ftp папку используя связку proftpd + mysql (ошибка 550) – проверьте права/владельца на папку и под каким пользователем/группой происходит запись. По умолчанию, proftpd пишет файлы как 65533:65533 и игнорирует то, что указано в /etc/proftpd/proftpd.conf. Соответственно, изменим пользователя и группу по умолчанию на нашего пользователя 105(proftpd) и зададим группу 65534(nogroup) именно в файле конфигурации /etc/proftpd/sql.conf:

1
2
SQLDefaultUID   105
SQLDefaultGID   65534

Перезапускаем сервис и смотрим логи на предмет ошибок.

1
2
3
debian:/# /etc/init.d/proftpd restart
Stopping ftp server: proftpd.
Starting ftp server: proftpd.

3. Тестирование начальной конфигурации

Проверим клиентом ftp, входящим в состав любой Widows. Попробуем залить файл на сервер.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Microsoft   Windows XP [Версия 5.1.2600]
(С) Корпорация Майкрософт,   1985-2001.
C:\Documents and Settings\Dmitry Vl.Ivanov>ftp 192.168.1.254
Связь с 192.168.1.254.
220 ProFTPD 1.3.1 Server (ProFTPD Home server) [::ffff:192.168.1.254]
Пользователь (192.168.1.254:(none)): demon
331 Password required for demon
Пароль:
230 User demon logged in
ftp> append
Локальный файл c:\test.rar
Удаленный файл test.rar
200 PORT command successful
150 Opening ASCII mode data connection for test.rar
226 Transfer complete
ftp: 559748 байт отправлено за 0,17 (сек) со скоростью 3254,35 (КБ/сек).
ftp> quit
221 Goodbye.

Прошло удачно? Не получилось? Читаем логи, проверяем разрешения на папки и пароли к БД MySQL и пароль ftp-пользователя.

4. Добавление виртуальных пользователей, расстановка прав

Всё работает? Отлично. Теперь небольшая цель-задача: Есть программист php сайта site.ru, которому нужен доступ к своему сайту со всеми правами – дадим ему это право:

Добавляем нового пользователя БД нашего FTP сервера:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
debian:/# mysql -u proftpd -p
Enter password:
USE `proftpd`;
INSERT INTO   `users_ftp` (`username`, `password`, `descr`, `groupname`, `uid`, `gid`,   `homedir`, `shell`, `last_login`, `login_count`, `last_err_login`, `err_login_count`) VALUES
('developer', 'PASSWORD', 'PHP developer',   'proftpd', 105, 33, '/var/www/vhosts/site.ru/', '/bin/false', 0, 0, 0, 0);
INSERT INTO `group_ftp` (`groupname`, `gid`, `members`) VALUES ('www-data', 33, 'developer');
INSERT INTO `quotalimits_ftp` (`id`, `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
(2, 'developer', 'user', 'false', 'soft', 157286400, 0, 0, 0, 0, 0);
INSERT INTO `quotatallies_ftp` (`id`, `name`, `quota_type`, `bytes_in_used`, `bytes_out_used`, `bytes_xfer_used`, `files_in_used`, `files_out_used`, `files_xfer_used`) VALUES
(2, 'developer', 'user', 0, 0, 0, 0, 0, 0);

Не забывайте про гибкий механизм прав доступа. Вы можете гибко выбирать от имени какого системного пользователя будет записывать в папку наш “виртуальный” пользователь и какую группу он будет использовать…

В частности, наш гипотетический девелопер будет создавать новые файлы в своей папке помеченные владельцем как proftpd:www-data (105:33). Если данная папка (домашняя папка виртуального пользователя proftpd) не создана, сервер proftpd создаст ёё самостоятельно. Однако, не забудем подправить права на предоставленную пользователю proftpd папку. Для начала выставим группу и владельца для папки, где хранится сайт, изменяем владельца и/или группу для указанных файлов и директорий, рекурсивно:

1
server:~# chown -v -R proftpd:www-data /var/www/vhosts/site.ru/

Подправим права доступа к файлам и папкам, рекурсивно (если надо):

1
server:~# chmod -R 775 /var/www/vhosts/site.ru/

Если вас беспокоит безопасность, подправим права на отдельные типы файлов:

1
2
server:~# find /home/vhosts/site.ru/ -type f -name '*.php' -exec chmod 644 {} \;
server:~# find /home/vhosts/site.ru/ -type f -name '.htaccess' -exec chmod 600 {}   \;

5. Увеличиваем безопасность proFTPD ftp-сервера, необходимо-достаточный тюнинг серверя для типового хостинга (опционально)

Для этого проверим и установим некоторые дополнительные параметры в конфигурационном файле /etc/proftpd/proftpd.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
server:~# vim /etc/proftpd/proftpd.conf
# Если вошел, но не начал передачу в течении 300 сек - выход
TimeoutNoTransfer 300
# Устанавливает  тайм-аут  на подвисшую загрузку
TimeoutStalled 600
# Накладываем ограничения
# Если никаких действий после входа в течении 600 сек - выход
TimeoutIdle 600
# Максимальное число `детей` (работает только в standalohe режиме)
# необходимо для защиты от атак типа `отказ в обслуживании` да и
# от перегрузки сервера поможет 🙂
MaxInstances 30
# На авторизацию отводится 300 сек, иначе разрыв
TimeoutLogin 300
# Задаём размер-очереди
tcpBackLog 5
# Максимальное количество клиентов и ошибку в случае превышения
MaxClients 10 "Слишком много соединений с сервером (%m)"
# Максимальное количество клиентов с одного хоста
MaxClientsPerHost 4 "%m клиента уже подключены с Вашего хоста, больше не разрешено"
# допускаемое число попыток ввести пароль
MaxLoginAttempts 3 "Слишком много попыток войти"

Примечание: Если Вы хотите, чтобы отображались скрытые файлы (начинающиеся с точки) используйте директивы Directory и ListOptions:

1
ListOptions -a

Разрешать ли для всех подряд работу со скрытыми файлами – всё же решать Вам, но лучше использовать разрешения для отдельно взятых ресурсов.

Примечание: Для того, чтобы у Вас работала докачка файлов на ftp сервер, используйте директиву AllowStoreRestart. Поместите её в файл конфигурации /etc/proftpd/proftpd.conf:

1
AllowStoreRestart on

Не забудьте перезапустить сервер proFTPD.

Поиск решений ошибок proftpd: если Вы столкнулись с ошибкой proftpd[16632]: mod_tls_memcache/0.1: notice: unable to register ‘memcache’ SSL session cache: Memcache support not enabled, отключите этот модуль в /etc/proftpd/modules.conf:

1
#LoadModule mod_tls_memcache.c

Или настройте memcache для proftpd как описано в руководстве – ProFTPD mini-HOWTO – ProFTPD and Memcache… Не забудьте перезапустить сервер proFTPD.

6. Добавляем сертификат SSL к нашему серверу proftpd

Для начала сгенерируем сертификат:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server:~# openssl req -new -x509 -days 365 -nodes -out /etc/ssl/certs/proftpd.cert.pem -keyout /etc/ssl/private/proftpd.key.pem
Generating a 1024 bit RSA private key
.......................++++++
.............++++++
writing new private key to '/etc/ssl/certs/proftpd.key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:RU
State or Province Name (full name) [Some-State]:Russia
Locality Name (eg, city) []:Russia
Organization Name (eg, company) [Internet Widgits Pty Ltd]:site.ru
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:ftp.site.ru
Email Address []:root@domain.ru

Подправим права на вновь-созданный сертификат:

1
2
debian:/# chmod 600 /etc/ssl/private/proftpd.key.pem
debian:/# chmod 640 /etc/ssl/certs/proftpd.cert.pem

Отредактируем конфигурационный файл /etc/proftpd/tls.conf:

1
2
3
4
5
6
7
8
9
10
11
debian:/# vim /etc/proftpd/tls.conf
TLSEngine on
TLSLog /var/log/proftpd/proftpd_tls.log
TLSProtocol SSLv23
TLSOptions NoCertRequest EnableDiags
TLSOptions AllowClientRenegotioations
TLSRSACertificateFile /etc/ssl/certs/proftpd.cert.pem
TLSRSACertificateKeyFile /etc/ssl/private/proftpd.key.pem
TLSVerifyClient off
TLSRequired off

Замечанние: Если вы указали опцию TLSRequired on, то для подключения к FTP возможен только доступ с использованием TLS (другие пользователи с старыми FTP клиентами не поддерживающими TLS подключиться не смогут); но закомментировав эту опцию или установим значение в TLSRequired off к FTP можно будет подключаться и используя TLS и обычным способом.

Включаем TLS в конфигурационном файле /etc/proftpd/proftpd.conf:

1
2
3
4
5
6
debian:/# vim /etc/proftpd/proftpd.conf
#
# This is used for FTPS connections
#
Include /etc/proftpd/tls.conf

Перезапускаем сервис и смотрим логи на предмет ошибок.

1
2
3
debian:/# /etc/init.d/proftpd restart
Stopping ftp server: proftpd.
Starting ftp server: proftpd.

7. Шифруем Palintext пароли в БД

1
2
3
4
5
debian:/# mysql -u proftpd -p
Enter password:
USE `proftpd`;
UPDATE `users_ftp` SET `password` = PASSWORD(`password`);

Заметьте, ничего в этой команде менять не надо, она самостоятельно, с помощью функции PASSWORD() зашифрует пароли и поменяет их. ВАЖНО! Процедура одностороняя, поэтому если в базе пользователей много, сделайте бэкап.

Допишем (если её нет) в файле /etc/proftpd/sql.conf в опцию SQLAuthTypes ключ Backend:

1
SQLAuthTypes Backend Plaintext

И перезапустим сервер.

1
2
3
debian:/# /etc/init.d/proftpd restart
Stopping ftp server: proftpd.
Starting ftp server: proftpd.

Теперь можно хранить в базе как шифрованные, так и не шифрованные пароли. Но я настоятельно рекомендую отказаться от аутентификации Plaintext