Мой опыт переноса блога с шаред хостинга на VDS

23 августа 2018

Когда я начинал вести этот блог в 2009 году, хостить сайты, особенно небольшие, на VDS как-то не было принято. (Не говоря уже о том, что сами идеи «посвящать самому себе сайт» / «вести общедоступный дневник» были еще новыми и казались немного дикими.) Главным образом, все использовали shared hosting, потому что он стоил дешевле VDS и решал свою задачу — сайт работал, странички открывались. Сегодня, конечно же, все сильно изменилось. Не только VDS стали дешевле, но и современные браузеры стали ругаться на сайты, не использующие HTTPS. А за сертификаты хостинг-провайдеры берут деньги. Еще бы, ведь у клиентов нет на сервере рутовых прав, а значит Let’s Encrypt они прикрутить не могут. В любом случае, в современных реалиях держать сайт на шаред хостинге иначе как зашкваром не назовешь. Поэтому я решил рассказать о своем опыте переноса сайта на VDS, на примере этого самого блога.

Примечание: Описанная ниже конфигурация покажется кому-то довольно олдскульной (в нашу-то с вами эпоху контейнеров и микросервисов на Go!), потому что именно таковой она и является. Я ставил перед собой задачу перенести сайт на VDS в том виде, в каком он есть, а не менять используемый стек технологий. Возможно, когда-нибудь я решу уделить время и данному вопросу тоже, но это уже будет темой отдельной статьи. Отмечу также, что гуру Linux не найдут для себя много нового в этой статье. Однако тем, кто гуру не является, она может быть крайне полезна.

LAMP для нетерпеливых

В этом разделе я опишу установку так называемого LAMP, то есть, связку Linux + Apache + MySQL + PHP. По этой теме только ленивый не писал статей. Тем не менее, я посчитал, что для полноты картины соответствующую инструкцию следует включить в текст. Постараюсь быть максимально кратким.

Использованный мной VDS имеет 1 ядро CPU, 1 Гб RAM и 25 Гб места на диске. Как показала практика, для персонального блога этих ресурсов хватает просто за глаза. При выборе региона, в котором будет размещаться VDS, убедитесь, что он не попал под раздачу РКН. Также желательно, чтобы регион территориально находился близко к вашей основной аудитории — чем меньше пинг, тем быстрее кажется работа сайта. Например, если вы пользуетесь DigitalOcean, и ваша основная аудитория, согласно статистике сайта, находится в России, то можно порекомендовать регион AMS2 (на момент написания этих строк). При регистрации в DigitalOcean по реферальной ссылке вы получаете на счет 10$, что позволит бесплатно пользоваться VDS в течение двух месяцев.

Работает VDS под управлением Ubuntu Linux 16.04, потому что именно такой дистрибутив использовался на старом хостинге. Я решил придерживаться стратегии «сначала унести все на VDS, а затем при необходимости обновить все на версии поновее». Если вы решите повторить действия из этой заметки, советую поступить так же. Для других дистрибутивов Linux отличия будут минимальными, и заключаться в основном в использовании другого менеджера пакетов.

Прежде всего, не сидим на сервере под рутом:

adduser afiskon
# говорим, что пользователь может sudo
vim /etc/sudoers
# копируем ~/.ssh/authorized_keys
cp -r .ssh /home/afiskon/.ssh
chown -R afiskon:afiskon /home/afiskon/.ssh/
exit

Заходим под новым пользователем. Меняем таймзону, чтобы время в логах нам о чем-то говорило, а запланированные посты публиковались вовремя:

sudo dpkg-reconfigure tzdata

На старом хостинге использовался PHP 5.3, поэтому добавим такой PPA:

sudo add-apt-repository ppa:ondrej/php
sudo apt update

Из него можно установить PHP 5.6, что достаточно близко. Более старые версии на момент написания этих строк больше не поддерживаются, и найти для них готовые пакеты оказалось проблематичным.

Ставим Apache:

sudo apt install apache2

Правим /etc/apache2/ports.conf, говорим слушать все интерфейсы на порту 8080:

Listen 8080

В файле /etc/apache2/mods-enabled/dir.conf переносим index.php в начало списка. Также включаем пару дополнительных модулей:

sudo a2enmod rewrite remoteip headers expires

Первый нужен для корректной работы WordPress, второй — для перезаписи $_SERVER['REMOTE_ADDR'] при работе за прокси-сервером, последние два используются WP-SuperCache.

В конец файла /etc/apache2/apache2.conf дописываем:

<Directory /var/www/html/>
    AllowOverride All
</Directory>

<IfModule mod_remoteip.c>
    RemoteIPHeader X-Real-IP
</IfModule>

# не палим версию сервера
ServerTokens Prod
ServerSignature Off

… и перезапускаем сервер:

sudo systemctl restart apache2

Теперь на порту 8080 должны видеть страничку «Apache2 Ubuntu Default Page».

Далее ставим MySQL (или, как альтернативный вариант, MariaDB):

sudo apt install mysql-server mysql-client
mysql --user root --password

Сравниваем sql_mode на новом сервере и на старом хостинге:

mysql> select @@sql_mode;

Если они отличаются, стоит поменять sql_mode в файле /etc/mysql/my.cnf, например, так:

[mysqld]
sql_mode="NO_ENGINE_SUBSTITUTION"

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

Перезапускам MySQL:

sudo systemctl restart mysql

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

mysql> CREATE DATABASE eaxme;
mysql> CREATE USER 'eaxme'@'localhost' IDENTIFIED BY 'pa55w0rd';
mysql> GRANT ALL ON eaxme.* TO 'eaxme'@'localhost';
mysql> exit

Проверяем, что пользователь может подключиться к базе, создавать / удалять таблицы, и так далее:

mysql --user eaxme eaxme --password

Теперь ставим PHP и его расширения, необходимые для работы WordPress:

sudo apt install php5.6 libapache2-mod-php5.6 \
  php5.6-mysql php5.6-curl php5.6-gd php5.6-mbstring \
  php5.6-mcrypt php5.6-xml php5.6-xmlrpc

Правим немного /etc/php/5.6/apache2/php.ini:

short_open_tag = On
# а также другие параметры при необходимости

Apache нужно рестартонуть, чтобы он гарантированно увидел все новые модули:

sudo systemctl restart apache2

Далее говорим:

sudo chown -R afiskon:www-data /var/www/html
echo '<? phpinfo(); ?>' > /var/www/html/test.php

Пытаемся открыть test.php в браузере. Если все было сделано правильно, увидим классический вывод phpinfo(). Не забываем удалить test.php:

rm /var/www/html/test.php

На этом с установкой и настройкой LAMP покончено. Настройка Nginx и HTTPS будет рассмотрена далее отдельно от LAMP.

PHP-функция mail()

Чтобы в PHP работала функция mail(), требуется выполнить кое-какие дополнительные шаги. Если вы точно знаете, что ваш сайт не использует эту функцию, сей раздел можно смело пропустить.

Ставим ssmtp:

sudo apt install ssmtp

Это простой консольный SMTP-клиент. Помимо прочего, он создает в системе символьную ссылку /usr/sbin/sendmail, которую использует функция mail().

В файле /etc/ssmtp/ssmtp.conf указываем параметры подключения к STMP-серверу, и кое-какие дополнительные настройки:

root=noreply@eax.me
mailhub=mail.eax.me:25
hostname=localhost
UseSTARTTLS=YES
AuthUser=noreply@eax.me
AuthPass=sup3r_pa$$word
FromLineOverride=YES

Проверяем, что письма отправляются:

echo -e "From: Noreply <noreply@eax.me>\n"\
"To: Somebody <somebody@example.org>\n"\
"Subject: Test message from ssmtp\n\n"\
"This is a test message" | ssmtp -v somebody@example.org

Если работает, проверяем функцию mail():

<?php

$to = "Somebody <somebody@example.org";
$subject = "Test e-amil";
$body = "Testing mail() function";
$headers = "From: Noreply <noreply@eax.me>";

mail($to, $subject, $body, $headers);

echo "<h1>OK!</h1>";
?>

Ну вот, теперь с чистой совестью можно двигаться дальше.

Переносим данные

Резервное копирование файлов при помощи tar, а также базы данных в MySQL при помощи mysqldump ранее были описаны в заметке Резервное копирование базы данных и файлов по SSH. Далее предполагается, что эти резервные копии у вас уже есть, и что они залиты на новый сервер.

Начнем с импорта базы данных:

zcat eaxme-db.sql.gz | mysql --user eaxme eaxme --password

На время отладки поменяем домашний URL сайта в настройках движка:

mysql> update eaxme_options
    -> set option_value = 'http://123.45.67.89:8080'
    -> where option_value = 'https://eax.me';

Распаковываем архив с файлами:

