Как настроить доменные имена для домашнего сервера в локальной сети без DNS-сервера?
На домашнем сервере часто одновременно работают разные веб-сервисы: сайты, умный дом, облачное хранилище, медиасервер. Пользователям неудобно открывать их по IP-адресу и разным портам. Хочется короткие адреса вроде homeassistant.local вместо 192.168.1.50 и plex.local вместо 192.168.1.50:32400.
Настроить полноценный локальный DNS получается не всегда. Даже если такая возможность есть, самодельные доменные зоны, даже .lan, в современных браузерах могут восприниматься как поисковый запрос, если не указать протокол.
Доменная зона .home.arpa специально выделена для домашних сетей, но она решает задачу только при наличии DNS-сервера на роутере и не понятна тем, кто далек от компьютеров.
Для одного домашнего сервера самый простой вариант без DNS-сервера — Multicast DNS, сокращённо mDNS, и домены в зоне .local. Это способ разрешения имён внутри локального сегмента сети при отсутствии обычного DNS-сервера. Устройства самостоятельно транслируют в локальную сеть свои имена.
Почему не получится публиковать много имен через конфигурацию Avahi
В Linux mDNS обычно обеспечивает Avahi. У Avahi есть конфигурационный файл /etc/avahi/hosts. Это простой текстовый файл, где на каждой строке задаётся соответствие IP-адреса и имени хоста, которое Avahi должен опубликовать через mDNS.
Таким способом можно присваивать доменные имена устройствам, у которых нет возможности самостоятельно транслировать свое локальное имя в сеть. Однако, когда пытаются опубликовать несколько имён для одного IP-адреса через этот механизм, Avahi часто отвечает ошибкой:
Static host name example.local: avahi_server_add_address failure: Local name collision
Это происходит, потому что один IPv4-адрес обычно должен иметь одну основную обратную запись.
Обычная запись отвечает на вопрос: какой IP-адрес у имени example.local. Это A-запись.
Обратная запись отвечает на вопрос: какое имя у IP-адреса 192.168.1.50. В классическом DNS это PTR-запись. Обратные записи используются в диагностике, логах и в ситуациях, когда по IP-адресу нужно получить человекочитаемое имя.
Если попытаться закрепить несколько разных имён за одним адресом через /etc/avahi/hosts, Avahi старается публиковать и обратную часть, а она становится неоднозначной. В результате Avahi фиксирует коллизию и отказывается добавлять адрес.
Практическое решение — публиковать дополнительные имена как A-записи без обратной публикации.
Публикация дополнительных имён через avahi-publish и ключ -R
Для публикации отдельных A-записей подходит утилита avahi-publish из пакета avahi-utils. Она регистрирует имя в mDNS через работающий avahi-daemon.
Базовая команда:
avahi-publish -a -R example.local 192.168.1.50
Пояснения по ключам:
-aпубликует A-запись, то есть соответствие имени и IPv4-адреса-Rсоответствует--no-reverse, то есть запрещает публикацию обратной PTR-части и тем самым избегает конфликтов при нескольких именах на одном IP
Так можно объявить несколько имён, которые будут указывать на один и тот же сервер.
Установка Avahi и управление набором имён через systemd
На Raspberry Pi OS 13 Avahi работает из коробки. Если нет — устанавливается и включается следующим образом:
sudo apt update
sudo apt install -y avahi-daemon avahi-utils
sudo systemctl enable avahi-daemon
sudo systemctl start avahi-daemon
Публикация имен avahi-publish работает как отдельный процесс. Удобно оформить каждое имя как systemd-сервис и поднимать весь набор одним target-юнитом.
В примерах ниже используется IP 192.168.1.50. Замените на IP адрес вашего сервера.
Шаблон systemd-юнита
Создайте файл /etc/systemd/system/avahi-publish@.service:
[Unit]
Description=Publish mDNS A record %I for 192.168.1.50 via avahi-publish
After=network-online.target avahi-daemon.service dbus.service
Wants=network-online.target
Requires=avahi-daemon.service
[Service]
Type=simple
# -a публикует A-запись
# -R отключает обратную запись
ExecStart=/usr/bin/avahi-publish -a -R %I 192.168.1.50
Restart=always
RestartSec=2
StartLimitIntervalSec=0
[Install]
WantedBy=multi-user.target
%I — имя экземпляра шаблона. Если запустить avahi-publish@example.local.service, то %I будет example.local.
Target-юнит для запуска всех имён
Создайте файл /etc/systemd/system/avahi-publish.target:
[Unit]
Description=Publish all mDNS A records via avahi-publish@.service
# Записи для сайта на Битрикс (bitrix.local), Home Assistant (homeassistant.local), ownCloud (owncloud.local) и Plex (plex.loca)
Wants=avahi-publish@bitrix.local.service
Wants=avahi-publish@homeassistant.local.service
Wants=avahi-publish@owncloud.local.service
Wants=avahi-publish@plex.local.service
After=avahi-daemon.service dbus.service network-online.target
Requires=avahi-daemon.service
[Install]
WantedBy=multi-user.target
Wants= перечисляет экземпляры шаблона, которые должны стартовать вместе с target-юнитом.
Включение и запуск
Примените новые unit-файлы:
sudo systemctl daemon-reload
Включите автозапуск набора имён и запустите его:
sudo systemctl enable avahi-publish.target
sudo systemctl start avahi-publish.target
Проверка разрешения имён:
getent hosts homeassistant.local
avahi-resolve -n owncloud.local
Один nginx как точка входа для всех сервисов
mDNS решает только задачу разрешения имён в .local в IP-адрес сервера. Чтобы разные имена открывали разные сервисы, нужен веб-сервер на 80 порту, который маршрутизирует запросы по заголовку Host. Для этого подходит nginx.
Установка Nginx на Raspberry Pi OS 13
sudo apt update
sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx
Один конфигурационный файл
Используем один файл /etc/nginx/conf.d/server.conf.
После изменений проверяйте конфигурацию и перечитывайте её:
sudo nginx -t
sudo systemctl reload nginx
Пример конфигурации Nginx
Файл /etc/nginx/conf.d/server.conf.
Общие настройки для прокси и WebSocket
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
Прямой доступ к сайту на 80 порту
server {
listen 80 default_server;
server_name server.local;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Проксирование обычного веб-сервиса
nginx принимает запрос на 80 порту и проксирует его на порт, который опубликован локально. Пример для тестовой Docker-среды для Bitrix.
server {
listen 80;
server_name bitrix.local;
location / {
proxy_pass http://127.0.0.1:8588;
proxy_http_version 1.1;
}
}
Home Assistant
Home Assistant использует WebSocket в интерфейсе, поэтому нужны заголовки Upgrade и Connection. Также полезно увеличить таймауты для длительных подключений.
server {
listen 80;
server_name homeassistant.local;
location / {
proxy_pass http://127.0.0.1:8123;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
Если Home Assistant стоит за обратным прокси, в configuration.yaml нужно включить use_x_forwarded_for и указать trusted_proxies, иначе запросы от прокси будут блокироваться.
http:
use_x_forwarded_for: true
trusted_proxies:
- 127.0.0.1
ownCloud
Для ownCloud часто требуется увеличить допустимый размер тела запроса, иначе крупные загрузки будут ограничены на уровне nginx. Также полезно увеличить таймауты чтения.
server {
listen 80;
server_name owncloud.local;
client_max_body_size 2G;
location / {
proxy_pass http://127.0.0.1:8880;
proxy_http_version 1.1;
proxy_read_timeout 3600s;
}
}
Plex
При доступе к Plex по доменному имени, сервис обычно требует авторизацию, даже если в локальной сети вы настроили доступ без входа. На практике это означает, что сценарий гостевого входа, который работает по IP-адресу, при входе по доменному имени перестаёт быть прозрачным. В этой схеме используется редирект.
Поэтому остаётся простой и предсказуемый вариант: редирект на IP-адрес и порт Plex Web.
server {
listen 80;
server_name plex.local;
return 301 http://192.168.1.50:32400/web/;
}
Что получится в итоге
После настройки пользователи в домашней сети смогут открывать сервисы по понятным адресам без запоминания портов:
server.localоткрывает сайт на 80 портуbitrix.localоткрывает тестовую среду через проксиhomeassistant.localоткрывает Home Assistant с поддержкой WebSocketowncloud.localоткрывает ownCloud с корректными лимитами загрузкиplex.localперенаправляет в Plex Web по IP-адресу и порту, чтобы не упираться в требования авторизации при доступе по доменному имени