Настройка сервера на базе Debin 9 для Web-хостинга сайтов (nginx + php-fpm7 + pure-ftpd + phpmyadmin)

В Интернете десятки, а может даже и сотни статей о настройке Linux серверов для хостинга Web-сайтов, что же такого нового в этой статье?

Все просто — эта статья наиболее актуальна на текущий момент, все что в ней описано было сделано на реальном сервере который вводился в эксплуатацию для хостинга небольшого Интернет-магазина (суточная посещаемость — примерно 2000 уникальных посетителей).

Итак приступим к настройке.

Исходные данные:
VPS сервер, арендованный в ihor.ru (4 CPU, 3 GB RAM, 40 GB SSD)
На сервере установлена ОС Debian 9 (minimal)
Задача:
Настроить сервер для Web-хостинга сайта Интернет-магазина, в качестве Web-сервера использовать Nginx, в качестве бэкенда — php-fpm7, в качестве ftp-сервера — pure-ftpd с локальной базой пользователей, из дополнительного софта для разработчиков развернуть phpMyAdmin.

1. Базовая настройка Debian 9.

Обновляем систему до последней версии:

apt-get update
apt-get upgrade

Устанавливаем правильную часовую зону (Asia/Yekaterinburg):

dpkg-reconfigure tzdata 

Устанавливаем вспомогательные пакеты (все они понадобятся нам в дальнейшем):

apt-get -y install binutils vim dirmngr git net-tools dnsutils wget curl unzip sudo

Добавим настройки среды для пользователя root (опционально, Вы можете это не делать):

sed -i 's/.*"syntax on.*/syntax on/' /etc/vim/vimrc
echo 'vnoremap :w !xsel -b' >> ~/.vimrc
cat <<EOT >> ~/.bashrc
export HISTSIZE=10000
export HISTFILESIZE=10000
export HISTCONTROL=ignoreboth:erasedups
PROMPT_COMMAND='history -a'
export HISTIGNORE='ls:ps:history*'
export HISTTIMEFORMAT='%d.%m.%Y %H:%M:%S: '
alias vi='vim'
PS1='\n\[\e[0;33m\][\D{%d.%m.%Y %H:%M:%S}] \[\e[01;31m\]\u@\h \[\e[1;34m\]\w\n\\$ \[\e[0;32m\]\[\e[0m\]'
EOT
source ~/.bashrc

Указанные выше настройки среды делают следующее (Многие из них описаны в моей статье про ведение истории команд):
1. Включают подсветку синтаксиса в vim;
2. Включают возможность копировать текст открытый в vim с помощью выделения его мышкой в терминале Putty.
3. При вызове vi будет запускаться редактор vim;
4. Устанавливают настройки хранения и вывода истории команд в консоле;
5. Изменяют командную строку терминала;

Идем далее.

Добавляем пользователя под которым будем входить на сервер в дальнейшем:

adduser --gecos "Mikhail Grigorev" mgrigorev

Настраиваем sudo для нашего пользователя:

echo "mgrigorev $(hostname)=(root) PASSWD: $(which su)" >> /etc/sudoers

Хочу обратить Ваше внимание на формат добавляемой строки в файл /etc/sudoers, обычно многие администраторы добавляют такую строку:

mgrigorev ALL=(ALL) NOPASSWD: ALL

Это неправильно и нарушает безопасность сервера, никогда так не делайте!
Обязательно указывайте вместо первого ALL имя сервера, а вместо второго ALL логин пользователя с правами которого Вы запустите команду из sudo.
Так же не следует указывать NOPASSWD, т.к. таким образом для выполнения sudo не будет запрошен пароль пользователя, а значит — это потенциальная возможность для злоумышленника получить полные привилегии на сервер без знания вашего пароля.
И вместо последнего ALL всегда указывайте какую конкретно команду Вы разрешаете выполнить пользователю с повышеными привилегиями, не нужно давать пользователю право на все команды, дайте только на те, которые действительно нужны.

Итак, наша правильная строка выглядит так:

mgrigorev $(hostname)=(root) PASSWD: /bin/su

$(hostname) будет заменено на имя сервера и в файл /etc/sudoers добавиться строка:

mgrigorev myserver.ru=(root) PASSWD: /bin/su

то есть, мы дали пользователю mgrigorev право выполнить команду su с правами пользователя root и только с нашего сервера myserver.ru и обязательно с запросом пароля пользователя mgrigorev.

Проверяем коректность настроек sudo:

visudo -c

Результат:

/etc/sudoers: parsed OK
/etc/sudoers.d/README: parsed OK

Теперь заходим на наш сервер через Putty под пользователем mgrigorev и добавляем свой публичный ssh-ключ:

mkdir .ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOaFVMOr2pRv7FnjjJhDpS2yf1haCP9GD6yupi2E+cWW mikhail.grigorev.ed25519" > ~/.ssh/authorized_keys

Разлогиневаемся и пробуем зайти по ssh-ключу, если после подключения к серверу у Вас не был запрошен пароль и в окне Putty при подключении было написано:

Using username "mgrigorev".
Authenticating with public key "mikhail.grigorev.ed25519" from agent
...

то Вы авторизовались по ssh-ключу.

Пробуем перейти в привилигерованный режим выполнив команду:

sudo su -

Обратите вниание на знак ‘-‘ после su, он не просто так написан, указав ‘-‘ при получении доступа под root мы установим все переменные среды именно пользователя root.
Если мы не укажем знак ‘-‘ , то некоторые переменные среды унаследуются от нашего пользователя mgrigorev, что в последствии может сыграть злую шутку.