tar -xvzf eaxme-files.tgz
rm /var/www/html/index.html
mv eax.me/docs/* /var/www/html
mv eax.me/docs/.htaccess /var/www/html

В файле wp-config.php нужно поправить параметры подключения к БД, как минимум — имя хоста. Также может потребоваться поменять абсолютные пути в файле wp-content/advanced-cache.php.

Меняем права доступа к файлам и каталогам:

cd /var/www/html
sudo chown -R afiskon:www-data ./
chmod -R g+w wp-content/cache
chmod -R g+w wp-content
chmod g+w sitemap.xml
chmod g+w sitemap.xml.gz
# вместо используемого мной пути "files"
# по дэфолту в WordPress используется "wp-content/uploads"
chmod -R g+w files

Для корректной работы отложенной публикации постов говорим crontab -e и вписываем такую строчку:

*/10 * * * * curl 'https://eax.me/wp-cron.php'

Проверяем работу сайта. Все должно работать корректно.

Nginx и HTTPS

На этом этапе желательно отключить любое кеширование страниц, в частности — плагин WP-SuperCache, так как в кэше сейчас лежат страницы с HTTP-ссылками. На всякий случай проверяем, что в каталоге wp-content/cache/supercache ничего не осталось. Все это нужно для того, чтобы после включения HTTPS не остаться без CSS, JavaScript и картинок, что потенциально может привести к невозможности попасть в админку сайта.

Ставим Nginx:

sudo apt install nginx

Переносим файлы .crt и .key со старого хостинга на новый сервер, куда-нибудь в /etc/ssl, а также переносим конфиг Nginx:

sudo mkdir /etc/ssl/eax.me/
# (кладем в него site.crt и site.key)
# ...

sudo rm /etc/nginx/sites-enabled/default
sudo vim /etc/nginx/sites-available/eax.me.site.conf
# (переносим конфиг с шаред хостинга)
# ...

sudo ln -s /etc/nginx/sites-available/eax.me.site.conf \
  /etc/nginx/sites-enabled/eax.me.site.conf

Проверяем конфиг:

sudo service nginx configtest
# или: sudo nginx -t

Если все ОК:

sudo systemctl reload nginx

Меняем адрес сайта обратно:

mysql> update eaxme_options
    -> set option_value = 'https://eax.me'
    -> where option_value = 'http://123.45.67.89:8080';

В /var/www/html/.htaccess дописываем:

<IfModule mod_setenvif.c>
SetEnvIf X-Forwarded-Proto https HTTPS=on
SetEnvIf X-Request-Scheme  https HTTPS=on
</IfModule>

У себя на компьютере прописываем новый адрес сайта в /etc/hosts, проверяем, что все работает. Не забываем включить обратно WP-SuperCache. Правим файл /etc/apache2/ports.conf, чтобы Apache не торчал наружу:

Listen 127.0.0.1:8080

Проверяем, что наружу торчат только порты 22 (SSH), 80 и 443 (Nginx), а 3306 (MySQL) и 8080 (Apache) открыты только на 127.0.0.1:

sudo systemctl restart apache2
sudo netstat -tuwpln

Если все хорошо, убираем изменения, сделанные в /etc/hosts, и вносим соответствующие изменения в DNS. Если ваш VDS-провайдер также предоставляет DNS, и вы решили им воспользоваться, не забываем внести соответствующие изменения в whois на сайте вашего регистратора доменов. Затем терпеливо ждем, пока всех посетителей не перкинет на новый сайт. Это будет видно по логам Nginx на старом хостинге и на новом сервере.

По окончании переезда можно сменить старого CA на Let’s Encrypt, введя пару команд из заметки Настройка HTTPS с сертификатами Let’s Encrypt. Также не забудьте поправить скрипты для резервного копирования сайта!

Заключение

Как видите, при переносе сайта было собрано не так уж и много граблей. По времени переезд занял где-то один вечер. Эта статья была написана уже после переезда и опубликована автоматически по расписанию. Так что, видимо, перенос можно считать успешным. Субъективно на VDS сайт работает существенно быстрее, что не может не радовать.

А доводилось ли вам переносить сайты с шаред хостинга на VDS и если да, то какие грабли вы собрали в процессе? Если нет, то планируете ли осуществить перенос после прочтения сего поста?

Дополнение: Поднимаем собственный почтовый сервер на VDS

Метки: , , , .

Понравился пост? Узнайте, как можно поддержать развитие этого блога.

Также подпишитесь на RSS, Google+, Facebook, ВКонтакте или Twitter.