Запуск домашнего веб-сервера без статического IP с помощью Python
Приветствую жителей Хабра!
Задался тут вопросом, как можно обойтись без статического IP для экспериментов в домашних условиях. Наткнулся на вот эту статью.
Если вы хотите развернуть свой вебсервер с доступом извне, а платить провайдеру за статический IP не хотите, то данное решение вполне себе выход, которое можно в дальнейшем подогнать под свои нужды.
Недавно я решил установить веб-сервер на Rasberry Pi, работающий за моим домашним маршрутизатором. У меня есть опыт настройки веб-серверов на виртуальных машинах Linux со статическими IP-адресами, поэтому в настройке сервера apache2 на Pi нет ничего особенного, и в Интернете есть сотни руководств. Проблема только в том, что при изменении внешнего IP вашего роутера сайт сломается! Один из способов решить эту проблему — заплатить своему интернет-провайдеру за статический IP-адрес… но тогда в чём веселье?!
Во многих своих последних проектах я использовал Google Domains для покупки доменного имени и обычно запускал сайты без собственных гугловских серверов имен на отдельном VPS/«облачном сервере». Но для моего домашнего сервера я решил использовать невероятно простую в настройке функцию переадресации IP-адресов поддоменов, чтобы перенаправить базовый домен (@.example.com) на IP-адрес моего маршрутизатора (а затем настроить мой маршрутизатор на перенаправление с http портов на https порты на Pi). Тогда мне пришлось бы вручную проверять, работает ли сайт, и менять IP при необходимости. Очевидно, это не идеальный план, поэтому я решил написать скрипт для автоматизации этого процесса.
На заметку, вы можете найти полный скрипт на гитхабе или импортировать пакет Python с помощью pip install domains-api
Есть много способов проверить ваш внешний IP-адрес, и один из самых простых, которые я нашел, был через ipify API (api.ipify.org), который просто возвращает ваш общедоступный IP-адрес. При использовании Python библиотеки requests запрос выглядит следующим образом:
Вот и все, это ваш внешний IP. Легко, правда? Есть много других подобных способов получить внешний IP-адрес, но я считаю, что это самый простой.
Итак, что еще нам нужно для нашего скрипта? Нам нужно где-то хранить IP-адрес, чтобы проверять будущие запросы. Изначально я решил сохранить его в простом текстовом файле. Нам также нужен способ либо уведомить пользователя, либо обновить domain.google.com, либо и то, и другое. Первый вариант довольно легко реализовать с помощью библиотеки электронной почты для Python, поэтому я настроил её для работы с моей учетной записью Gmail следующим образом (вам нужно будет разрешить менее безопасные приложения (less secure apps) в своей учетной записи Google):
Одна вещь, которая немного беспокоит здесь, — это сохранение вашего пароля от учетки Gmail в переменной, поэтому я решил на этом этапе хотя бы немного зашифровать его, добавив один уровень кодирования к паролю перед его сохранением. Опять же, есть много способов, которые могут предложить более или менее сносную защиту, но я решил, что для моих целей будет в достаточной мере надежно, если пароль будет закодирован в base64 при сохранении на сервере, поэтому я написал следующие функций: одна для кодирования/сохранения пароля и одна для получения/декодирования сохраненного пароля:
Теперь я мог бы заменить константу GMAIL_PASSWORD из функции уведомления на функцию read_pwd() (которая возвращает декодированный пароль), что всяко безопаснее.
Последнее, что мне нужно, чтобы программа стала эффективной, — это дописать функцию, которая свяжет всё вместе и сохранит/сравнит IP-адреса:
Бум! Это была первая реализация моей идеи. Когда я получаю уведомление по электронной почте, я могу просто изменить правила переадресации на сайте domains.google.com…
Стоп, что? Мне все еще нужно это делать самому? Конечно нет, есть способ проще!
Что ж, оказывается, есть два способа автоматизировать это — один значительно менее эффективный, но бесконечно более захватывающий, а другой довольно скучный, но бесконечно более эффективный! Я начну, как и сделал, с захватывающего и сложного способа: слышали когда-нибудь о Selenium для автоматизации тестирования веб-сайтов? Я решил написать сценарий, который будет физически входить в домены Google и перемещаться по сайту, чтобы изменить правила для меня, если и когда изменится IP. Однако это приводило к следующим проблемам:
Прежде всего, Google Domains (и другие сервисы Google, такие как Gmail) довольно хорошо обнаруживают автоматизацию браузера и просто не позволяют вам войти в систему через веб-драйвер Selenium. Мне посчастливилось найти этот ответ (есть и другие решения) в Stack Overflow, который предлагал войти в сам Stack Overflow с вашей учетной записью Google, прежде чем переключаться на желаемую службу Google, что действительно работало, пока я не брал под контроль браузер и при необходимости не вводил капчу. Со скриптом, запущенным на моем ноутбуке или десктопе, это замечательно — тем более, что после первоначальной проверки Captcha StackOverflow, похоже, больше не проверял тот же компьютер, поэтому после этого веб-драйвер можно было запустить в автономном режиме, но это не подходит для веб-сервера! Хотя я мог заставить веб-драйвер нормально работать с помощью PyVirtualDisplay и Geckodriver (веб-драйвер для Firefox), ему удавалось только один раз попасть на желаемую страницу «Мои домены», а в других случаях вообще не мог войти в систему из-за Captcha.
После того, как я провозился с этим и пытался дебежить/работать над этим полдня, я решил, что это безнадежное дело, так как в любом случае всё, что потребуется, — это немного изменить одну из страниц, на которой я просматривал информацию, и вся работа скрипта будет нарушена. Поэтому я решил прибегнуть к скучному методу, который до сих пор я по глупости не изучал очень глубоко.
Так уж получилось, что у Google Domains есть API именно для той цели, которая мне нужна. Я изначально отклонил APi, когда не смог заставить его работать с правилами переадресации поддоменов, которые я использовал, не понимая, что API предназначен для изменения правил динамического DNS — эта документация стала намного более понятной после того, как я настроил запись динамического DNS вместо стандартного правила «Переадресация поддоменов» (спасибо Джереми Гейлу за его отличный урок о том, как сделать что-то подобное с помощью простого сценария bash, который помог мне победить эту проблему!)
Раздел «Synthetic records» на странице конфигурации DNS Google Domains должен выглядеть следующим образом:
Затем вы получите автоматически сгенерированные учетные данные, необходимые для аутентификации с помощью API:
Теперь, зная этот метод, я смог значительно уменьшить длину и нагрузку на скрипт! TTL динамического DNS также очень низок, по умолчанию: 1 мин, что сокращает возможное время простоя — ещё один дополнительный бонус. Всё, что мне было нужно, это включить вызов API в мою функцию check_ip(), и он сделает все за меня! И эта единственная строка кода (2 с вызовом логирования) выглядит так:
Я заключил всё в блок try / except, чтобы перехватить любые исключения, и таким образом этот довольно простой, но удивительно полезный скрипт был почти готов. Теперь осталось только добавить его в crontab на моем веб-сервере и дать ему работать, и (теоретически) мне больше не придется беспокоиться о смене IP!
Стоп! … Время рефакторинга
Готовый, практически уникальный (!) результат можно увидеть ниже во всей его полноте, а также его можно форкнуть/клонировать с моего GitHub (включая README.md с инструкциями по установке). Я также выпустил его как пакет Python на pypi.org, который вы можете просмотреть здесь или установить обычным способом с помощью: pip install domains-api
Любые вопросы, отзывы или предложения — пишите!
Какие ещё методы стабильной работы веб-сервера без статического адреса вы знаете? И как можно доработать это решение?
Как написать dns сервер на python
A Domain Name Server that allows you to use your own domain name IP address mappings. This could be used within private networks to simplify sharing of resources within the network.
The application requires Python 3.x to run (tested with version 3.6).
To use the server there are 2 basic steps to follow:
Step 1: You must first generate a zone file. This is the file that stores the domain name and it’s IP address mapping. To generate a zone file you must create a file with the following filename format: [domain name in reverse order].zone. Examples:
An example zone file is provided in the project. You can simply copy the detail inside and change the relevant fields for your own mapping. In particular you will need to change the domains in the following fields:
Ensure the domain names placed in the fields match with the filename to avoid errors Finally the ‘a’ field holds 3 records for the IP address mapped to the domain name. Ensure you change them to the correct IP address.
Step 2: Once the zone file is created and placed in the ‘Zones’ directory you can start the server. No special modifications are needed to run the server. You can simply run the ‘Server.py’ file. Ensure that you run the ‘Server.py’ with the necessary privileges required for the program to access network resources.
Note: The server uses the default DNS server port (53). Ensure no other process is using port 53 or else the server will not be able to run.
Now you can change the network configurations on various machines that need to use this DNS server by specifying the IP address of the machine running the DNS server.
To see an example run you can use the ‘dig’ command on Linux to see the response the server provides.
You should receive a response for the domain xyz.com Once you have set your own zone file you can replace ‘xyz.com’ with your own domain name. You can change the IP address ‘127.0.0.1’ to the IP address where the DNS server is running when you have it running on a remote machine on the network.
Note: if you have updated your network configurations to use a specific IP for the dns server then there is no need to include the ‘@127.0.0.1’ portion in the command.
Составляем DNS-запрос вручную
Об авторе. Джеймс Рутли — бэкенд-разработчик в компании Monzo.
В этой статье мы изучим двочиный формат сообщений Domain Name Service (DNS) и напишем вручную одно сообщение. Это больше, чем вам нужно для использования DNS, но я подумал, что для развлечения и в образовательных целях интересно посмотреть, что находится под капотом.
Обзор DNS
DNS используется для перевода человекочитаемых доменных имён (таких как example.com ) в машиночитаемые IP-адреса (такие как 93.184.216.34). Для использования DNS нужно отправить запрос на DNS-сервер. Этот запрос содержит доменное имя, которое мы ищем. DNS-сервер пытается найти IP-адрес этого домена в своём внутреннем хранилище данных. Если находит, то возвращает его. Если не может найти, то перенаправляет запрос на другой DNS-сервер, и процесс повторяется до тех пор, пока IP-адрес не будет найден. Сообщения DNS обычно отправляются по протоколу UDP.
Стандарт DNS описан в RFC 1035. Все диаграммы и бóльшая часть информации для этой статьи взята в данном RFC. Я бы рекомендовал обратиться к нему, если что-то непонятно.
Формат запроса
У всех сообщений DNS одинаковый формат:
Вопрос и ответ находятся в разных частях сообщения. В нашем запросе будут секции «Заголовок» и «Вопрос».
Заголовок
У заголовка следующий формат:
На этой диаграмме каждая ячейка представляет единственный бит. В каждой строчке 16 колонок, что составляет два байта данных. Диаграмма поделена на строки для простоты восприятия, но реальное сообщение представляет собой непрерывный ряд байтов.
Поскольку у запросов и ответов одинаковый формат заголовка, некоторые поля не имеют отношения к запросу и будут установлены в значение 0. Полное описание каждого из полей см. в RFC1035, раздел 4.1.1.
Для нас имеют значение следующие поля:
Полный заголовок
Совместив все поля, можно записать наш заголовок в шестнадцатеричном формате:
Вопрос
Секция вопроса имеет следующий формат:
Для составления надписи нужно закодировать каждую секцию URL, получив ряд байтов. Надпись — это ряд байтов, перед которыми стоит байт беззнакового целого, обозначающий количество байт в секции. Для кодирования нашего URL можно просто указать ASCII-код каждого символа.
В секции QNAME разрешено нечётное число байтов, так что набивка байтами не требуется перед началом секции QTYPE.
Отправка запроса
Мы отправляем наше DNS-сообщение в теле UDP-запроса. Следующий код Python возьмёт наш шестнадцатеричный DNS-запрос, преобразует его в двоичный формат и отправит на сервер Google DNS по адресу 8.8.8.8:53.
Чтение ответа
После выполнения скрипт выводит ответ от DNS-сервера. Разобьём его на части и посмотрим, что можно выяснить.
Заголовок
Сообщение начинается с заголовка, как и наше сообщение с запросом:
Преобразуем 81 80 в двоичный формат:
Преобразуя эти биты по вышеуказанной схеме, можно увидеть:
Секция вопроса
Секция вопроса идентична такой же секции в запросе:
Секция ответа
У секции ответа формат ресурсной записи:
Первые два бита установлены в значение 1, а следующие 14 содержат беззнаковое целое, которое соответствует смещению байт от начала сообщения до первого упоминания этого имени.
В данном случае смещение составляет c0 0c или двоичном формате:
Расширения
Мы увидели, как составить DNS-запрос. Теперь можно попробовать следующее:
Как создать очень простой сервер DNS с помощью Python?
Я просто хочу создать сервер DNS, который слушает запросы и всегда возвращает один и тот же конкретный ip. Я использую Python.
1 ответ
Есть ли какой-нибудь сервер DNS, написанный на python, где я могу легко использовать пользовательский бэкэнд? В принципе, я просто хочу ответить на запросы для некоторых доменных имен с помощью моего собственного IPs, но передать rest запросов на реальный сервер DNS.
Я добавляю функцию в свой текущий проект, которая позволит сетевым администраторам устанавливать программное обеспечение в сеть. Мне нужно закодировать сервер DNS в Python, который позволит мне перенаправить на определенную страницу, если адрес запроса находится в моем списке. Я смог написать.
Похожие вопросы:
У меня есть сервер linux, имеющий специальную беспроводную сеть для подключения клиентов. После подключения я хочу, чтобы пользователи всегда перенаправлялись на свой собственный веб-сервер.
у меня есть простой сервер python cgi: import BaseHTTPServer import CGIHTTPServer import cgitb; cgitb.enable() ## This line enables CGI error reporting server = BaseHTTPServer.HTTPServer handler =.
Есть ли какой-нибудь сервер DNS, написанный на python, где я могу легко использовать пользовательский бэкэнд? В принципе, я просто хочу ответить на запросы для некоторых доменных имен с помощью.
Я добавляю функцию в свой текущий проект, которая позволит сетевым администраторам устанавливать программное обеспечение в сеть. Мне нужно закодировать сервер DNS в Python, который позволит мне.
Я хотел бы создать локальный сервер https с помощью express, который обрабатывает любой поддомен example.com. В идеале я хотел бы изменить свой файл hosts следующим образом: 127.0.0.2 localhost.
Я использую windows 7 и python 2.7 я хочу сопоставить 172.16.45.84 IP адрес с myapp.nobies.in без сопоставления в файле hosts. У меня есть необходимый сертификат на это имя хоста. Я не хочу.
Я успешно установил сервер по умолчанию DNS с wmi, как это SetDNSServerSearchOrder([dns]) Но я не могу найти, Как установить вторичный DNS с python
Python DNS сервер
Я добавляю функцию в свой текущий проект, которая позволит сетевым администраторам устанавливать программное обеспечение в сеть. Мне нужно закодировать сервер DNS в Python, который позволит мне перенаправить на определенную страницу, если адрес запроса находится в моем списке. Я смог написать сервер, просто не знаю, как перенаправить.
Спасибо. Я использую Python 2.6 на Windows XP.
4 ответа
у меня есть простой сервер python cgi: import BaseHTTPServer import CGIHTTPServer import cgitb; cgitb.enable() ## This line enables CGI error reporting server = BaseHTTPServer.HTTPServer handler = CGIHTTPServer.CGIHTTPRequestHandler server_address = (, 8000) httpd = server(server_address, handler).
Есть ли какой-нибудь сервер DNS, написанный на python, где я могу легко использовать пользовательский бэкэнд? В принципе, я просто хочу ответить на запросы для некоторых доменных имен с помощью моего собственного IPs, но передать rest запросов на реальный сервер DNS.
Использование:
Я использую windows 7 и python 2.7 я хочу сопоставить 172.16.45.84 IP адрес с myapp.nobies.in без сопоставления в файле hosts. У меня есть необходимый сертификат на это имя хоста. Я не хочу сопоставлять данные в файле hosts, так как это требует административных привилегий. Итак, как создать для.
Вот dns serer/прокси, который работает для меня, написанный на python:
Похожие вопросы:
Предположим, что на моей машине настроен прокси-сервер. Предположим теперь, что я хочу посетить www.sitename.com, что произойдет? В частности, я отправляю запрос HTTP GET www.sitename.com на.
На нашем маршрутизаторе у нас есть основной DNS, установленный на локальный IP, который работает под управлением Windows Server 2008 и встроенного сервера DNS. Мы используем это для разрешения.
Мне нужно реализовать сервер DNS в C, и я не знаю, с чего начать. Каковы все функции, которые a DNS has. how может реализовать a bare-bones DNS в одном файле C. Я даже не хочу использовать базу.
у меня есть простой сервер python cgi: import BaseHTTPServer import CGIHTTPServer import cgitb; cgitb.enable() ## This line enables CGI error reporting server = BaseHTTPServer.HTTPServer handler =.
Есть ли какой-нибудь сервер DNS, написанный на python, где я могу легко использовать пользовательский бэкэнд? В принципе, я просто хочу ответить на запросы для некоторых доменных имен с помощью.
Я использую windows 7 и python 2.7 я хочу сопоставить 172.16.45.84 IP адрес с myapp.nobies.in без сопоставления в файле hosts. У меня есть необходимый сертификат на это имя хоста. Я не хочу.
Я просто хочу создать сервер DNS, который слушает запросы и всегда возвращает один и тот же конкретный ip. Я использую Python.
Я успешно установил сервер по умолчанию DNS с wmi, как это SetDNSServerSearchOrder([dns]) Но я не могу найти, Как установить вторичный DNS с python