Статьи: Домашний хостинг для нищебродов
05.07.2018


Апельсин, распечатанный на 3D-принтере

Сегодня мы рассмотрим вопрос экономии денег и размещения веб-сайтов и прочих сетевых сервисов (например, ботов для мессенджера Telegram) на собственном «железе» в обычной городской квартире и постараемся выяснить, есть ли в этом смысл или всё-таки лучше поручить поддержку инфраструктуры профессионалам. Изначально этот пост планировался познавательным туториалом, но в итоге всё скатилось к разбору полётов…

Как-то давным-давно я кинул клич в одном из чатов и посетовал на отсутствие денежных средств для оплаты хостинга на следующий год. Откликнулся хорошо известный в очень узких кругах товарищ Кив и предложил безумную идею с созданием собственного домашнего сервера! Сам он хостит свои сайты на Cubieboard 2, а мне согласился бесплатно отправить «Апельсинку» — китайский одноплатный компьютер Orange Pi PC с 4-ядерным процессором на архитектуре ARM, 1 Гб оперативной памяти и постоянной памятью в виде любой воткнутой в него SD-карты.


Необходимое оборудование и первоначальная настройка

Orange Pi PC

Поскольку Кив — уважаемый и опытный человек, занимающийся созданием роботов и написанием операционных систем, но, тем не менее, не гнушающийся время от времени замарать руки вебом, фронтендом и мобильной разработкой, то он быстро смог побороть мой изначальный скептицизм, ответив на ряд вопросов. Одной из основных проблем является, разумеется, мой динамический IP-адрес. Но разговор об этом мы пока ненадолго отложим.

Итак, к одноплатнику я докупил на AliExpress блок питания с корпусом и охлаждением за $10.50 (при том что сам компьютер можно найти за $15.56).

Одноплатник с блоком питания и корпусом

Поскольку у меня нет монитора с HDMI, пришлось прикупить USB-адаптер COM-порта, чтобы выводить сообщения с консоли в PuTTY по интерфейсу UART.

USB to TTL HW-597

Трёхпиновый коннектор есть на плате Апельсина. Общий провод (землю, GND) нужно соединить, TX и RX подключить крест-накрест (передачу к приёмнику), питание (VCC) замкнуть перемычкой на 3.3 вольта. Скорость выставить при подключении — 115200 бод.

Для первоначальной настройки COM-порта вполне хватает. В дальнейшем работать, конечно, гораздо удобнее настроив SSH-сервер (благо это легко и в Сети полно туториалов: нужно всего лишь сгенерировать пару ключей и закинуть открытый ключ в файл ~/.ssh/authorized_keys).

В качестве прошивки я выбрал Armbian — дистрибутив, производный от Debian и оптимизированный для работы на одноплатных ARM-компьютерах с флеш-памятью. Там исправлены косяки инженеров Xunlong с завышенными и плохо адаптирующимися под условия частотами процессора, ведущими к его перегреву, а также оптимизирована запись служебных данных (логов, например) для продления жизни SD-карты. Впрочем, другие варианты прошивок (а их много) я не пробовал, так что ничего плохого или хорошего о них сказать не могу. Сама установка весьма проста и прекрасно описана как в официальном руководстве, так и в посте по предыдущей ссылке на сборник дистрибутивов: нужно просто записать готовую систему на флешку.


Охлаждение

Купленная мной система охлаждения состоит из радиатора и небольшого пятивольтового вентилятора, у которого есть один недостаток — слишком уж он шумный. При этом Армбиан заявляется достаточно оптимизированной системой, чтобы можно было использовать одноплатник лишь с пассивным охлаждением. Но раз уж вентилятор есть, то хотелось его как-то использовать. Выход один: считывать датчик температуры и включать/выключать вентилятор в зависимости от его значения.

Подходящий скрипт легко находится на форуме Армбиана. Рекомендую, кстати, посмотреть на содержимое каталогов /sys/class/thermal и /sys/class/gpio. В первом находится файл, из которого можно получить информацию о температуре процессора (точный путь прописан в скрипте), а на втором я остановлюсь подробнее, потому что это жутко интересно и мне хочется поделиться.

