[Из песочницы] Домашний хостинг сайтов с динамическим IP

У меня (как и у многих web-разработчиков) имеется с десяток сайтов которые необходимо где-то размещать (хостить).

Сайты практически не приносят прибыли, поскольку это какие-то старые работы (по разным причинам не пошедшие в продакшн), домашняя страница, сайт заведенный красивой почты и тому подобное. Но в то же время эти сайты жалко бросать, а потому приходится каждый месяц на них тратить вполне реальные деньги чтобы покупать хостинг. Деньги, прямо скажем небольшие, но тем не менее их жалко, поскольку отдачи от сайтов никакой нет.

В то-же время в наличии имеется:

  • Домашний сервер на Ubuntu
  • Быстрый ethernet-интернет от МТС

Но не имеется ключевого — статического IP. Если бы он был, то все было-бы намного проще и данную статью я бы точно не писал. А выдавать статический IP мой МТС абсолютно не желает (если только я не подключусь как бизнес-клиент).

Разумеется есть всем известные Dynamic DNS сервисы вроде noip.com, но они успешно решают лишь задачу удаленного доступа к нашему серверу (по SSH или FTP), но для хостинга совершенно нам не подходят, поскольку в настройках домена на DNS-сервере нам нужно обязательно прописать A-запись с реальным IP-адресом (а не ссылку на наш виртуальный домен).

Что делать?


Я не буду останавливаться на том, как настроить linux сервер (и тем более как его выбрать), поскольку предполагаю, что он у вас уже есть. Также я не буду подробно расписывать настройки nginx и Apache, поскольку опять-таки предполагаю, что вы с этим справитесь самостоятельно.

Первое с чем у меня возникли проблемы — это как перенаправить посетителей с моих доменов (у меня есть 2 домена) на мой домашний сервер. То есть чтобы клиент который набрал domain.com попал ровно на мой домашний сервер с учетом того, что на нем каждый день меняется IP-адрес.

Для решения нам нужно настроить DNS-сервер, а именно следующие записи: SOA, NS, MX, A, CNAME. Важно чтобы мы имели возможность настройкой TTL (time to live), поскольку время жизни наших записей должно быть очень небольшим, буквально 60–120 секунд. В противном случае при смене IP-адреса сервера пользователи долго не смогут попасть на наш сервер (из-за кеширования).

Итак, нам нужен DNS сервер, варианты решения:

  1. Используем сервисы которые предоставляют нам DNS-хостинг
  2. Используем собственный DNS-сервер в связке с DDNS-доменом

Рассмотрим оба варианта.

Используем сервисы которые предоставляют нам DNS-хостинг


Для этого есть ряд бесплатных сервисов, из которых самым популярным является freedns.afraid.org. На таких сервисах можно добавить свой домен (ы) и получить возможность через API обновлять у них A-запись при помощи небольшого скрипта.

Выглядит вполне неплохо, но подвох в том, что эти сервисы оставляют за собой право довешивать к вашему домену поддомены третьего уровня. То есть вы зарегистрировали у них user.ru, а они спокойно довешают свои сайты вида hello.user.ru, shop.user.ru и так далее. Разумеется от этого можно отказаться, но… за деньги. Платить деньги за такие сервисы смысла я не вижу, поскольку за сравнимые деньги вы можете купить полноценный хостинг на каком-нибудь провайдере без всяких плясок вокруг DNS настроек.

Остальные сервисы рассматривать не будем, а сосредоточимся на втором варианте.

Используем собственный DNS-сервер в связке с DDNS-доменом


Для этого варианта у нас, во-первых, должен быть DDNS-домен (который обновляется при смене IP), например, domain.ddns.net, а во-вторых, придется установить и настроить BIND на нашем сервере.

Всего необходимо сделать ровно 5 шагов. Везде под словами «domain» или «domain.ru» подразумевается ваше имя домена (короткое или полное).

1. Настроить 2 или 3 DDNS-поддомена
Почему 2 или 3? Потому, что ряд регистрантов не разрешит вам использовать домен только с одним NS-сервером. Самое обидно, что не все про это скажут — ваш домен просто не будет работать, но вы не будете понимать почему.

Тут все просто — идем на noip.com, там регистрируем аккаунт и добавляем 3 бесплатных поддомена (больше 3 не даст).