Будет запрошен пароль пользователя mgrigorev, вводим его и мы должны увидеть приглашение вида:

root@myserver:~#

Если все получилось, то отключаем возможность входа на сервер под пользователем root:

sed -i "s/PermitRootLogin yes/PermitRootLogin no/g" /etc/ssh/sshd_config

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

sed -i "s/#PasswordAuthentication yes/PasswordAuthentication no/g" /etc/ssh/sshd_config

Перезапустим sshd:

/etc/init.d/ssh restart

2. Установка БД MariaDB 10.3

Я не буду останавливаться на установке и первоначальной настройки MariaDB 10.3, т.к. у меня в блоге есть отдельная полная статья на эту тему, на данном сервере я все делал как в статье.

3. Установка и базовая настройка Nginx

Скачиваем и добавляем ключ Nginx Inc. на нашу систему:

wget --quiet -O - http://nginx.org/keys/nginx_signing.key | apt-key add -

Если нужно установить Nginx из ветки Stable, то выполняем:

echo "deb http://nginx.org/packages/debian/ $(lsb_release -sc) nginx">/etc/apt/sources.list.d/nginx.list
echo "deb-src http://nginx.org/packages/debian/ $(lsb_release -sc) nginx">>/etc/apt/sources.list.d/nginx.list

Если нужно установить Nginx из ветки Mainline, то выполняем:

echo "deb http://nginx.org/packages/mainline/debian/ $(lsb_release -sc) nginx">/etc/apt/sources.list.d/nginx.list
echo "deb-src http://nginx.org/packages/mainline/debian/ $(lsb_release -sc) nginx">>/etc/apt/sources.list.d/nginx.list

Обновляем список пакетов:

apt-get update

Устанавливаем Nginx и OpenSSL (опционально):

apt-get -y install nginx
apt-get -y install openssl

Запускаем Nginx:

systemctl start nginx

Проверим:

root@myserver:~# systemctl status nginx
● nginx.service - nginx - high performance web server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2018-07-21 23:40:38 +05; 4s ago
     Docs: http://nginx.org/en/docs/
  Process: 25891 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
 Main PID: 25892 (nginx)
    Tasks: 2 (limit: 4915)
   CGroup: /system.slice/nginx.service
           ├─25892 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
           └─25893 nginx: worker process

Проверим открытые порты:

netstat -ltupn | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      25892/nginx: master

Теперь займемся базовой настройкой Nginx.

Создадим директорию для хранения SSL сертификатов и DH-ключей, а также создаем файл с параметрами для DHE-шифров:

mkdir /etc/nginx/ssl/
openssl dhparam -out /etc/nginx/ssl/dhparams.pem 2048

2048 бит выбраны не случайно, это разумный компромисс между безопасностью, оптимальной нагрузкой на CPU и скоростью работы. Если Вы думаете, что 2048 бит недостаточно, то Вы ошибаетесь, авторы атаки Logjam говорят, что простое число размеров 2048 бит и более не взламываемое при текущем уровне развития техники.

Создадим директории для хранения настроек Web-сайтов:

mkdir /etc/nginx/sites-available
mkdir /etc/nginx/sites-enabled

Я приведу базовый эталонный файл настроек который использую я на 99% серверов, рекомендую использовать его с дополнительными Вашими правками под конкретные нужды. В файле присутствуют комментарии для многих параметров.

Скачать уже готовый файл для Nginx версии 1.13.x (1.15.x) и выше Вы можете командой:

wget https://gist.githubusercontent.com/CHERTS/8e9ecf4fbfb765556311a88e5106174b/raw/nginx.conf -O /etc/nginx/nginx.conf

После того, как мы сохранили наш новый файл настроек nginx.conf проверим конфигурацию Nginx:

nginx -t

Если ошибок нет, то выполняем (это заставит Nginx перечитать конфигурацию):

nginx -s reload

Меняем системные лимиты на кол.открытых файлов.

Т.к. мы указали в nginx.conf параметр worker_rlimit_nofile = 10000, то будем исходить из него.

Традиционно во всех статьях в Интернет все меняют лимиты через редактирование файла /etc/security/limits.conf, но это неправильно, т.к. для Debian 8 и Debian 9 этот файл не работает.

В Debian 8 и Debian 9 используется система инициализации systemd и поэтому лимиты на максимальное количество открытых файлов нужно настроить для systemd, для этого выполняем:

mkdir -p /lib/systemd/system/nginx.service.d/
echo "[Service]" >/lib/systemd/system/nginx.service.d/limit.conf
echo "LimitNOFILE=10000" >>/lib/systemd/system/nginx.service.d/limit.conf
systemctl daemon-reload
systemctl restart nginx

Теперь проверим лимиты, для этого смотрим строку «Max open files» в выводе:

root@myserver:~# cat /proc/$(cat /var/run/nginx.pid)/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        0                    unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             11960                11960                processes
Max open files            10000                10000                files
Max locked memory         65536                65536                bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       11960                11960                signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

Все отлично! Nginx работает, лимит открытых файлов мы поменяли.

4. Установка и базовая настройка PHP 7.0 и PHP-FPM

Установим все необходимые пакеты:

apt-get -y install php-fpm php-mysql php-curl php-gd php-imagick php-imap php-intl php-mcrypt php-mbstring php-memcache php-memcached php-xml php-zip php-bz2

Отредактируем некоторые настройки PHP (cli):

