Как создать собственный динамический DNS с помощью AWS Route 53
Если у вас дома работают серверы, вы не сможете направить на них домен без статического IP-адреса. Вместо того чтобы платить за динамический DNS-сервис, вы можете создать свой собственный с помощью AWS Route 53.
Динамический DNS не сложен
Концепция динамического DNS довольно проста. Демон запускается на клиентском компьютере и регулярно проверяет общедоступный IP-адрес на предмет любых изменений. Если IP-адрес меняется, демон отправляет обновление провайдеру DNS, который изменяет запись. Это часто предлагается в качестве платной услуги многими регистраторами доменов и провайдерами DNS.
У AWS нет специального сервиса для предоставления динамического DNS, но его довольно просто настроить самостоятельно. «Способ AWS» для этого — настроить событие CloudWatch, которое запускает функцию Lambda в ответ на изменения инфраструктуры. (Хотя в большинстве сценариев вам, вероятно, следует просто использовать балансировщик нагрузки и группу автоматического масштабирования.)
Однако, если вы хотите настроить динамический DNS для домашнего сервера или другого устройства, отличного от AWS, которое будет иметь частые изменения IP-адреса, написать сценарий довольно просто. Route 53 имеет простые команды CLI, которые можно использовать для обновления записей DNS из командной строки; подключение этого к заданию cron, которое следит за изменением общедоступного IP-адреса и запускает интерфейс командной строки AWS, выполнит свою работу.
Что касается цен, Route 53 на самом деле не стоит дорого — фиксированная плата в размере 0,50 доллара США в месяц за каждое доменное имя плюс несколько незначительных сборов за поиск DNS в зависимости от использования. Записи A бесплатны (наиболее распространенный поиск), поэтому вы, вероятно, не увидите в своем счете больше нескольких центов в месяц, если только вы не привлекаете серьезный трафик. Для сравнения, цена DynDNS начинается с 55 долларов в год.
Настройка стороны AWS
Чтобы начать работу, перейдите в консоль управления AWS Route 53. Если у вас нет домена, вы можете зарегистрировать его в разделе «Зарегистрированные домены» довольно дешево, как правило, в размере регистрационного взноса ICANN. Если ваш домен в настоящее время не находится в Route 53, вам придется перенести его, что является простым, но длительным процессом.
Найдите или создайте зону хостинга для вашего домена, которая будет содержать все записи. Вы захотите записать идентификатор размещенной зоны, так как он понадобится вам для скрипта.
Вы захотите создать запись-заполнитель A, чтобы в сценарии было на что ссылаться. Вы можете установить что-то явно неправильное — 255.255.255.255
будет работать — чтобы проверить функциональность скрипта.
Вам также потребуется настроить интерфейс командной строки AWS, что вы можете сделать с помощью:
curl "https://d1vvhvl2y92vvt.cloudfront.net/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install
И настройте его с учетными данными пользователя IAM с помощью:
aws2 configure
Написание сценария
Если вам просто нужен сценарий, вы можете обратиться к этой сути, но мы объясним, как он настроен, потому что это круто. Если вы просто копируете и вставляете, вам придется изменить переменные HOSTED_ZONE_ID
и NAME
, чтобы они соответствовали записи, которую вы пытаетесь обновить. Обратите внимание, что этот скрипт также использует интерфейс командной строки aws2
, который вам придется изменить, если вы используете версию 1.
Во-первых, нам понадобится способ программно получить наш общедоступный IP-адрес. Для этого мы можем использовать API AWS checkip.amazonaws.com. Это совершенно бесплатно, и нет ограничений по скорости. Вы также можете использовать для этой цели api.ipify.org, который также является бесплатным и неограниченным. Мы загрузим это в переменную и сохраним на потом.
IP=$(curl https://api.ipify.org/)
Затем нам нужно будет проверить это, чтобы убедиться, что мы вернули действительный IP-адрес, а не код ошибки или что-то искаженное. Для этой цели достаточно просто проверить, что ввод представляет собой числа, разделенные точкой, поэтому немного регулярного выражения вместе с оператором =~
(возвращает true, если регулярное выражение соответствует вводу слева, очень полезно) сделает свое дело. :
if [[ ! $IP =~ ^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$ ]]; then exit 1 fi
Нам нужно сравнить это с нашим старым IP-адресом, чтобы увидеть, изменилось ли что-нибудь. Мы могли бы сохранить это на диске в виде файла в /tmp/
, но это беспорядочно и чревато ошибками. Вместо этого мы запросим Route 53 напрямую с помощью list-resource-record-sets
и отфильтруем IP-адрес из записи, которую мы пытаемся обновить, с помощью jq
:
aws2 route53 list-resource-record-sets --hosted-zone-id Z1VCYR76DBUXPL | jq -r '.ResourceRecordSets[] | select (.Name == "'"$NAME"'") | select (.Type == "'"$TYPE"'") | .ResourceRecords[0].Value' > /tmp/current_route53_value
Это сохраняет его в /tmp/current_route53_value
, который мы затем можем использовать для проверки с помощью grep
, который достаточно устойчив:
if grep -Fxq "$IP" /tmp/current_route53_value; then echo "IP Has Not Changed, Exiting" exit 1 fi
Наконец, мы готовим полезную нагрузку для change-resource-record-sets
. Это должно быть в формате JSON, поэтому мы выведем файл на диск и отправим его в качестве аргумента команде.
cat > /tmp/route53_changes.json << EOF { "Comment":"Updated From DDNS Shell Script", "Changes":[ { "Action":"UPSERT", "ResourceRecordSet":{ "ResourceRecords":[ { "Value":"$IP" } ], "Name":"$NAME", "Type":"$TYPE", "TTL":$TTL } } ] } EOF #update records aws2 route53 change-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID --change-batch file:///tmp/route53_changes.json
Все объединяется, чтобы сформировать следующий сценарий. Вы захотите изменить переменные HOSTED_ZONE_ID
и NAME
, чтобы они соответствовали записи, которую вы пытаетесь обновить. Обратите внимание, что NAME
имеет точку в самом конце.
#!/bin/bash #Variable Declaration - Change These HOSTED_ZONE_ID="XXXXXXXXXXXX" NAME="example.com." TYPE="A" TTL=60 #get current IP address IP=$(curl http://checkip.amazonaws.com/) #validate IP address (makes sure Route 53 doesn't get updated with a malformed payload) if [[ ! $IP =~ ^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$ ]]; then exit 1 fi #get current aws2 route53 list-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID | jq -r '.ResourceRecordSets[] | select (.Name == "'"$NAME"'") | select (.Type == "'"$TYPE"'") | .ResourceRecords[0].Value' > /tmp/current_route53_value cat /tmp/current_route53_value #check if IP is different from Route 53 if grep -Fxq "$IP" /tmp/current_route53_value; then echo "IP Has Not Changed, Exiting" exit 1 fi echo "IP Changed, Updating Records" #prepare route 53 payload cat > /tmp/route53_changes.json << EOF { "Comment":"Updated From DDNS Shell Script", "Changes":[ { "Action":"UPSERT", "ResourceRecordSet":{ "ResourceRecords":[ { "Value":"$IP" } ], "Name":"$NAME", "Type":"$TYPE", "TTL":$TTL } } ] } EOF #update records aws2 route53 change-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID --change-batch file:///tmp/route53_changes.json >> /dev/null
Настройте свой Crontab
Вы можете редактировать свой crontab с помощью:
crontab -e
Вы можете настроить запуск этого скрипта каждую минуту, так как он довольно легкий. Дайте cron путь к вашему скрипту на диске. Вы можете отправить выходные данные в файл журнала или в /dev/null
, если не хотите с ними иметь дело.
* * * * * /home/user/update_dns.sh >/dev/null 2>&1