Забавно, как Линукс позволяет считывать состояние датчиков из файлов или менять состояния пинов GPIO, просто записывая новые значения в файлы специальной файловой системы, транслирующей эти обращения в системные вызовы. Напомню, что GPIO — это просто набор контактов общего назначения на плате, сгруппированных в один порт, в котором, кроме них, есть пин на «землю» и питание на 3.3 или 5 вольт (точная распиновка есть в руководстве). С каждым из портов ассоциировано какое-то число, чтобы к нему можно было обращаться из системы (вот тут точную распиновку дать не могу: так до конца и не разобрался). В скрипте это число 12, которое присваивается переменной GPIO.

В папке /sys/class/gpio/ имеется два файла: export и unexport. Если записать в первый файл номер порта, то рядом появится папка gpio$GPIO (подстановка в стиле Bash'а). Убрать её можно, очевидно, записав то же число во второй файл. Внутри неё находятся файлы direction и value. Пишем в первый out, если хотим записывать значения, или in, если считывать, и работаем дальше со вторым. Всё гениально и просто!

Примечание

Записать значение в файл можно двумя способами. Если работа выполняется от имени суперпользователя, то всё просто:

echo 12 > /sys/class/gpio/export

Иначе придётся применить небольшой трюк с программой tee:

echo 12 | sudo tee /sys/class/gpio/export > /dev/null

Впрочем, вывод можно и не перенаправлять вникуда, если он не мешает.

Дополнено 11.07.18: ещё можно запускать отдельную оболочку от имени суперпользователя:

sudo bash -c "echo 12 > /sys/class/gpio/export"

Ладно, что-то я отвлёкся от темы. Вернёмся к охлаждению, ведь проблема тут возникла вовсе не программная. А всё дело в том, что пины GPIO выдают всего 3.3 В. Причём даже их категорически нельзя использовать для питания устройств. Совсем. Они подключены без какой-то специальной защитной обвязки и такая эксплуатация может в любой момент привести к выходу всей платы из строя. Соответственно, питать вентилятор можно только со специальных контактов питания: либо на 5, либо на 3.3 вольта. Поэтому придётся использовать полевой транзистор, на который будем подавать управляющий сигнал с GPIO.

Проблема с транзисторами в том, что для неподготовленного человека это уже довольно сложная электроника, которую нужно подбирать тщательно и аккуратно, чтобы не получить транзистор который не будет открываться от управляющего сигнала. Причём с покупкой тоже могут возникнуть проблемы: в провинциальных магазинах выбор скуп, заказывать из российских интернет-магазинов дорого, а китайцы могут обмануть. И на последнем я хочу заострить особое внимание, потому что пошёл именно по этому пути, заказав набор мосфетов IRL3705N, которые мне посоветовали. Догадайтесь, что произошло дальше?

MOSFET-транзисторы

Я редко что-то делаю руками, потому что обычно всё получается через одно место. В этот раз, после не особо удачного опыта припаивания ножек к Ардуине, я решил основательно подготовиться к процессу: обзавёлся новым паяльником, оловоотсосом, флюсом. Разумеется, опять помогая экономике Китая (ох уж этот путь нищеброда). В итоге всё шло по почте настолько долго и неравномерно (+ внезапно возникли дела по учёбе), что паять схему я начал, только когда прошли уже все сроки для открытия диспута по транзисторам. Заранее я их тоже не догадался проверить, потому что не умел. Лишь потом пришлось во всё это вникать, когда после пайки и сборки схемы оказалось, что ничего не работает: транзисторы поддельные и открываются только от 5 вольт, но не от 3.3, как должны по спецификации.

Собранная схема Разобранная схема соединения вентилятора с транзистором

В итоге я плюнул, расковырял всё обратно, отпаял, разделил парный коннектор на два отдельных провода, позаимствовав коннекторы у одного из проводов, которые покупал для Ардуины, и воткнул вентилятор в пин на 3.3 В, чтобы замедлить обороты и уменьшить шум (благо такой опыт у меня уже был с десктопным ПК, когда пришлось перепаивать коннектор нерегулирующегося вентилятора на мулекс по схеме с пониженным напряжением). В принципе, результатом доволен. Работает очень тихо и его совершенно не слышно.

Окончательный вид сервера

Результаты тестовых измерений температуры

На пассивном охлаждении в простое Апельсин даёт 36-37 °C. С небольшим обдувом — 27-29. До 59 градусов под 100% нагрузкой нагрелся, пока считал простые числа до 2000. Если время теста увеличить, выросло бы ещё, судя по динамике. С охлаждением под нагрузкой даёт 47-48. И, вроде бы, застыл на этих значениях.

В общем, выигрыш10 градусов спокойно даёт небольшой вентилятор на 3.3 V. С пятью выигрыш был бы ещё больше. Однако без постоянных и длительных нагрузок, в принципе, спокойно вывозит и обычный радиатор.


Динамический IP

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

Простейший набор бесплатного (а как мы помним, весь сыр-бор затевался именно ради экономии) решения проблемы отсутствия статического IP состоит из двух инструментов: Cloudflare и ddclient. Первый широко извествен как сервис, предоставляющий защиту от DDoS-атак, а также ускоряющий работу многих сайтов путём минификации и кэширования страниц в обширной сети своих CDN-серверов. Указываешь в настройках домена DNS-сервера Cloudflare, он чудесным образом автоматически определяет все записи и переносит их к себе. Дальше для каждой записи можно выбрать, будет ли доступ к указанному в адресе серверу осуществляться напрямую (то есть адрес сервера виден пользователям и доступен для атаки) или он будет спрятан за HTTP-прокси от Cloudflare, попутно подвергаясь магическим оптимизирующим преобразованиям. У них есть публичный API, чтобы можно было в зависимости от ситуации гибко управлять настройками сайта с помощью скриптов. И поскольку всё работает через DNS, то для него «ручки», разумеется, тоже имеются.

Тут на сцену выходит второй герой нашего набора нищеброда — ddclient — скрипт на языке Perl для отслеживания смены IP-адреса сервера и автоматического обновления DNS-записей. Он запоминает последний установленный через него IP-адрес и обращается к API только при получении нового адреса. Для получения фактического IP-адреса существует несколько вариантов, но для большинства домашних пользователей это будет обращение к внешнему сайту, который скажет IP, с которого к нему пришёл запрос.

Пример конфигурационного файла

/etc/ddclient.conf или /etc/ddclient/ddclient.conf:

daemon=60
protocol=cloudflare
use=web
server=www.cloudflare.com
ssl=yes
login=<адрес электронной почты>
password=<API-токен>
zone=<основной домен>
<домен>
<поддомен 1>
<поддомен 2>
…

Проблема с этим скриптом состоит в его нелёгкой судьбе. Оригинальная версия на SourceForge не обновлялась уже несколько лет. И вот похоже, что буквально на этой неделе Cloudflare отключил старые версии API, из-за чего всё сломалось. На GitHub есть форк, в котором реализована поддержка последней версии протокола. Я попытался его поставить, но он тоже сыплет ошибками и ничего не обновляет. В общем, пока всё очень плохо. Ждём фиксов.

И ладно бы это была первая проблема с ddclient'ом. Но нет! Различные неприятности с ним случались и до этого. Как будто на нём лежит какое-то древнее проклятье…


Архитектурные проблемы — ARM

Не то чтобы все домашние сервера были одноплатниками на ARMе, но благодаря пассивному охлаждению такой вариант выглядит куда привлекательнее, чем шумный и прожорливый ПК на x86. Но тут можно столкнуться с проблемой, что не всё ПО поддерживает данную архитектуру.

На самом деле всё не так плохо и большинство программ спокойно устанавливаются из репозиториев и нормально работают. Пока у меня возникла проблема только со сборкой Java-программ в EXEшники с помощью программы launch4j, которая не работает на ARMе. В принципе, можно попытаться обойти с помощью QEMU (опять же идея Кива), но для этого нужно нетривиально пердолить процесс сборки (вероятно, писать свой плагин для интеграции launch4j с Gradle/Maven), а также, судя по обсуждениям на форумах, и так небыстрый процесс сборки на слабеньких мобильных процессорах может растянуться ещё в несколько раз, так как эмуляция инструкций «полноценных» компьютеров даётся нелегко. В итоге я решил отказаться от данной затеи.


Обеспечение надёжности

А теперь серьёзная часть, касающаяся всех домашних серверов — обеспечение надёжности и бесперебойной работы сервера. Даже если не брать в расчёт возможность физического выхода из строя самого компьютера (что, конечно, является серьёзным допущением), существуют две куда более серьёзные и очевидные проблемы: бесперебойное обеспечение сервера электроэнергией и недопущение разрывов интернет-соединения. Согласитесь, отключение электричества или «пропажа интернета» (пусть даже и на относительно короткий срок) происходит гораздо чаще, чем поломка оборудования. За последний год могу припомнить несколько таких случаев, которые разрешались как за несколько минут, так и за несколько часов.

Что же с этим делать? Ну, во-первых, обзавестись источником бесперебойного питания. Причём желательно с аккумулятором побольше, чтобы сервер как можно дольше мог обходиться без внешнего источника питания (благо сам по себе он потребляет крайне мало электроэнергии, но нужно питать ещё и роутеры, которых может быть несколько, как в моём случае). Во-вторых, можно вставить в сервер модем с симкой какого-либо мобильного оператора и обмазаться скриптами для автоматического переключения подключений при пропаже соединения. Впрочем, тут появляется вопрос о том, сколько трафика мы можем себе позволить пропустить через такое соединение и не разориться?

Да, решение возникших проблем выйдет в копеечку и добавит много дополнительных хлопот и работы. А ведь мы ещё даже не рассмотрели вариант с поломкой самого одноплатника. Хотя никто и не говорил, что всё будет просто!.. Стоп, мне же как раз так и говорили. Хм…

Выводом из этого раздела является осознание факта, что хостеры кушают свой хлеб не даром: построение и обеспечение бесперебойной работы датацентра — это сложная и дорогостоящая задача. Только когда пытаешься построить собственную инфраструктуру, начинаешь понимать всю трудоёмкость этого процесса и ценить услуги хостинга. Были бы ещё деньги на его оплату…


Блокировки

Последней проблемой, о которой я даже не сразу вспомнил в силу её относительной новизны, являются блокировки российскими властями разных электронных ресурсов. Например, мессенджера Telegram, для которого я зачастил пилить ботов. Разумеется, теперь держать их на сервере в обычной российской квартире, подключённой к обычному российскому провайдеру, становится проблематично: адрес, на который отправляются запросы, заблокирован. Приходится использовать различного рода обходы блокировок, которые негативно сказываются как на скорости ответа, так и на надёжности в общем. Подробнее о них расскажу как-нибудь в другой раз и в не таком явном виде (а то мало ли).

Напомню также, что во время активной фазы войны Роскомнадзора с «Телеграммом» под удар попало и множество вполне легальных ресурсов. Периодически подобные эксцессы случались и ранее. Неприятно, когда что-то может «упасть», просто потому что чей-то IP-адрес случайно (или не совсем) попал в выгрузку. Не правда ли?


Выводы

На данный момент проект самохостинга свёрнут на неопределённое время, пока не решится проблема с обновлением DNS-записей. Но даже без этого надо понимать, что у самохостинга есть ряд серьёзных проблем с надёжностью. И если держать там небольшой бложик, на который практически никто никогда не заходит, ещё нормально, то вот для тех же ботов это может быть куда критичнее (как же бесит огромное множество неработающих ботов в Telegram!). Я собирался перенести ряд некритичных и редко посещаемых ресурсов с платного VPS на домашний сервер, но теперь, видимо, их придётся закрыть совсем.

Нет свободной оперативной памяти

Поскольку я до сих пор нищий безработный и оплачиваю хостинг с доменами на подарочные деньги за Новый год и день рождения, то пользуюсь самым дешёвым тарифом на VPS, который нашёл — 12 долларов в год (со скидкой бывает 9). И в последнее время я стал упираться в установленные лимиты по оперативной памяти — 128 Мб (на скрине 256, потому что, видимо, ещё 128 Мб выделены под систему и не учитываются). Пока всё более-менее работает, однако Линукс уже начал чистить страницы из памяти и убивать процессы-воркеры веб-сервера (чем освободил память почти на четверть), так что дальнейшее добавление сервисов и расширение существующих представляется затруднительным. Выхода два: либо платить больше, либо ужиматься в то, что имеем.

Следующий тариф обойдётся в $2.5-3 в месяц (я не понимаю, почему KVM-виртуализация у них дешевле, чем OpenVZ). Если пойти этим путём, сумма оплаты за хостинг превысит 2 000 рублей в год. Что на данный момент для меня является неподъёмной суммой (так как вместе с доменами это уже будет около 3 000 рублей, а подарки за день рождения в этом году уже ушли в расход). Так что придётся как-то сбавлять аппетиты и урезать количество сервисов, закрывая самые неприоритетные и непопулярные. Благо простора для оптимизации много! Ну либо ждать и надеяться, что кто-нибудь придёт и решит задонатить ;)

На этой попрошайнической ноте, пожалуй, я и закончу данный пост. До скорых встреч, друзья!