PHPVER=7.0
sed -i "s/error_reporting = .*/error_reporting = E_ALL/" /etc/php/${PHPVER}/cli/php.ini
sed -i "s/display_errors = .*/display_errors = On/" /etc/php/${PHPVER}/cli/php.ini
sed -i "s/memory_limit = .*/memory_limit = 128M/" /etc/php/${PHPVER}/cli/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/Moscow/" /etc/php/${PHPVER}/cli/php.ini

Отредактируем некоторые настройки PHP (fpm):

PHPVER=7.0
sed -i "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/" /etc/php/${PHPVER}/fpm/php.ini
sed -i "s/memory_limit = .*/memory_limit = 128M/" /etc/php/${PHPVER}/fpm/php.ini
sed -i "s/upload_max_filesize = .*/upload_max_filesize = 64M/" /etc/php/${PHPVER}/fpm/php.ini
sed -i "s/post_max_size = .*/post_max_size = 64M/" /etc/php/${PHPVER}/fpm/php.ini
sed -i "s/;date.timezone.*/date.timezone = Europe\/Moscow/" /etc/php/${PHPVER}/fpm/php.ini

Мы установили следующие базовые настройки для php (cli):

error_reporting = E_ALL
display_errors = On
memory_limit = 128M
date.timezone = Europe/Moscow

И установили базовые настройки для php (fpm), которые будут применяться для всех php-fpm пулов по умолчанию:

cgi.fix_pathinfo=0
memory_limit = 128M
upload_max_filesize = 64M
post_max_size = 64M
date.timezone = Europe/Moscow

Вы можете дописать необходимые Вам настройки.

5. Создание и настройка площадки для сайта

Далее следовало бы написать огромную кучу команд для создания отдельного пользователя и группы для работы отдельного пула php-fpm от имени этого пользователя, создания php-fpm пула с минимумом настроек, создания иерархии каталогов для размещения сайта, выставления правильных прав на эти каталоги, настройка файла конфигурации нашего сайта для Nginx, создания файла для ротации логов Nginx и т.д.
Но для автоматизации всей этой рутины я написал 2 простых скрипта на bash, они открыты и размещены у меня на github.com

Скачиваем мои скрипты и распаковываем:

wget https://github.com/CHERTS/linux-scripts/archive/master.zip
unzip master.zip && rm -f master.zip
cd linux-scripts-master/nginx/
chmod a+x *.sh

Теперь создадим все необходимое для хостинга сайта mysite.ru (у Вас будет другой домен):

./nginx-create-vhost.sh -d mysite.ru

Результат работы скрипта:

Detecting your OS       Linux (x86_64)
Detecting Linux distrib Debian (SYSTEMD)
Detecting your php-fpm  Found php-fpm7.0
Detecting nginx owner   Found www-data
Set new username:       web1
Set new groupname:      client1
Set nginx hostname:     mysite.ru
Set nginx vhost ip:     194.XX.XX.XX:80
Adding new user web1...                         Done
Adding new group client1...                     Done
Adding user web1 to group client1...    	    Done
Adding user www-data to group client1...        Done
Create a home directory...                      Done
Create web,log,tmp,private directory...         Done
Create index.html...                            Done
Create robots.txt...                            Done
Set permition to directory...                   Done
Set protected attribute to directory...         Done
Create php-fpm config file web1.conf...         Done
Configtest php-fpm...                           Done
Restart php-fpm...                              Done
Create nginx config file...                     Done
Activate nginx config file...                   Done
Nginx configtest...                             Done
Reload nginx...                                 Done
Create logrotate rule...                        Done

Что делает этот скрипт ?

Он выполняет вот такие команды на основе введенных данных и файла настройки /etc/nginx/settings.conf:

# Создание пользователя web1 и группы client1
useradd -d /var/www/mysite.ru -s /bin/false web1
addgroup client1
usermod -a -G client1 web1
usermod -a -G client1 www-data
# Создания дерева каталогов для размещения web-сайта, логов nginx и временного каталога
# для php-fpm и копирование заглушки сайта (index.html и robots.txt)
mkdir -p /var/www/mysite.ru
mkdir -p /var/www/mysite.ru/{web,log,private,tmp}
cp template/index.html.template /var/www/mysite.ru/web/index.html
sed -i 's/!SITENAME!/mysite.ru/g' /var/www/mysite.ru/web/index.html
cp template/robots.txt.template /var/www/mysite.ru/web/robots.txt
# Выставление нужных прав на каталоги web-сайта
chmod -R 755 /var/www/mysite.ru
chmod -R 770 /var/www/mysite.ru/tmp
chmod -R 755 /var/www/mysite.ru/web
chmod -R 710 /var/www/mysite.ru/private
chown -R web1:client1 /var/www/mysite.ru
chown root:root /var/www/mysite.ru
chown root:root /var/www/mysite.ru/log
chattr +a /var/www/mysite.ru
# Создание типового файла настроек пулы php-fpm на основе шаблона, перезапуск php-fpm
cp template/php_fpm.conf.template /etc/php/7.0/fpm/pool.d/web1.conf
sed -i 's/!SITEDIR!/\/var\/www\/mysite.ru/g' /etc/php/7.0/fpm/pool.d/web1.conf
sed -i 's/!USERLOGINNAME!/web1/g' /etc/php/7.0/fpm/pool.d/web1.conf
sed -i 's/!GROUPNAME!/client1/g' /etc/php/7.0/fpm/pool.d/web1.conf
sed -i 's/!PHPFPMSOCKDIR!/\/run\/php/g' /etc/php/7.0/fpm/pool.d/web1.conf
/usr/sbin/php-fpm7.0 -t
systemctl restart php7.0-fpm
# Создание типового файла настроек nginx на основе шаблона, перезапуск nginx
cp template/nginx_virtual_host.template /etc/nginx/sites-available/mysite.ru.vhost
sed -i 's/!SERVERIP!/195.XX.XX.XX/g' /etc/nginx/sites-available/mysite.ru.vhost
sed -i 's/!SERVERPORT!/80/g' /etc/nginx/sites-available/mysite.ru.vhost
sed -i 's/!SITENAME!/mysite.ru/g' /etc/nginx/sites-available/mysite.ru.vhost
sed -i 's/!SITEDIR!/\/var\/www\/mysite.ru/g' /etc/nginx/sites-available/mysite.ru.vhost
sed -i 's/!PHPFPMSOCKDIR!/\/run\/php/g' /etc/nginx/sites-available/mysite.ru.vhost
sed -i 's/!USERLOGINNAME!/web1/g' /etc/nginx/sites-available/mysite.ru.vhost
ln -s /etc/nginx/sites-available/mysite.ru.vhost /etc/nginx/sites-enabled/100-mysite.ru.vhost
nginx -t
nginx -s reload
# Создания правила ротации логов nginx
cat <<EOT > /etc/logrotate.d/web2
/var/www/mysite.ru/log/access.log /var/www/mysite.ru/log/error.log {
    create 0644 www-data root
    daily
    rotate 10
    missingok
    notifempty
    compress
    sharedscripts
    postrotate
        [ ! -f /var/run/nginx.pid ] || kill -USR1 \`cat /var/run/nginx.pid\`
    endscript
}
EOT

Как видите, скрипт делает довольно много работы, а главное делает он ее с предварительной проверкой многих параметров системы. А после выполнения практический каждой команды он проверяет результат ее выполнения и если что-то пойдет не так, то выполнение будет остановлено.
Именно из-за необходимости выполнения большого числа рутиных команд я и написал скрипт автоматизации nginx-create-vhost.sh

Скрипт ./nginx-create-vhost.sh создает следующую иерархию каталогов для размещения web-сайта:

/var/www - это корневой каталог для размещения всех сайтов
       |
       |- mysite.ru
       |          |-web      - каталог для размещения файлов сайта mysite.ru (php-скрипты, js,css и другие файлы)
       |          |-log      - каталог в котором будут лежать лог-файлы web-сервера nginx (acces.log и error.log)
       |          |-tmp      - каталог для размещения временных файлов php (файлы сессий и прочее)
       |          |-private  - каталог для размещения файлов скриптов (php) доступных для выполнения через директиву open_basedir
       |
       |- mysite2.ru
                   |-web
....

Все файлы конфигурации Nginx будут создаваться в каталоге /etc/nginx/sites-available
Все активные сайты активируются путем создания симлинка в каталоге /etc/nginx/sites-enabled на соответствующий файл в /etc/nginx/sites-available
Все файлы настроек пулов php-fpm для Debian 9 будут создаваться в каталоге /etc/php/7.0/fpm/pool.d, для Debian 8 или Oracle Linux каталоги будут другие.
Все файлы правил ротации логов будут создаваться в каталоге /etc/logrotate.d

Ниже представлен типовой файл настроек Nginx (/etc/nginx/sites-available/mysite.ru.vhost)
Файлы называются по имени сайта с добавлением расширения vhost.
Вы можете изменить шаблон файла template/nginx_virtual_host.template на основе которого создается конфигурация vhost.

server {
        listen 194.XX.XX.XX:80;
        server_name mysite.ru www.mysite.ru;
        root /var/www/mysite.ru/web;

        index index.php index.html index.htm;

        error_log /var/www/mysite.ru/log/error.log;
        access_log /var/www/mysite.ru/log/access.log main;

        set $fastcgipass unix:/run/php/web1.sock;

        if ( $args ~ "_SERVER|_GLOBALS|DOCUMENT_ROOT|INCLUDE_FOLDER|ROOT_FOLDER|FILES_FOLDER|MODULE_FOLDER|ADMIN_FOLDER|TMP_FOLDER" ) { return 500; }

        location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|mov)$ {
                charset utf-8;
                expires 14d;
                access_log off;
                log_not_found off;
        }

        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        location /ng1nx_statuz {
                stub_status on;
                access_log off;
                allow all;
        }

        location / {
                try_files $uri $uri/ /index.php;
        }

        location ~ \.php$ {
                try_files       $uri = 404;
                fastcgi_pass    $fastcgipass;
                fastcgi_param   HTTPS $fastcgi_https;
                fastcgi_index   index.php;
                fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include         /etc/nginx/fastcgi_params;
        }

}

Это минимально необходимый файл конфигурации Nginx, для того, чтобы заработали php-скрипты на сайте.
Вы можете его изменять и добавлять нужные Вам директивы.

Например если у Вас сайт на WordPress, то файл может принять такой вид (привожу только часть блоков location):

....
        location ~* /(images|logs|tmp)/.*\.(php|pl|py|jsp|asp|sh|cgi)$ {
                deny all;
                access_log off;
                log_not_found off;
        }

        location ~* /wp-content/.*\.php$ {
                deny all;
                access_log off;
                log_not_found off;
        }

        location ~* /(?:uploads|files)/.*\.php$ {
                deny all;
                access_log off;
                log_not_found off;
        }

        location = /wp-config.php {
                deny all;
                access_log off;
                log_not_found off;
        }

        location = /xmlrpc.php {
                deny all;
                access_log off;
                log_not_found off;
        }

        location / {
                try_files       $uri $uri/ /index.php;
        }

        location ~ \.php$ {
                try_files       $uri @cms;
                include         /etc/nginx/fastcgi_params;
                fastcgi_param   HTTPS $fastcgi_https;
                fastcgi_pass    $fastcgipass;
                fastcgi_index   index.php;
                fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
        }

        location @cms {
                fastcgi_pass    $fastcgipass;
                fastcgi_param   HTTPS $fastcgi_https;
                fastcgi_index   index.php;
                fastcgi_param   SCRIPT_FILENAME $document_root/index.php;
                include         /etc/nginx/fastcgi_params;
        }
....

После изменения файла конфигурации Nginx не забудьте проверить конфигурацию и перезагрузить ее:

nginx -t && nginx -s reload

Ниже представлен типовой файл настроек пула php-fpm (/etc/php/7.0/fpm/pool.d/web1.conf)
Файлы пула называются по логину создаваемого пользователя от имени которого данный пул будет работать.
Вы можете изменить файл шаблона template/php_fpm.conf.template на основе которого создаются настройки пула php-fpm.

[web1]

listen = /run/php/web1.sock
listen.owner = web1
listen.group = client1
listen.mode = 0660

user = web1
group = client1

pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 5
pm.max_requests = 500
request_terminate_timeout = 15m
request_slowlog_timeout = 5s
slowlog = /var/www/mysite.ru/log/php-slow.log

chdir = /

php_admin_value[open_basedir] = /var/www/mysite.ru/web:/var/www/mysite.ru/private:/var/www/mysite.ru/tmp:/usr/share/php5:/usr/share/php:/tmp:/usr/share/phpmyadmin:/etc/phpmyadmin:/var/lib/phpmyadmin
php_admin_value[session.save_path] = /var/www/mysite.ru/tmp
php_admin_value[upload_tmp_dir] = /var/www/mysite.ru/tmp
php_admin_flag[cgi.fix_pathinfo] = off
php_admin_value[error_log] = /var/www/mysite.ru/log/php-error.log

Вы можете добавлять в этот файл уникальные для каждого сайта настройки php, например увеличим лимит памяти (memory_limit) для сайта, для этого добавим в файл /etc/php/7.0/fpm/pool.d/web1.conf настройку

php_admin_value[memory_limit] = 256M

Проверим корректность настроек и перезапустим php-fpm (для Debian 9):

php-fpm7.0 -t
systemctl restart php7.0-fpm

Так же в комплекте со скриптом создания типовой хостинговой площадки (nginx-create-vhost.sh) идет скрипт ее удаления — nginx-remove-vhost.sh
Скрипту удаления площадки (nginx-remove-vhost.sh) нужно указать чуть больше настроек (нужно указать имя сайта, логин пользователя и имя группы), например:

Посмотрим какому пользователю и группе принадлежит сайт:

ls -l /var/www/mysite.ru
total 16
drwxr-xr-x 2 root root    4096 Aug  6 15:45 log
drwx--x--- 2 web1 client1 4096 Aug  6 15:45 private
drwxrwx--- 2 web1 client1 4096 Aug  6 15:45 tmp
drwxr-xr-x 2 web1 client1 4096 Aug  6 15:45 web

Удалим каталог сайта, все настройки php-fpm, nginx, logrotate, а так же пользователя и группу с правами которой работал php-fpm:

./nginx-remove-vhost.sh -d mysite.ru -u web1 -g client1

Результат:

Detecting your OS       Linux (x86_64)
Detecting Linux distrib Debian (SYSTEMD)
Detecting your php-fpm  Found php-fpm7.0
Delete php-fpm config file web1.conf...         Done
Configtest php-fpm...                           Done
Restart php-fpm...                              Done
Deactivate nginx config file...                 Done
Delete nginx config file...                     Done
Nginx configtest...                             Done
Reload nginx...                                 Done
Delete logrotate rule...                        Done
Unset protected attribute to directory...       Done
Delete site directory...                        Done
Delete group client1...                         Done
Delete user web1...                             Done

ВНИМАНИЕ! Скрипт nginx-remove-vhost.sh удаляет все настройки созданные скриптом nginx-create-vhost.sh включая каталог с сайтом, логами и т.п., он не спросит подтверждения, он удалит тот каталог в /var/www что Вы укажите в опции -d и удалит пользователя и группу указанные в опциях -u и -g

6. Расширенная настройка Nginx

Почему я выделил эти настройки в отдельный пункт и что сюда входит ?

При настройке работы Nginx многие администраторы не уделяют должного внимания таким вещам как порядок обработки запросов web-сервером Nginx и правильная настройка default_server. В результате когда у Вас на сервере размещается несколько сайтов и Вы случайно заходите на сайт не по доменному имени, а например по IP адресу Вашего web-сервера и получает страницу «Welcome to Nginx» или еще хуже того — страницу случайного сайта, расположенного на Вашем сервере.

Чтобы этого избежать нужно настроить default_server на Nginx — это тот виртуальный сервер, который Nginx будет использовать для обработки HTTP-запросов в поле Host которых указан сервер не подходящий под Ваши существующие настройки или отсутствующий у Вас в настройках в принципе.

Например, у вашего сервера IP адрес 194.10.12.13 (для примера), для сайтов mysite1.ru, mysite2.ru и mysite3.ru в качестве A-записи указан Ваш IP адрес 194.10.12.13. Для сайтов mysite1.ru и mysite2.ru у Вас создан виртуальный сервер Nginx (есть конфиг), а вот для mysite3.ru не создан виртуальный сервер. Тогда если Вы откроете в браузере mysite3.ru, то получите либо страницу «Welcome to Nginx», либо откроется первый из сайтов расположенных на Вашем сервере (первый, это тот чей виртуальный сервер будет первым в списке на обработку запросов у Nginx).

Чтобы этого избежать нужно создать виртуальный сервер по умолчанию, который будет обрабатывать все неизвестные запросы, как правило обрабатывать эти запросы не нужно, т.к. это создаст дополнительную нагрузку на Ваш web-сервер, правильнее всего все эти соединения закрывать. Для этого разработчики Nginx придумали специальный код 444 (его нет в стандарте HTTP), который закрывает соединение.

Итак правильный файл конфигурации виртуального сервера по умолчанию будет таким:

server {
        listen 194.XX.XX.XX:80 default_server;
        listen 194.XX.XX.XX:443 http2 ssl default_server;
        server_name _;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_certificate /etc/nginx/ssl/default_server.crt;
        ssl_certificate_key /etc/nginx/ssl/default_server.key;
        return 444;
}

Сохраняем это в файл /etc/nginx/conf.d/fallback.conf, правим под себя IP адрес вашего сервера.
Чтобы Nginx подключил конфигурацию из файла /etc/nginx/conf.d/fallback.conf нужно чтобы каталог /etc/nginx/conf.d был определен в директиве include в файле /etc/nginx/nginx.conf, примерно так:

....
http {
...
        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
}

Данный fallback.conf определяет default_server как для соединений по 80 порту (HTTP), так и для соединений по порту 443 (HTTPS). Для обработки HTTPS соединений нам нужно создать минимальный самоподписной сертификат, он будет нужен лишь для того, чтобы браузер на этапе установки TLS-соединения (Handshake) попытался все таки его установить, хоть и с выводом ошибки, что сертификат самоподписной, ну а далее уже на этапе HTTP соединение будет закрыто самим Nginx. Если кому-то интересно почитать как работает TLS, то я рекомендую статью Александра Венедюхина, там много интересного.

Создаем простой самоподписной сертификат (194.XX.XX.XX замените на свой IP):

mkdir /etc/nginx/ssl
openssl genrsa -out /etc/nginx/ssl/default_server.key 2048
openssl req -new -key /etc/nginx/ssl/default_server.key -sha256 -out /etc/nginx/ssl/default_server.csr -subj "/C=CA/ST=None/L=NB/O=None/CN=194.XX.XX.XX"
openssl x509 -req -sha256 -days 3650 -in /etc/nginx/ssl/default_server.csr -signkey /etc/nginx/ssl/default_server.key -out /etc/nginx/ssl/default_server.crt

После этого проверяем конфигурацию Nginx и перезагружаем ее:

nginx -t && nginx -s reload

Теперь пробуем открыть сервер по IP адресу:
http://194.XX.XX.XX
https://194.XX.XX.XX
http://mysite3.ru
https://mysite3.ru
* Сайты mysite3.ru я взял для примера, у Вас конечно же будут свои сайты.
В браузере соединение по HTTP будет закрыто сразу, а по HTTPS к примеру Google Chrome скажет вначале, что у нас самоподписной сертификат (NET::ERR_CERT_AUTHORITY_INVALID), далее если принять сертификат и перейти на сайт, то соединение по HTTPS так же будет закрыто.

Можно попробовать с другого сервера установить соединение с помощью curl, например так:

Для HTTP:

$ curl -D -k -s http://194.XX.XX.XX -v
* Rebuilt URL to: http://194.XX.XX.XX/
*   Trying 194.XX.XX.XX...
* Connected to 194.67.207.125 (194.XX.XX.XX) port 80 (#0)
> GET / HTTP/1.1
> Host: 194.XX.XX.XX
> User-Agent: curl/7.47.0
> Accept: */*
>
* Recv failure: Connection reset by peer
* Closing connection 0

Для HTTPS:

$ curl -D -k -s https://194.XX.XX.XX -v
* Rebuilt URL to: https://194.XX.XX.XX/
*   Trying 194.XX.XX.XX...
* Connected to 194.XX.XX.XX (194.XX.XX.XX) port 443 (#0)
* found 148 certificates in /etc/ssl/certs/ca-certificates.crt
* found 592 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* SSL connection using TLS1.2 / ECDHE_RSA_AES_128_GCM_SHA256
* server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none
* Closing connection 0

Мы видим, что соединение сразу же закрывается — этого мы и хотели добиться.
Вместо кода 444 Вы можете написать в fallback.conf код 403 и тогда соединение будет открываться и возвращаться HTTP код 403, но лучше не доводить соединение до стадии открытия.

7. Установка и настройка phpMyAdmin

Для Web-разработчиков phpMyAdmin необходим как собственно и сам PHP, поэтому давайте установим и настроим его.

Во-первых давайте определимся по какому URL мы и web-разработчики будут заходить в phpMyAdmin.
Обычно для phpMyAdmin выделают отдельный поддомен, например phpmyadmin.mysite.ru, но у нас же на сервере будет куча сайтов и делать для каждого такого вида поддомен просто неудобно.
Давайте сделаем URL такого вида http://mysite.ru/phpmyadmin и при входе на него наш web-сервер будет делать 301 редирект на какой-то постоянный сервисный домен http://phpmyadmin.myorg.ru
Пусть сайт phpmyadmin.myorg.ru так же будет на этом сервер, для простоты настройки.

Воспользуемся моим скриптом nginx-create-vhost.sh для создания этой сервисной площадки:

./nginx-create-vhost.sh -d phpmyadmin.myorg.ru

Я опущу вывод процесса создания площадки, она успешно создастся, наш рабочий каталог для php-скриптов phpMyAdmin будет /var/www/phpmyadmin.myorg.ru/web

Теперь скачаем последнюю версию phpMyAdmin и развернем ее в каталоге /var/www/phpmyadmin.myorg.ru/web:

cd /var/www/phpmyadmin.myorg.ru/web
wget https://files.phpmyadmin.net/phpMyAdmin/4.8.3/phpMyAdmin-4.8.3-all-languages.zip -O phpMyAdmin-4.8.3-all-languages.zip
unzip phpMyAdmin-4.8.3-all-languages.zip
rm -f phpMyAdmin-4.8.3-all-languages.zip
mv phpMyAdmin-4.8.3-all-languages/* .
rm -rf ./phpMyAdmin-4.8.3-all-languages/
chown -R web2:client2 *

Здесь в команде chown мы назначаем владельца и группу для файлов phpMyAdmin, у Вас это будут другие пользователь и группа.

Далее настроим конфигурацию phpMyAdmin, для этого перейдите в браузер по адресу http://phpmyadmin.myorg.ru/setup/ и создайте файл конфигурации config.inc.php для вашей БД, в самом простом виде он выглядит так:

<?php

$cfg['blowfish_secret'] = 'XXXXXXXXXXXX';
$cfg['DefaultLang'] = 'ru';
$cfg['ServerDefault'] = 1;
$cfg['UploadDir'] = '';
$cfg['SaveDir'] = '';

/* Servers configuration */
$i = 0;

/* Server: localhost [1] */
$i++;
$cfg['Servers'][$i]['verbose'] = 'localhost';
$cfg['Servers'][$i]['host'] = 'localhost';
$cfg['Servers'][$i]['port'] = 3306;
$cfg['Servers'][$i]['socket'] = '';
$cfg['Servers'][$i]['auth_type'] = 'cookie';

/* End of servers configuration */
?>

Параметр $cfg[‘blowfish_secret’] генерируется автоматически и очень важен для защиты.

После создания файла конфигурации Вы можете зайти на http://phpmyadmin.myorg.ru/ и авторизоваться введя данные пользователя MySQL.

Так же я настоятельно рекомендую настроить HTTPS для нашего поддомена phpmyadmin.myorg.ru, но эту тему я оставляю на Вашей совести. Про правильную настройку HTTPS на Nginx я расскажу в отдельной статье.

8. Установка и настройка Pure-FTPd

Теперь установим и настроим ftp-сервер Pure-FTPd.

apt-get -y install pure-ftpd

В качестве базы хранения пользователей мы будем использовать локальную базу Pure-FTPd.
Для начала отключим авторизацию по системный учетным записям через подсистему PAM, для этого остановим Pure-FTPd и выполним ряд команд:

/etc/init.d/pure-ftpd stop
unlink /etc/pure-ftpd/auth/70pam
rm -f /etc/pure-ftpd/conf/PAMAuthentication
ln -s /etc/pure-ftpd/conf/PureDB /etc/pure-ftpd/auth/45puredb

Настроим некоторые полезные опции Pure-FTPd:
1. Запретим анонимный вход;
2. Включим поддержку chroot, это значит, что пользователь будет ограничен своим домашним каталогом и не сможет перейти выше уровнем;
3. Включим расширенное ведение логов;
4. Оставим поддержку только IPv4;
5. Увеличим максимальное число клиентов до 100;
6. Разрешим отображение в директориях файлов начинающихся с точки;
7. Определим список пассивных портов;
8. Зададим кодировку по умолчанию;
9. Увеличим лимиты на количество отображаемых в директориях файлов и глубину вложенности;

echo "yes" > /etc/pure-ftpd/conf/NoAnonymous
echo "yes" > /etc/pure-ftpd/conf/ChrootEveryone
echo "yes" > /etc/pure-ftpd/conf/VerboseLog
echo "yes" > /etc/pure-ftpd/conf/IPV4Only
echo "100" > /etc/pure-ftpd/conf/MaxClientsNumber 
echo "yes" > /etc/pure-ftpd/conf/DisplayDotFiles
echo "yes" > /etc/pure-ftpd/conf/DontResolve
echo "40110 40210" > /etc/pure-ftpd/conf/PassivePortRange
echo "UTF-8" > /etc/pure-ftpd/conf/FSCharset
echo "5000 500" > /etc/pure-ftpd/conf/LimitRecursion

Запустим Pure-FTPd:

/etc/init.d/pure-ftpd start

Проверим, что демон pure-ftpd запустился:

# ps -auxw | grep [p]ure-ftpd
root      6220  0.0  0.1  28316  3456 ?        Ss   Aug19   0:18 pure-ftpd (SERVER)

Посмотрим список открытых портов:

# netstat -ltupn | grep pure-ftpd
tcp        0      0 0.0.0.0:21              0.0.0.0:*               LISTEN      6220/pure-ftpd (SER

Отлично, Pure-FTPd работает.

Теперь можно добавить виртуального пользователя (логин mysite):

pure-pw useradd mysite -u web1 -g client1 -d /var/www/mysite.ru

В опции -u мы указали UID нашего виртуального пользователя, он должен соответствовать UID реального пользователя имеющего право на чтение и запись в домашний каталог.
В опции -g мы указывается GID нашего виртуального пользователя, он должен так же должен соответствовать GID реальной группы.
В опции -d мы указали домашний каталог нашего виртуального пользователя, он должен соответствовать корневому каталогу нашей площадки для сайта mysite.ru в которой располагаются каталог web, log, private и tmp.

При первом запуске данная команда создает базу пользователей, а после любых операций с пользователями — обновляет (не забывайте ее запускать каждый раз):

pure-pw mkdb

Чтобы избежать использования команды ‘pure-pw mkdb’ после каждого изменения данных я рекомендую использовать опцию ‘-m’ в командах модификации. Ниже Вы увидите ее в примерах.

Просмотрим список пользователей:

pure-pw list

Для просмотра подробной информации о пользователе mysite выполним:

pure-pw show mysite

Результат:

Login              : mysite
Password           : $6$MRCbtVpkmo94lpS0$mFPvkoHD/RZ5kl7xrKZtS/aG8OIbaoue.DHoapX9wt54K1/u8KqehHoSAOrWs/Lq8HAilZnbc58U3FLuq3TqK1
UID                : 1001 (web1)
GID                : 1002 (client1)
Directory          : /var/www/mysite.ru/./
Full name          :
Download bandwidth : 0 Kb (unlimited)
Upload   bandwidth : 0 Kb (unlimited)
Max files          : 0 (unlimited)
Max size           : 0 Mb (unlimited)
Ratio              : 0:0 (unlimited:unlimited)
Allowed local  IPs :
Denied  local  IPs :
Allowed client IPs :
Denied  client IPs :
Time restrictions  : 0000-0000 (unlimited)
Max sim sessions   : 0 (unlimited)

Мы видим, что у пользователя есть много различных настроек, например мы можем задать лимиты на загрузку файлов, ограничения на подключение по времени или по количеству одновременных сессий и т.д.

Для смены пароля пользователя mysite выполните:

pure-pw passwd mysite -m

Для смены домашней директории пользователя mysite выполните:

pure-pw usermod mysite -d /var/www/mysite.ru/web -m

Для удаления пользователя mysite выполните:

pure-pw userdel mysite -m

Pure-FTPd пишет логи в файл /var/log/messages, поэтому для просмотра логов нужно отфильтровать их по слову pure-ftpd, например так:

tail -f /var/log/messages | grep pure-ftpd

Расширенный лог пишется в файл /var/log/pure-ftpd/transfer.log, в нем можно посмотреть кто, когда и какие операции выполнял после прохождения аутентификации. Сами попытки аутентификации (удачные и не удачные) нужно смотреть в файле /var/log/messages

Вопрос включения TLS и некоторых других интересных опций я рассмотрю в отдельной небольшой статье.

На этом все, до скорых встреч. Если у Вас возникли вопросы или Вы хотите чтобы я помог Вам, то Вы всегда можете связаться со мной разными доступными способами.


Подписаться
Уведомить о
guest

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

13 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
wer1
wer1
6 лет назад

Доброго времени суток.

Спасибо за ваши статьи )

P.s.

sed -i «s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/» /etc/php/7.0/fpm/php.ini и другие можно сократить:

sed -i -e ‘s/;(\cgi.fix_pathinfo\)/\1=0/’ /etc/php/7.0/fpm/php.ini

Проверяю тут https://www.shellcheck.net/

wer1
wer1
6 лет назад

Добрый.

echo «vnoremap :w !xsel -b» >> ~/.vimrc не работает.
echo ‘vnoremap :w !xsel -b’ >> ~/.vimrc работает

Владимир
Владимир
5 лет назад

Ссылка «размещены у меня на github.com» не работает.

Андрей
Андрей
5 лет назад

Выдает ошибку,всю голову сломал.
root@c4:/home/linux-scripts-master/nginx# ./nginx-create-vhost.sh -d test.de
Detecting your OS Linux (x86_64)
Detecting Linux distrib Debian (SYSTEMD)
Detecting your php-fpm Found php-fpm7.0
Detecting nginx owner Found www-data
Error: In file /etc/nginx/settings.conf not found parameter NEXTWEBUSER.
Usage: ./nginx-create-vhost.sh [ -d domain_name -s site_directory -u user_name -g group_name]

-d sitename : Domain name, domain.com
-s sitedir : Site directory, /var/www/domain.com
-u username : User name, www-data
-g group : Group name, www-data
-h : Print this screen

root@c4:/home/linux-scripts-master/nginx#

Александр
Александр
5 лет назад

Михаил, огромное спасибо за ваши статьи!
Человеку, только ставшему на пусть изучения данного направления они крайне полезны и экономят уйму нервов.

Николай
Николай
5 лет назад

Михаил добрый день!
Очень хорошо расписываете все шаги, интересно читать!
Ждем пока доберетесь до — Про правильную настройку HTTPS на Nginx я расскажу в отдельной статье.
Спасибо!

Илья
Илья
3 лет назад

Помогли в решении моей задачи

Виктор
Виктор
2 лет назад

Извините за дилетантский вопрос, но почему на папку web не поставить права 750, вместо 755, чтобы вообще никто кроме нужного пользователя и сервера (который в соотв. группе) не мог там ничего просматривать? Чему помешают права 750?

Виктор
Виктор
2 лет назад
Ответить на  Михаил Григорьев

Спасибо.

13
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x