2. Настраиваем собственный DNS-сервер
Устанавливаем BIND:
$ sudo apt-get install bind9

Создаем зоны (по одной зоне на каждый наш домен):
$ sudo nano /etc/bind/zones.my

с содержимым:
zone "domain.ru" {
	type master;
	file "/etc/bind/db.domain.ru";
};

и собственно файл с настройками зоны:
$ nano /etc/bind/db.domain.ru

и пишем внутри:
;
; BIND data file for local loopback interface
;
$TTL	60
@	IN	SOA	domain.ru. admin.domain.ru. (
			1477015437	; Serial
			10800		; Refresh
			3600		; Retry
			604800		; Expire
			1800 )		; Negative Cache TTL

@	IN	NS	domain.ddns.net.
@	IN	NS	domain.ddnsking.com.
@	IN	NS	domain.myftp.biz.

@	IN	MX	10 mx.yandex.net.

@	IN	A	1.2.3.4

mail	IN	CNAME	domain.mail.yandex.net.
*	IN	CNAME	domain.ru.

Примечание: обращаю внимание, что TTL устанавливаем равным 60 секунд. В файле /etc/bind/named.conf.local добавляем подключение нашей зоны:
include "/etc/bind/zones.my";

Все, рестартуем BIND:
$ sudo service bind9 restart

И глянем /var/log/syslog чтобы там не было сообщений об ошибках3. Настроить наш домен (ы)
Идем в панель управления регистратора и там в настройках нашего домена в качестве NS-серверов указываем созданные DDNS-поддомены:
nameserver1 = domain.ddns.net
nameserver2 = domain.ddnsking.com
nameserver3 = domain.myftp.biz

После этого возможно придется подождать несколько часов (или даже сутки) пока настройки среплицируются между всеми серверами.4. Настроить периодическое обновление IP-адресов
Мой роутер поддерживает обновление IP-адреса на одном домене, но мне нужно это делать сразу для 3-х доменов. Плюс нам надо обновлять IP-адрес в конфиге BIND’а, поэтому напишем скрипт который будет делать:
  1. Определять наш внешний IP-адрес
  2. Проверять изменился ли IP адрес, если не изменился, то ничего делать не надо
  3. Обновлять IP-адрес у всех DDNS-поддоменов через API сервиса noip.com
  4. Прописывать новый IP адрес в конфиг BIND’а
  5. Перезапускать BIND

Сам скрипт пусть будет на шелле:
#!/bin/sh

# This script works via noip.com service + local Bind server

# Settings
ZONES_CONFIG=zones.my
IP_FILE=./current_ip.txt
DDNS_USER=user
DDNS_PASS=password
DDNS_HOST=domain.ddns.net
DDNS_HOSTS=domain.ddns.net,domain.ddnsking.com,domain.myftp.biz

# Start
DATE=$(date +"%Y-%m-%d %H:%M:%S")

# detect an external IP
IP=$(dig +short $DDNS_HOST)
if [ $? -ne 0 ] || [ -z $IP ] || [ $IP = "0.0.0.0" ] ; then
	echo "$DATE Can't detect a remote IP. Aborting."
	exit 1
fi

# verify IP changing
PREV_IP="(unknown)"
if [ -e $IP_FILE ] ; then
	PREV_IP=$(cat $IP_FILE)
fi

if [ $IP = $PREV_IP ] ; then
	echo "$DATE IP '$IP' has not changed"
else
	echo "$DATE IP has been changed from '$PREV_IP' to '$IP'"

	echo "$DATE IP will be updated on DDNS server"
	/usr/bin/curl -u $DDNS_USER:$DDNS_PASS "https://dynupdate.no-ip.com/nic/update?hostname=$DDNS_HOSTS&myip=$IP"
fi
echo $IP > $IP_FILE

# check BIND config
cd /etc/bind
if [ ! -e $ZONES_CONFIG ] ; then
        echo "$DATE File $ZONES_CONFIG not found!"
        exit 1
fi

