Переводим сайты WordPress на LEMP (Linux + Nginx + MySQL + php-fpm)
|Появилось время на оптимизацию своего зоопарка, крутилось всё уже несколько лет на Debian 6 и 7, Apache2, MySQL и т.д. Хотя всем и советовал сразу уходить на Nginx, старые проектики всё никак не мог перевести и оптимизировать.
Работать будем в DigitalOcean на стеке LEMP с минимальным дроплетом за 5$ на 1GB RAM + 1xCORE + 25GB SSD, оптимизировать скорость будем за счет сжатия в Nginx, кеширования в Memcached и в некоторых случаях можно применить CloudFlare в качестве дополнительного кеша и CDN.
Первым делом нужно создать виртуальный сервер (он же droplet) с ОС Debian 9 Stretch
Регион можете выбрать на свое усмотрение, я с учетом моего географического положения (Беларусь) посчитал, что наиоблее оптимальным будет Германия. Из дополнительных опция нам могут пригодиться Private networking и Monitoring, а аутентификацию лучше всего настраивать по ключу (ключ можете сделать с помощью PuTTY Gen). На финальном этапе задаем название для нашего дроплета, жмем кнопку создать и выжидаем порядка минуты (если аутентификация по ключу — письмо о том, что создан дроплет на почту не пришлют).
Заходим на наш дроплет и первым делом обновляемся:
$ apt-get update -y && apt-get upgrade -y
Далее, сразу ставим разные полезные мелочи, которые могут на понадобиться:
$ apt-get install htop nano mc zip unzip
Для загрузки файлов на сервер мы можем использовать либо wget если речь о скачивании из интернета, либо качаем к себе WinSCP и работаем по SFTP для загрузки файлов с компьютера. FTP мы использовать не будем по нескольким причинам: это не безопасно, это дополнительные группы и пользователи, обновлять еще один компонент, лишний открытый порт у нас на сервере.
Теперь приступим к установке нашего стека по шагам и начнем пожалуй с nginx:
$ apt-get install nginx -y
Далее настроим наш веб-сервер:
$ nano /etc/nginx/nginx.conf
Выставим следующие параметры:
Пользователя оставляем «www-data» — с наименьшими привилегиями;
«worker_processes auto;» — можно так же оставить «auto» т.к. 1 у нас все равно одно ядро и особого смысла трогать его нет.
Далее, в events оставляем все как есть:
events { worker_connections 768; # multi_accept on; }
В настройках сжати gzip немного корректируем параметры и включаем сжатие для статики:
## # Gzip Settings ## gzip on; gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_min_length 256; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
В нашем случае выставлять уровень сжатия более 6 не стоит т.к. при максимальном параметре «gzip_comp_level 9» мощностей потребляется больше, а каких-то кардинальных отличий вы не заметите.
Далее нам нужно создать снипет по пути «/etc/nginx/snippets/ssl-params.conf» в котороым мы пропишем некоторые настройки для SSL на нашем сервере:
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; ssl_ecdh_curve secp384r1; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s; add_header Strict-Transport-Security "max-age=63072000"; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff;
Данная конфигурация отключает на нашем сервере поддержку SSLv3 и ниже, выставляет допустимые алгоритмы шифрования, разрешает кешировать ssl сессии, а так же выставляем безопасные параметры заголовков веб-сервера.
Далее в конфигурационных файлах наших сайтов мы будем использовать наш заранее заготовленный снипет.
Теперь можно доставить всё остальное:
$ apt-get install php7-fpm php7.0-mysql mysql-server memcached monit certbot sendmail
- Monit будет отвечать за повышение отказоустойчивости (перезапуск сервисов и оповещение)
- Certbot поможет нам получать и обновлять наш SSL сертификат
- Memcached поможет нам с организацией кеша и ускорением нашего сайта (вместе с плагино W3 Total Cache)
- Sendmail пригодится для быстрой настройки email оповещений
- php и mysql-server думаю и без лишних слов понятно, зачем нужны нам
- Ну и чуть позже мы еще доставим phpMyAdmin как довольно удобный инструмент для управления и мониторинга нашей БД
Пока устанавливаются все пакеты описанные выше, мы быстренько выполним несколько нехитрых действий.
Для начала давайте спрячем наш SSH, изменим порт на что-то, менее стандартное:
$ nano /etc/ssh/sshd_config
Раскоментируем параметр порт и выставим к примеру 2222 (выбирайте любой порт на свое усмотрение, главное чтобы оно не конфликтовало с другими сервисами). Меняем настройку, сохраняем и выходим из файлика конфигурации, рестартуем службу:
$ service ssh restart
Переходим в веб-интерфейс DigitalOcean и в нем активируем приложения файрвола, а так же вносим некоторые корректировки (в веб панели заходим в Networking -> Firewalls):
На файрволе блокируем все (следуем примеру Amazon) и открываем только нужные нам порты. Как бонус, можно заблокировать еще ICMP и тогда ваш сервер перестанет пинговаться. С одной стороны удобно, немного улучшим защиту от мелких хулиганов, с другой — не совсем понятно, как это может сказаться на SEO оптимизации, по этому лучше не будем рисковать и разрешим ICMP, при надобности отключим если что.
Теперь добиваем наш мониторинг, заходим в Monitoring и создаем там «Alert policy»:
Т.к. у нас самый простой и относительно слабенький дроплет, я выставил планку оповещения на 90%, потому что при большом наплыве людей на сайты, загруза будет существенной для ресурса в 1гб памяти и одного ядра.
Да, чуть не забыл, для нас еще актуально создать раздел swap который в трудный момент может нас слегка выручить, создается он выполненим следующих команд:
$ fallocate -l 2G /swap $ chmod 600 /swap $ mkswap /swap $ swapon /swap $ nano /etc/fstab В самом конце файла добавляем строку: /swap none swap sw 0 0
Swap мы сделали на 2GB исходя из объема нашей оперативной памяти (RAM*2). Последней командой мы добавили заставили систему подгружать наш файл подкачки автоматически (удобно при перезагрузках).
Базовый файрвол настроили, минимальный мониторинг загруженности теперь у нас тоже есть, swap добавили, теперь добиваем настройку WordPress, nginx и php с mysql.
Сразу выполним безопасную настройку базы данных с командой «mysql_secure_installation», ну а дальше сделаем для БД себе нового пользователя:
$ mysql -u root -p<ВашПароль> CREATE USER 'user'@'localhost' IDENTIFIED BY 'password'; GRANT ALL PRIVILEGES ON *.* TO 'user'@'localhost'; FLUSH PRIVILEGES;
Посл того, как пользователя добавили и все безопасно настроили, ставим phpMyAdmin:
$ apt-get install phpmyadmin -y
Далее в /etc/nginx/sites-available/default добавляем наш будущий путь к phpmyadmin ну и создаем линк к папке с файлами админки по нужному пути (пускай путь будет myadm):
$ nano /etc/nginx/sites-available/default
Добавляем в «server { … }»:
location /myadm { index index.html index.php; auth_basic "Password protected"; auth_basic_user_file /usr/share/phpmyadmin/password; }
Генерируем пароль для нашей аутентификации:
$ openssl passwd
В примере это «auth_basic_user_file /usr/share/phpmyadmin/password» файл, с пользователем и паролем, у себя можете делать так, как вам будет удобнее и звучнее. После того, как в nginx мы путь уже указали, создаем линк до нашей админки:
ln -s /usr/share/phpmyadmin/ /var/www/html/myadm
Дело остается за малым, донастроить кеш и вордпресс, а так же сказать серверу где лежит наш сайт:
$ cp /etc/nginx/sites-available/default /etc/nginx/sites-available/new_websites.conf $ nano /etc/nginx/sites-available/new_websites.conf
Конфигурацию как видно, мы скопировали из файла по умолчанию и просто внесем несколько корректировок с учетом того, что мы будем использовать SSL, а значит нам понадобится правильный редирект (перенаправление с HTTP на HTTPS), а так же путь до сертификата которого еще нет.
Добавляем нужные нам строки:
server { #Указываем редирект с HTTP на HTTPS listen 80; server_name newwebsite.com www.newwebsite.com; return 302 https://$server_name$request_uri; } server { #Заставляем наш сайт работать на 443 порту по HTTPS listen 443; listen [::]:443; server_name newwebsite.com www.newwebsite.com; #Подгружаем наш снипт с настройками для SSL include snippets/ssl-params.conf; #Включаем SSL и указываем путь к сертификатам нашего сайта ssl on; ssl_certificate /etc/letsencrypt/live/newwebsites.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/newwebsite.com/privkey.pem; #Указываем путь к корневому каталогу нашего сайта root /var/www/html/newwebsite/www; location / { #Учим WordPress работе с красивыми ссылками index index.html index.php; try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; } location ~ /\.ht { #Запрещаем прямой доступ к файлам конфигурации deny all; } }
Старые строки если мешают можно удалить или закоментировать, либо как вариант — подкорректировать старый конфигурационный файл который мы скорпировали (default). Что к чему в файле конфигурации, можно посмотреть по комментариям из выше приведенного примера.
Правим наш php-fpm:
$ nano /etc/php/7.0/fpm/php.ini
Выставляем параметр cgi.fix_pathinfo = 1 выставляем значение 0 (ноль). Эти настройки по умолчанию очень небезопасны, потому что благодаря им PHP попытается исполнить ближайший файл, который сможет найти в случае, когда запрашиваемый PHP файл не может быть найден.
Выпускаем для нашего сайта сертификат:
certbot certonly
И далее выполняем шаг за шагом все пункты из интерактивного меню, по окончании у вас в /etc/letsencrypt/live/ должны появиться папки с названием сайтов и сертификатами внутри.
Рестартуем службу ngix и php-fpm:
$ service nginx restart $ service php-fpm restart
WordPress качаем с официального сайта, последнюю версию или если у вас есть сайт, то переносим его к нам на хостинг через SFTP (описано выше). Учтите, что мы работаем с php-fpm версии 7.0, если у вас WordPress был более старой версии и вы его не обновляли, то прдется пойти еще на один маневр:
- Бекапируем корень сайта без папок, а так же все в: /wp-admin/ и /wp-includes/
- Качаем последнюю версию дистрибутива WordPress и из нее заливаем более свежие файлы в /wp-admin и /wp-includes соответственно, а так же обновляем наш корень сайта, /wp-content/ и файл wp-config.php не трогаем.
- Заходим на наш сайт и обновляем нашу БД
Если всё прошло отлично, значит вы уже можете зайти к себе на сайт и поставить плагин «W3 Total Cache».
В последних версиях Debian пакет memcached для кеширования ставился из коробки правильно, но если вдруг что-то пошло не так, то параметры должны быть выставлены следующим образом в файле «/etc/memcached.conf»:
-d -m 64 -p 11211 -u memcache -l 127.0.0.1
Работаем на localhost из под пользователя «memcache». Рестартуем наш сервис: «service memcached restart».
Теперь ставим monit который будет показывать статистику аптайма критически важных для нас сервисов и рестартовать их в случае каких-то проблем.
$ nano /etc/monit/monitrc
Активируем отправку по почту оповещений, ищем и редактируем:
set mail-format { from: alert@srv-websites-1 } - от кого будет отправлено сообщение set alert sm0k3web@gmail.com - кому будет отправлено сообщение
Сохраняем и закрываем, добавляем следующие шаблоны для интересующих нас сервисов nginx, mysql, memcached в файлики с соответствующими названиями в папке «/etc/monit/conf-available/»:
# Nginx check process nginx with pidfile /run/nginx.pid start program = "/etc/init.d/nginx start" stop program = "/etc/init.d/nginx stop" if failed host 127.0.0.1 port 80 then restart if cpu > 75% for 2 cycles then alert if cpu > 95% for 5 cycles then restart if 10 restarts within 10 cycles then timeout # MySQL check process mysqld with pidfile /run/mysqld/mysqld.pid group database start program = "/etc/init.d/mysql start" stop program = "/etc/init.d/mysql stop" if failed host 127.0.0.1 port 3306 then restart if cpu > 90% for 3 cycles then alert if 5 restarts within 5 cycles then timeout # Memcached check process memcached matching "memcached" start program = "/etc/init.d/memcached start" stop program = "/etc/init.d/memcached stop" if failed host 127.0.0.1 port 11211 then restart if cpu > 75% for 2 cycles then alert if cpu > 98% for 5 cycles then restart if 2 restarts within 3 cycles then timeout
Когда закончили с файликами конфигурации, линукем их в активные и рестартуем monit:
ln -s /etc/monit/conf-available/nginx /etc/monit/conf-enabled/
Так проделываем со всеми нужными файлами конфигурации и далее:
$ service monit restart
После перезапуска службы, на почту должно было упасть тестовое сообщение, если не видно, то можно проверить папку спам, если в спаме нет — с большей вероятностью проблемы с sendmail.
На завершающем этапе нам остается лишь настроить плагин кеширования вордпресс W3 Total Cache. Активируем плагин, заходим в настройки и включаем все возможные опции кеширования, а в доступных вариантах в выпадающем меню выбираем «Memcached».
Если вдруг возникли проблемы на этапе скачивания и инсталяции плагина WordPress, то стоит обратить внимание на права выставленные на папки и соответственно кому они принадлежат. В идеале это пользователь www-data из такой же группы, и права на папку «/wp-content/uploads» на запись (777):
$ chown -R www-data:www-data /var/www/html/newwebsites/www $ chmod -R 777 /var/www/html/newwebsites/www/wp-content/uploads/
Команды выше меняют группу и выставляют права рекурсивно, т.е. проходятся по всем папкам ниже.
Кеширование это с одной стороны друг, с другой может создать некоторые проблемы. Для административных нужд кеширование лучше отключить, данные опции доступны в этом плагине. Заходим в «Page Cache» и отключаем кеш для администратора и на главной странице при добавлении контента:
Для главной:
При небольших нагрузках данный сервер сможет поддерживать до 5 сайтов. В случае, если вдруг нагрузка начнет расти (а это рано или поздно случится), первым делом мы можем попробовать довесить до кучи еще CloudFlare, если это не поможет — то добавить для нашего сервера ресурсов (на DigitalOcean можно добавлять ресурсы на лету) и немного еще увеличить степень сжатия.
Если не полениться и разобраться с сервисом Zapier, то можно делать снапшоты в автоматическом режиме через API DigitalOcean в режиме бекапов и бесплатно (по расписанию).
По итогу имеем достаточно защищеный и отказоуйстойчивый сервер для нескольких сайтов, дополнительную защиту за счет скрытия IP адреса еще может дать вам CloudFlare, но его лучше внедрять на этапе создания сервера, чтобы не светить реальный IP адрес. К тому же, наше решение может оповещать в случае повышенного использования ресурсов, автоматически перезапускать службы, бекапиться и все это за 5$ и часик свободного времени.
Может быть интересно: