Поиск по сайту:

Как создать собственный динамический 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