Все настройки выполнены в VPS от hostsailor.com. У других хостеров наверняка также, но могут быть нюансы.
Всё, что написано ниже, написано только для маленьких хоббитов волею случая проживающих в Мордоре и находящихся под надзором злобного Саурона. Это просто сказка, любые совпадения с реальностью случайны.
Представим себе совершенно гипотетическую ситуацию. Какому-то хоббиту не повезло оказаться на ПМЖ в Мордоре — стране, где каждый его шаг в Интернете хочет видеть и контролировать злодей Саурон. В нашей-то стране такого конечно нет. Только в волшебном Мордоре. Хоббит в целом, наверное, не дурак и давно уже сделал собственный VPN-сервер, как описано в этих статьях. Ну или хоббит уже преисполнился, и сделал, как написано здесь или здесь. Однако не всегда есть возможность/желание установить VPN-клиент. Например хоббит за рабочим компьютером или это компьютер бабушки хоббита, которая не умеет запускать VPN-клиенты. И до сих пор хоббита выручало то, что все сайты уже давно используют защищённый протокол HTTPS. Да вот беда: Саурон узнал про существование DNS. Это такая служба Domain Name System, которая позволяет хоббитопонятный интернет-адрес превратить в IP-адрес, понятный для интернет-браузеров. Без этой службы интернет-браузеры не работают. А к серверам службы DNS большинство компьютеров обычно ходят по не шифрованному DNS протоколу.
Все картинки в статье кликабельны.
Саурон приказал своему орккомнадзору фильтровать эти запросы, записывать их и, в некоторых случаях, подменять. То есть Саурон не видит, что хоббит делал на сайте, ведь там протокол HTTPS, но вот какие сайты хоббит запрашивал — он видит. А если хоббит захотел открыть эльфийский сайт, то можно в DNS запросе подменить ответ и хоббит вместо эльфийского сайта увидит злобную картинку от орккомнадзора. Или просто обвинить хоббита в сочувствии и поддержке эльфов, признать его эльфоагентом. Тогда мудрые эльфы придумали протокол DNS-over-HTTPS (сокращенно DOH). Это когда DNS-сервер прикидывается обычным веб-сервером, работающим по протоколу HTTPS, и интернет-браузер хоббита запрашивает у этого сервера IP-адреса сайтов по зашифрованному протоколу.
Саурон сначала приуныл, но потом до него дошло, что DNS сервера эльфов, поддерживающие протокол DOH, это те же сервера, что и работающие по обычному DNS протоколу. Да и серверов таких совсем не много. Тогда Саурон приказал своим оркам блокировать любые запросы хоббитов к известным серверам, поддерживающим DOH. Это заставит хоббита пользоваться мордорскими DNS серверами и можно и дальше фильтровать/записывать/подменять его запросы. Что ж делать хоббиту? Ну, например, использовать личный VPN, как написано в начале статьи. Но у хоббита есть потребность обойтись без VPN. Хоббит хитрый и он подумал: обращения к серверу DOH всё равно выглядят как обычный HTTPS, выдаёт их в основном только то, что они идут к известным Саурону DNS-серверам. Что если сделать свой web-сервер, такой же, как тысячи других, работающий по HTTPS, но при этом способный выступать посредником между хоббитом и публичным DNS-сервером. Т.е. сервер хоббита будет принимать зашифрованные DNS запросы, пересылать их публичному эльфийскому DNS-серверу, принимать ответы, зашифровывать и отправлять обратно хоббиту. Получится реверс-прокси сервер для DOH. Расположить его конечно нужно там, куда не дотянуться беспредельничающие орки.
Для Саурона это будет выглядеть так, как будто хоббит ходит на очередной web-сайт. Конечно, если он начнёт вглядываться очень пристально в конкретного хоббита, то через некоторое время поймет что к чему. Но хобиттов в Мордоре миллионы и Саурон предпочитает бить по площадям. Кроме того DOH реверс-прокси лишит Саурона списка эльфийских сайтов, которые запрашивал хоббит. А это может помочь хоббиту в его не простой жизни.
Всё, что описано ниже, выглядит сложным. Но это не сложно. С этим справится любой хоббит, даже если у него лапки. Нужно просто верить в себя и следовать плану.
Для начала хоббиту нужно заблаговременно озаботится арендой доменного имени. Как это сделать примерно описано в начале этой статьи. Предположим хоббит арендовал доменное имя theshire.ru. В принципе он мог его и использовать для реверс-прокси. Но можно добавить имя третьего уровня. Тогда сам домен можно будет потом использовать для чего-то ещё. Так больше гибкости. Хоббит решил сделать имя третьего уровня ns1.theshire.ru. У него получились такие записи домена:
В этих записях вписан IP арендованного хоббитом VPS. Думаю не нужно напоминать, что виртуальный сервер должен находится за пределами Мордора. Хоббит, используя эту статью, арендовал предельно дешёвую виртуалку с такими параметрами:
Как видно, на сервере установлена операционная система CentOS 7. Далее нужно настроить защищённый вход на сервер, как описано здесь, и файрволл сервера, как описано здесь. Только при настройке файрволла нужно в ipt-set записать другое содержимое:
#!/bin/sh IF_EXT="venet0" IPT="/sbin/iptables" IPT6="/sbin/ip6tables" # flush $IPT --flush $IPT -t nat --flush $IPT -t mangle --flush $IPT -X $IPT6 --flush # loopback $IPT -A INPUT -i lo -j ACCEPT $IPT -A OUTPUT -o lo -j ACCEPT # default $IPT -P INPUT DROP $IPT -P OUTPUT DROP $IPT -P FORWARD DROP $IPT6 -P INPUT DROP $IPT6 -P OUTPUT DROP $IPT6 -P FORWARD DROP # allow forwarding echo 1 > /proc/sys/net/ipv4/ip_forward # INPUT chain # ######################################### $IPT -A INPUT -p tcp ! --syn -m state --state NEW -j DROP $IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # ssh $IPT -A INPUT -i $IF_EXT -p tcp --dport 22 -j ACCEPT # nginx $IPT -A INPUT -i $IF_EXT -p udp --dport 53 -j ACCEPT $IPT -A INPUT -i $IF_EXT -p tcp --dport 80 -j ACCEPT $IPT -A INPUT -i $IF_EXT -p tcp --dport 443 -j ACCEPT $IPT -A INPUT -i $IF_EXT -p tcp --dport 853 -j ACCEPT # OUTPUT chain # ######################################### $IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
Не забудьте про правильное имя внешнего интерфейса в переменной IF_EXT (вторая строчка), как описано в этой статье.
Обновим сервер и установим необходимые утилиты:
yum -y update yum -y install net-tools wget
Проверим, не сидит ли какая-то дефолтная http служба на нужном нам 80-ом порту:
netstat -tulnp | grep 80
Сидит, собака
Убиваем её
systemctl stop httpd systemctl disable httpd yum -y remove httpd
Теперь сервер готов. Реверс-прокси сделаем конечно же на nginx. Ранее уже была статья про использование его в такой роли. Ретранслировать DOH запросы не на столько простая задача, как кажется. Дабы не изобретать велосипед, используем уже готовый проект NGINX-DNS. Благодаря скриптам этого проекта мы не только сделает DOH между хоббитом и его реверс прокси, но и обмен по протоколу DOT между реверс-прокси и публичным DNS. Т.е даже хостинг VPS не сможет заглянуть в трафик хоббита! Кстати, для этого проекта подойдёт не каждый nginx. Тот, который в epel-release, НЕ подойдёт. Поэтому epel-release ни в коем случае не устанавливаем, он всё поломает. Накатим репозиторий с правильным nginx:
cd /tmp wget http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm rpm -ivh nginx-release-centos-7-0.el7.ngx.noarch.rpm
Проверим, что операционная система теперь знает, где брать nginx и модули к нему:
yum list | grep nginx
Отлично. Устанавливаем nginx и нужный модуль:
yum -y install nginx.x86_64 nginx-module-njs.x86_64
Еще раз проверьте, что файрволл настроен и открытые порты выглядят так:
iptables -L -n
Теперь любым удобным способом откроем для редактирования файл /etc/nginx/conf.d/default.conf (хоббитам с лапаками рекомендую использовать WinSCP и Notepad++). В этом файле сразу после строчки
server {
нужно найти строчку
server_name localhost;
и вместо localhost вписать своё доменное имя. У хоббита это так (не удалите случайно точку с запятой!):
server_name ns1.theshire.ru;
Файл можно сохранить и закрыть. Запускаем nginx и смотрим, что всё в порядке:
systemctl start nginx systemctl status nginx
Дальше в браузере на компьютере переходим по доменному адресу сервера. У хоббита это http://ns1.theshire.ru
Оно живое! Но только по протоколу HTTP, а нам надо по HTTPS. Для этого нужно сделать SSL сертификаты от letsencryp. Сертификаты весь прогрессивный эльфийский мир делает с помощью Certbot. Поскольку epel-release мы не используем, то ставить certbot хоббиту придётся через жопу Pip.
Накатим питона с либами:
yum -y install python3 augeas-libs
и подготовим виртуальную среду:
python3 -m venv /opt/certbot/ /opt/certbot/bin/pip install --upgrade pip
Отлично. Можно и накатить сам certbot:
/opt/certbot/bin/pip install certbot certbot-nginx ln -s /opt/certbot/bin/certbot /usr/bin/certbot
Теперь сделаем сертификаты:
certbot --nginx
Соглашаемся с условиями использования, указываем почту (желательно настоящую, туда, если что, будут спамить о проблемах с сертификатами) и отказываемся от спама. На запрос доменного имени нужно выбрать своё. У хоббита получилось так:
Если на этом этапе не удаётся создать сертификаты, появляются ошибки, то:
- ещё раз проверить настройки файрволла и доступность страницы приветствия по (у хоббита это http://ns1.theshire.ru);
- возможно домен арендован и/или его записи внесены менее 24 часов назад и не все DNS серверы успели их синхронизировать. Тогда придётся подождать.
Современный certbot настолько преисполненный, что он сам вписал настройки HTTPS в nginx и сам применил их. Нам остаётся только открыть свой доменный адрес по HTTPS:
SSL сертификаты выдаются всего на три месяца. Дабы они не прокисли, добавляем в планировщик задачу по обновлению:
echo "0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q" | tee -a /var/spool/cron/root > /dev/null
и проверяем результат:
crontab -l
Теперь превратим наш безобидный nginx в боевой DOH сервер. Для начала остановим его:
systemctl stop nginx
Теперь из проекта NGINX-DNS с гитхаба скопируем нужные нам файлы и засунем в папку nginx. При этом старые конфиги nginx удалять не будем, а просто добавим к имени приставку .old:
cd /tmp wget https://github.com/TuxInvader/nginx-dns/archive/refs/heads/master.zip unzip master.zip cp -r nginx-dns-master/njs.d /etc/nginx/ cd /etc/nginx/ mv nginx.conf nginx.conf.old mv ./conf.d/default.conf default.conf.old
В папке /etc/nginx/ создадим файл nginx.conf с вот таким содержимым:
user nginx; worker_processes auto; load_module modules/ngx_stream_js_module.so; error_log /var/log/nginx/error.log error; #error_log off; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; # logging directives log_format doh '$remote_addr - $remote_user [$time_local] "$request" ' '[ $msec, $request_time, $upstream_response_time $pipe ] ' '$status $body_bytes_sent "$http_x_forwarded_for" ' '$upstream_http_x_dns_question $upstream_http_x_dns_type ' '$upstream_http_x_dns_result ' '$upstream_http_x_dns_ttl $upstream_http_x_dns_answers ' '$upstream_cache_status'; access_log /var/log/nginx/doh-access.log doh; #access_log off; resolver 1.1.1.1 valid=10s; # This upstream connects to a local Stream service which converts HTTP -> DNS upstream dohloop { zone dohloop 64k; server 127.0.0.1:8053; keepalive_timeout 60s; keepalive_requests 100; keepalive 10; } # Proxy Cache storage - so we can cache the DoH response from the upstream proxy_cache_path /var/cache/nginx/doh_cache levels=1:2 keys_zone=doh_cache:10m; # The DoH server block server { server_name ns1.theshire.ru; root /usr/share/nginx/html; # Listen on standard HTTPS port, and accept HTTP2, with SSL termination listen 443 ssl http2 default_server; ssl_certificate /etc/letsencrypt/live/ns1.theshire.ru/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/ns1.theshire.ru/privkey.pem; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot ssl_session_cache shared:ssl_cache:10m; ssl_session_timeout 10m; # DoH may use GET or POST requests, Cache both proxy_cache_methods GET POST; # Return 404 to all responses, except for those using our published DoH URI location / { return 404 "404 Not Found\n"; } # This is our published DoH URI location /dns-query { # Proxy HTTP/1.1, clear the connection header to enable Keep-Alive proxy_http_version 1.1; proxy_set_header Connection ""; # Enable Cache, and set the cache_key to include the request_body proxy_cache doh_cache; proxy_cache_key $scheme$proxy_host$uri$is_args$args$request_body; # proxy pass to the dohloop upstream proxy_pass http://dohloop; } } server { if ($host = ns1.theshire.ru) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name ns1.theshire.ru; return 404; # managed by Certbot } } # DNS Stream Services stream { # DNS logging log_format dns '$remote_addr [$time_local] $protocol "$dns_qname"'; access_log /var/log/nginx/dns-access.log dns; #access_log off; # Include the NJS module js_include /etc/nginx/njs.d/nginx_stream.js; # The $dns_qname variable can be populated by preread calls, and can be used for DNS routing js_set $dns_qname dns_get_qname; #DNS upstream pool. upstream dns { zone dns 64k; server 1.1.1.1:53; } # DNS over TLS upstream pool upstream dot { zone dot 64k; server 1.1.1.1:853; } # DNS(TCP) and DNS over TLS (DoT) Server # Upstream can be either DNS(TCP) or DoT. If upstream is DNS, proxy_ssl should be off. server { # DNS TCP listen 53; # DNS DoT listen 853 ssl; ssl_certificate /etc/letsencrypt/live/ns1.theshire.ru/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/ns1.theshire.ru/privkey.pem; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot # This is used to pull out question for logging js_preread dns_preread_dns_request; # Enable SSL re-encryption for DoT connection upstream proxy_ssl on; proxy_pass dot; } # DNS over HTTPS (gateway) Service # Upstream can be either DNS(TCP) or DoT. If upstream is DNS, proxy_ssl should be off. server { listen 127.0.0.1:8053; js_filter dns_filter_doh_request; proxy_ssl on; proxy_pass dot; } # DNS(UDP) Server # DNS UDP proxy onto DNS UDP server { listen 53 udp; proxy_responses 1; js_preread dns_preread_dns_request; proxy_pass dns; } }
Указанный выше конфиг сделан для нашего хоббита и его доменного имени ns1.theshire.ru. Чтобы переделать файл под другого хоббита и другое доменное имя:
- Найти строчки, начинающиеся на «server_name», и заменить в них доменное имя ns1.theshire.ru на своё.
- Найти строчки, начинающиеся на «ssl_certificate», и заменить в них путь на сертификат своим. Свой путь можно найти в аналогичных строчках файла /etc/nginx/default.conf.old
Сохраните и закройте файл. Выполните тест корректности конфига командой:
nginx -t
У хоббита хоть и лапки, но прямые. У него получилось с первого раза:
Если есть ошибки, то будут написаны номера строк с ними. Смотрим в эти строки и исправляем. Чаще всего хоббиты нечаяно удаляют «;» в конце строк.
Теперь nginx можно запустить и добавить в автозагрузку.
systemctl start nginx systemctl enable nginx
Собственно всё. Хоббит сделал сервер который:
- Может работать как обычный DNS сервер по порту 53/UDP. Если добавить его IP в настройки DNS, например, сетевой карты компьютера, то всё взлетит. Обратите внимание, что это не шифрованный обмен. Обычный DNS. Если этот функционал не нужен, то просто закомментируйте/удалите строку с портом 53 в файле /root/ipt-set и перезагрузите сервер.
- Принимает запросы по протоколу DOH (по порту 443), расшифровывает их, разбирает, перенаправляет запросы на публичный DNS сервер по зашифрованному протоколу DOT, полученные ответы зашифровывает и отправляет хоббиту.
- Принимает запросы по протоколу DOТ, расшифровывает их, разбирает, перенаправляет запросы на публичный DNS сервер по, опять же, протоколу DOT, полученные ответы зашифровывает и отправляет хоббиту. Протокол DOT на сегодня не особо распространён в браузерах. Если этот функционал не нужен, то просто закомментируйте/удалите строку с портом 853 в файле /root/ipt-set и перезагрузите сервер.
Хоббиту осталось настроить браузер.
В Mozilla Firefox нужно открыть Настройки -> Параметры сети -> Настроить, в самом низу поставить галочку «Включить DNS через HTTPS» и вписать свой DNS адрес. У нашего хоббита он такой:
https://ns1.theshire.ru/dns-query
Другим хоббитам вместо ns1.theshire.ru нужно вписать свой домен.
В Google Chrome открыть Настройки -> Конфиденциальность и безопасность -> Безопасность -> Использовать безопасный DNS-сервер вписать сервер также, как это указано выше для Firefox. У нашего хоббита это получилось так:
Для других браузеров хоббиту предлагается напрячь лапки и погуглить.
В качестве домашнего задания также предлагается нагуглить, как настроить Windows 10 для использования DOH. Необязательный пункт. Браузеры не зависят от этого и используют настройку, показанную выше.
Дальше хоббит пользуется браузером как обычно. Сайты должны без проблем открываться. Убедится, что сервер работает как надо, можно сходив в файл лога /var/log/nginx/doh-access.log. Там будут логгированы все DNS запросы хоббита по протоколу DOH.
Посмотрев логи умненький хоббит должен подумать, а нужны ли ему эти следы? Если нет, то он в файле /etc/nginx/nginx.conf:
- находит строчку, начинающуюся на «error_log» и ставит в ее начале #. А вот из строчки «#error_log off;» наоборот символ # убирает.
- находит строчки, начинающиеся на «access_log» и ставит в их начале #. Во всех строчках «#access_log off;» символ # убирает.
Дальше нужно сохранить файл. Остановить сервер командой:
systemctl stop nginx
удалить все файлы из папки /var/log/nginx/ и запустить сервер обратно:
systemctl start nginx
Теперь никаких следов.
За сим эта часть саги про хоббита заканчивается. Обсуждение в https://t.me/SecFAll_chat