# read the list of active zones
ZONE_FILES=$(grep file $ZONES_CONFIG | grep -v ^# | perl -ne '/file "(.+)"/ && print "$1\n"')
for ZONE_FILE in $ZONE_FILES; do
        echo "$DATE Process the zone config $ZONE_FILE"

	cat $ZONE_FILE | perl -ne "s/([\t ]+IN[\t ]+A[\t ]+)[\d\.]*/\${1}${IP}/; print \${_}" > $ZONE_FILE.tmp

	if [ $(diff -w $ZONE_FILE $ZONE_FILE.tmp | wc -l) -ne 0 ] ; then
		# update serial number
		STAMP=$(date +%s)
		cat $ZONE_FILE.tmp | perl -ne "s/\d+(?=.+Serial)/$STAMP/; print \${_}" > $ZONE_FILE

		# reload BIND
		service bind9 reload

		echo "$DATE Config $ZONE_FILE is updated"
	else
		# nothing to do
		rm $ZONE_FILE.tmp
		echo "$DATE Config $ZONE_FILE is NOT changed"
	fi
done

Скрипт нужно запускать под рутом (чтобы ему хватило прав обновлять конфиги BIND’а и рестартовать его). Добавляем в crontab рута его запуск каждую минуту:
* * * * *	cd /home/root && ./update_bind_config.sh >> /var/log/update_bind_config.log

Пару слов про определение текущего IP-адреса. В скрипте выше это делается через резолвинг DDNS-поддомена domain.ddns.net. То есть сначала наш роутер его туда прописывает, а потом мы читаем. Это не очень хороший вариант, поскольку мы завязываемся на роутер и можем потерять несколько минут пока на DDNS-поддомене обновится IP-адрес на актуальный. Все это время наш сервер будет недоступен.

Поэтому у себя я использовал улучшенный вариант, который заодно не лазит в интернет:

IP=$(perl -le 'use LWP::UserAgent; my $content=LWP::UserAgent->new->get("http://router")->decoded_content(); $content =~ q(([\d\.]+)); print $1')

В данном варианте мы загружаем главную страницу роутера (через http), дальше регэкспом находим на ней текущий IP-адрес. Разумеется, этот вариант подходит далеко не всем, но на DD-WRT прошивках работает.5. Настройка роутера
Про необходимость настроить обращение к DDNS-сервису я уже писал, но еще не забывайте про необходимость настроить форвардинг портов на вашем роутере:
  • HTTP — TCP, 80-ый порт
  • DNS — TCP+UDP, 53 порт
Вывод
Итак, что я получил в итоге:
  • Мои сайты живут на домашнем сервере, за который я никому не плачу;
  • Мои домены резолвятся через мой собственный DNS-сервер, время жизни записей 1 минута, то есть обновление происходит очень быстро;
  • В качестве NS-записей указаны не реальные IP-адреса (которые у меня часто меняются), а DDNS-поддомены;
  • Актуальность записей в DDNS-поддоменах и в конфиге моего DNS-сервера обеспечивается автоматически, без какого-либо вмешательства со моей стороны.

По моим замерам, когда МТС (мой провайдер) обновляет мне IP-адрес, то мои сайты начинают работать спустя где-то 2 минуты. Это вполне приемлемо для меня.

P.S. Если кому-то понравилась данная заметка, то я могу написать вторую часть, где расскажу как настроить работу с использованием DNS-хостинга Яндекса. Это позволит отказаться от собственного DNS-сервера, отказаться от DDNS-поддоменов, плюс чуть улучшит надежность работы (поскольку DNS-сервер никогда не будет менять свой IP). Именно такую схему я использую в настоящий момент.

Комментарии (13)

  • 24 октября 2016 в 12:42 (комментарий был изменён)

    +1

    > в настройках домена на DNS-сервере нам нужно обязательно прописать A-запись с реальным IP-адресом (а не ссылку на наш виртуальный домен).
    А я в настройках DNS как раз писал имя виртуального домена (толи в A, то ли CNAME, было давно, не помню), и всё работало. Т.е. выглядело примерно так: домен.ru — DNS регистратора — tra-la-la.dyndns.com — серый_ип. Не знаю должно было так работать, или нет, но проработало пару лет, потом белый адрес появился.
    • 24 октября 2016 в 12:50

      +1

      Абсолютно так сейчас и, к примеру, у меня работает. noip дает домен третьего уровня, роутер постоянно обновляет IP для него, а у DNS записи домена прописан CNAME для домена noip, и все прекрасно работает.
      • 24 октября 2016 в 13:25

        0

        Вы абсолютно правы, CNAME с доменом прописать можно. Я пару дней именно на такой схеме и поработал, но у нее есть глобальный недостаток — ваш domain.com не будет резолвится DNS-серверами в IP-адрес.

        То есть www.domain.com будет работать, тут проблем нет. А вот сам domain.com не будет, поскольку для него обязательно наличие A-записи с реальным IP-адресом. Редирект посредством DNS вы не настроите (на www версию), а web-редирект или rewrite rule опять-таки требуют чтобы посетители попадали на ваш domain.com, а они тут просто не попадают.

        Именно чтобы исправить этот недостаток, я и поднимал свой DNS-сервер (что не помогло), а потом в итоге добавил эту злосчастную A-запись.

  • 24 октября 2016 в 12:46

    +3

    Поздравляю, у вас белый IP, просто он не постоянный. А серый IP — это когда вы за NAT сидите, и извне к вам никто постучаться не может, только вы можете пойти наружу.
  • 24 октября 2016 в 12:52

    +2

    > Но не имеется ключевого — белого (статического) IP.

    Мне кажется, автор не полностью понимает чем отличаются между собой «белый» и «серый» IP адреса.

    • 24 октября 2016 в 13:20 (комментарий был изменён)

      0

      Автор просто это забыл за давностью лет (9 лет назад ушел из админства). :) Спасибо за отзыв, поправил.
  • 24 октября 2016 в 13:02

    +1

    «Белый» и «статический» — это разные характеристики IP-адреса.
    Белый/серый — оно же реальный/приватный — могут быть как статическими, так и динамическими.

    Так что поправьте заголовок и немного текст. У вас обычная задача доступа к серверу с динамическим реальным IP, она несложная. Вот если бы вы действительно с серым (приватным) адресом сайт подняли и сделали к нему доступ из интернета…

    • 24 октября 2016 в 13:13

      +1

      Спасибо за отзыв, поправил терминологию: белый → статический, серый → динамический.
    • 24 октября 2016 в 13:18

      0

      У вас обычная задача доступа к серверу с динамическим реальным IP, она несложная. Вот если бы вы действительно с серым (приватным) адресом сайт подняли и сделали к нему доступ из интернета…

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

      Рассматривал и вариант с VPN-тунелем, но опять-таки надо где-то иметь сервер с статическим IP.

  • 24 октября 2016 в 13:18

    0

    Решение задачи интересное для динамического IP, но я в такой же ситуации арендовал VPS за 4 евро в месяц самую дешевую, 20 гб места. Это выходит дешевле чем платить за электричество которое тратит всегда включенный компьютер дома, плюс избавляет от геморроя хардварной поддержки сервера. Ну из плюсов ещё можно считать, что даже отключения электричества мне не мешают. Ну и на сервере завел себе почту и owncloud с календарем и контактами. Так что аптайм стал очень важен для меня.
    • 24 октября 2016 в 13:46

      0

      Минимальный тарифный план который подходил мне (на тот момент было 3 домена, с кучей поддоменов, плюс пара MySQL баз, плюс почта) стоил 9$ в месяц.

      VPS — это получится некий промежуточный вариант — надо и самому с настройкой сервера возится, плюс платить за него каждый месяц.

      А про почту — я в итоге пришел к решению от Яндекса — http://pdd.yandex.ru

  • 24 октября 2016 в 13:33

    0

    А аптайм влияет на ранжирование в поисковиках? Слышал, что влияет. Не могли бы вы в следующей статье хотя бы примерно накидать сравнение с удаленным хостингом по экономическим затратам (по электричеству, износу ж/д и т.п.). Как насчет юридической составляющей? Многие отказываются сейчас размещать сайты на серверах в России из-за последних неадекватных решений правительства. Какие юридические риски, размещения на домашнем сервере? Спасибо.
  • 24 октября 2016 в 13:48

    0

    А что мешает использовать DNS от yandex?
    Там есть API, все изумительно работает и из под Linux и из под Windows.
    Была на хабре пара статей на этот счет.
    Даже для Microtik делали DNS апдейт при поднятии PPPoE сессии.

© Habrahabr.ru