Как обойти блокировку Роскомнадзора: история mkdev

Illustration of a rider on a horse near a "Wanted" sign, with horse tracks in the snow leading up to them, and a bag of money by the sign. Illustration of a rider on a horse near a "Wanted" sign, with horse tracks in the snow leading up to them, and a bag of money by the sign.

Как и многие другие сервисы, mkdev пострадал от недавних блокировок Роскомнадзора. В результате мы потеряли солидную долю трафика и, как следствие, потенциальных клиентов. Сначала mkdev перестал открываться у пользователей нескольких мобильных операторов, а затем блок дошёл и до крупных интернет-провайдеров. Первые два дня мы искренне надеялись, что слабоумие и отвага сменятся на здравый смысл. Этого не произошло, ситуация спустя несколько дней стала только хуже, и нам пришлось выкручиваться своими руками. О том, как мы боролись и победили блокировку нашего бизнеса на очень важном для нас рынке, сейчас и расскажем.

Официальный способ разблокировки без применения технических навыков

Попасть в список заблокированных ресурсов легко, а вот выйти из него официальными методами оказалось не так просто.

Вопросов вроде «что делать?» и «кому писать?» задавать не пришлось. На второй день войны РКН против Телеграма в интернете образовалось множество инструкций от правозащитных организаций разной степени полезности.

В первую очередь мы стали писать жалобу в сам РКН. У них предусмотрена специальная процедура обжалования. Сделать этого, правда, не удалось, так как их сайт и официальная форма подачи жалобы не то были под DDoS атакой, не то они сами себя заблокировали. Форма отправки жалобы всё так же сбоит на момент написания статьи.

Примерно тогда же появилось их официальное заявление о том, что сообщения, будто под блокировку попали добросовестные сайты, являются выдумкой. А следом - предложение писать о подобных фактах на горячую линию для последующей проверки.

Мы написали на эту горячую линию, приложив скриншоты с недоступным сайтом от клиентов и скриншот с официальной страницы РКН, подтверждающий блокировку нашего IP. Ответом нам была ошибка 554 (почтовый домен находится в стоп-листе за спам). С такой же проблемой столкнулись другие предприниматели. Видимо, в РКН предусмотрительно занесли все почтовые сервисы в стоп-лист.

Спустя несколько дней они опомнились и завели ящик горячей линии на Яндексе. Мы продублировали письмо туда, но на сегодняшней день ответа всё ещё не последовало. Также никакого ответа не последовало ни от РОЦИТ, ни от РАЭК, хотя на своих официальных сайтах они рапортуют об успехах в переговорах с РКН о снятии блокировок с пострадавших сайтов.

Похожая ситуация наблюдалась и в общении с провайдерами. Особенно с крупными, диалог с которыми выглядит примерно так:

— Почему нет доступа к сайту?
— Мы тут не при чём. Обновите браузер, обратитесь к хостеру. — Ну, из под VPN ведь открывается. Значит с хостером и браузером всё ок? — Нам больше нечего посоветовать. — А у вас у самих сайт mkdev.me открывается? — Нет. — Почему? — Всего хорошего.

Некоторые, конечно, признают, что недоступность сайта связана с блокировкой Телеграма. Но объяснить, на основании какого решения суда они ограничивают доступ к нашему сервису, они не могут.

Складывается впечатление, что провайдеры то ли покрывают РКН, то ли настолько же некомпетентны (или боятся исков?). Нормальный диалог получался только с мелкими региональными провайдерами.

Спустя две недели после блокировки, мы так и не получили ни одного официального разъяснения, на каком основании доступ к нашему сервису заблокирован на территории России. И хотя мы уверены, что получим ответ на этот вопрос в арбитражном суде, случится это ещё очень не скоро. А трафик из России на наш сайт тем временем упал больше чем на 60%, а убытки (как финансовые, так и репутационные) только множатся.

В итоге мы поняли, что надежды на быструю помощь в восстановлении справедливости можно не ждать. Пришлось думать, как решать вопрос техническими средствами.

Пара слов об инфраструктуре mkdev

На mkdev мы не просто используем 1-2 сервиса AWS. Вся инфраструктура проекта расположена на облаке Амазона. Среди прочего, mkdev жить не может без EC2, RDS, S3, CloudWatch, CloudFrount, SES и SNS. Так как юридически mkdev остаётся немецким бизнесом, в качестве дата-центра мы используем франкфуртский регион AWS (eu-central-1). По юридическим же причинам мы не можем просто взять и перенести все данные и сервера в другую страну.

Переносить инфраструктуру в другую страну или даже просто к другому провайдеру облачной инфраструктуры не имеет смысла и по другой причине: блокировка от РКН настолько прямолинейна, что по-настоящему от неё спастись нельзя. Это просто блок IP-адресов целыми подсетями. И список этих адресов, как мы все убедились недавно, может вырасти в любой момент. Нет никаких гарантий, что после переноса инфраструктуры в другой дата-центр РКН не заблокирует все публичные IP-адреса этого дата-центра. Поэтому вкладывать время и деньги в миграцию, только чтобы снова оказаться заблокированными, смысла не было.

Несмотря на то, что по-настоящему спастись от блокировки не получится, есть вариант, как её можно удачно избегать. Но сначала поговорим про IPv6.

Почему IPv6 не спасает от блокировки РКН

РКН блокирует только IPv4 адреса. IPv6 продолжает работать, поэтому теоретически можно просто перейти наконец на IPv6 и использовать его. Но чтобы IPv6 сработал, адрес должен быть не только у сервера приложения, но и у конечного пользователя. Как выяснилось, в России у IPv6 один из самых низких уровней использования. Поэтому простым переходом на IPv6 не обойтись - пришлось бы думать о том, что делать клиентам, интернет-провайдер которых не обрадовал совместимостью с новыми адресами.

Мы, конечно, всё равно завели себе IPv6 адрес, от которого прямо сейчас нет толку. Но это другая история, давайте вернёмся к финальному решению.

У нас есть более подробная статья о том, как работают сети, что такое IP адрес, DNS и вот это всё Читать

Почему обход блокировки всё таки возможен

Говорят, в какой-то момент РКН заблокировал 1% всех IP-адресов. Может показаться, что это ужасно много. И так на самом деле и есть. Но не будем забывать, что 99% адресов по-прежнему остаются доступными, в том числе миллионы адресов, принадлежащие AWS.

Если мы можем обзавестись публичным адресом, не заблокированным в России и серверов, который не ограничен блокировками РКН (например, любой сервер за пределами России), то мы можем просто провести весь наш трафик через этот промежуточный сервер. И именно так мы обошли блокировку РКН.

Шаг 1. Ищем адреса, не заблокированные Роскомнадзором

В первую очередь, нам нужен этот самый не заблокированный адрес. Проверить, заблокирован ли адрес, можно в специальном сервисе от РКН. Немножко погуглив, можно также найти списки подсетей, попавших под блокировку.

На нашу удачу, 28 апреля РКН разблокировал две крупные подсети, принадлежащих AWS. К несчастью, эти подсети не пересекались с немецким регионом AWS. Амазон публикует все адреса, которыми владеет. Воспользовавшись их списком, мы нашли те регионы AWS, в которых находятся желанные IP-адреса. И снова, к несчастью, большинство из доступных подсетей находились либо в Японии, либо в США. Но и этого достаточно, чтобы начать действовать.

Мы выбрали японский регион AWS и начали играть в "выбей себе нужный адрес". Нам нужен был Elastic IP, который всегда будет доступен именно нам. При запросе AWS, он выдаёт случайный EIP, поэтому получение нужного адреса - это вопрос удачи. Либо навыков программирования.

Так как у AWS есть API вообще для всего, мы написали небольшой скрипт, который бесконечно долго запрашивает адреса, проверяет их вхождение в нужную подсеть и освобождает их, если они в нужную подсеть не входят. Сам скрипт настолько простой, что даже стыдно его показывать. Но мы покажем:

require 'aws-sdk-ec2'

ec2 = Aws::EC2::Client.new

while true
  sleep 2 # Это чтобы не упереться в лимит запросов к API
  resp = ec2.allocate_address({
    domain: "vpc",
  })

  ip = resp.public_ip
  alloc = resp.allocation_id

  puts ip

  # Так начинается одна из не заблокированных в России подсетей.
  if ip.start_with?("54.170")
    puts "Win!"
    break
  else
    ec2.release_address({
      allocation_id: alloc,
    })
  end
end

Покрутив скрипт несколько минут, мы в итоге получили нужный нам адрес, не попавший под блокировку. Конечно, получение адреса таким способом это исключительно вопрос везения - вполне может быть, что все заблокированные адреса в одном из регионов уже разобраны другими клиентами AWS. Нам, безусловно, повезло.

Небольшое отступление: я тут рассказываю про AWS и поиски адреса в дата-центрах AWS. Но обход блокировки никак не завязан на Амазоне. Вам просто нужен сервер с публичным не заблокированным адресом - если вы его найдёте на Digital Ocean, Google Cloud, Azure или где-нибудь ещё, то это здорово! Нам удобнее держать оплату инфраструктуры, как и саму инфраструктуру, в одном месте, но если вдруг вообще весь AWS попадёт под блок, мы просто перенесём наш туннель в другое место.

Шаг 2. Настраиваем сервер-туннель

После того, как мы запустим сервер и назначим ему IP адрес, нам нужно его настроить так, чтобы он просто перенаправлял весь трафик на основной сервер mkdev. Есть несколько способов это сделать - возможно, несколько десятков. Я расскажу про два способа - бесконечно простой и чуть более сложный.

Способ 1: port forwarding на третьем уровне OSI

Самое просто это просто перенаправлять трафик на третьем уровне сети. На современных дистрибутивах Linux это достигается несколькими командами:

echo "net.ipv4.conf.all.forwarding = 1" >> /etc/sysctl.conf
sysctl -p
firewall-cmd --permanent --add-masquerade
firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=80:toaddr=TARGET_IP
firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=443:toaddr=TARGET_IP
firewall-cmd --reload

Этого достаточно, чтобы весь трафик, направленный в прокси-сервер, пересылался на настоящий сервер с приложением. Но есть одна проблема: отслеживание оригинальных IP-адресов клиентов. Обычно оригинальный адрес хранится в HTTP-заголовке типа X-Forwarded-For или X-Real-IP. Так как выше мы перенаправляем трафик на уровне, где HTTP-заголовков нет, то сообщить конечному серверу о клиентском IP мы не можем.

Результат? Наше приложением будет думать, что весь трафик идёт с одного IP-адреса - адреса нашего прокси. А это может быть нежелательно.

Конечно, мы можем настроить прокси немного иначе - вырубить masquerading и проводить вообще весь трафик между клиентами и приложением через прокси, настроив роутинг на сервере приложения так, чтобы пакеты по умолчанию шли через прокси. Но мы не хотим проводить весь трафик через прокси. Прокси у нас только для того трафика, что приходит из России. Поэтому обращаемся к другому способу - полноценному прокси с nginx в главной роли.

Способ 2: прокси на nginx

В этом случае нам нужно настроить на прокси-сервере nginx и так же сказать ему перенаправлять весь трафик в сервер с приложением. Дополнительно нужно сообщить об этом серверу с приложением и подсказать ему, откуда брать настоящий IP клиента.

Конфиг для прокси может в таком случае выглядеть вот так:

stream {
    server {
        listen 443;
        proxy_pass TARGET_IP:8443;
        proxy_protocol on;
    }
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;

        location / {
          proxy_pass  http://TARGET_IP;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       }
    }
}

И на сервере с приложением, где у нас тоже nginx, нужно поправить конфиг вот так:

server {
  listen 443 ssl;
  listen 8443 ssl proxy_protocol;
  # ....
  add_header Cache-Control public;

  set_real_ip_from PROXY_IP;
  real_ip_header proxy_protocol;
  # ...
}

Сразу замечу, что это не идеальный конфиг, а самая топорная и быстрая реализация. Её можно использовать как ориентир для своей реализации.

С таким конфигом nginx на прокси-сервере будет пересылать весь трафик и конечный сервер будет брать настоящий клиентский IP из proxy_protocol. В принципе, этого достаточно. Остаётся ещё один шаг: DNS

Шаг 3. Настраиваем DNS.

Мы хотим, чтобы все клиенты, кроме клиентов из России, шли напрямую к серверам mkdev. А вот клиентам из России при запросе mkdev.me нужно отдавать IP адрес нашего прокси. С Route53 это делается очень легко при помощи geolocation routing policy. Мы просто указываем, какой IP адрес отдавать клиентам из России и какой - всем остальным. В итоге россияне идут на прокси, весь мир идёт напрямую к mkdev.

И это всё?

Ну, вообщем-то, да. Мы проделали эти шаги, настроили самый простой, топорный прокси на nginx, и mkdev снова заработал в России. Если вдруг IP-адрес нашего прокси заблокируют, мы всегда сможем найти другой доступный адрес и мгновенно настроить прокси на нём.

Важно, чтобы прокси не был слишком удалён от основных серверов. Изначально мы настроили прокси в Токио, в качестве эксперимента. Это сильно ударило по отзывчивости сайта, и после быстрого proof of concept мы перенесли прокси в Париж.

Если ваш сервис заблокировал Роскомнадзор - не бойтесь. Блокировку обойти вполне реально. Конечно, вам стоит запустить официальный процесс разблокировки сервиса. Но ждать можно неделями, и во время ожидания желательно, чтобы сервис был доступен.

Выводы из блокировок Роскомнадзора

Мы сделали неутешительный вывод: фокусироваться и дальше на российском рынке для нас не имеет смысла. В любой момент пачка слабо отдающих отчёт своим действиям людей может буквально убить наш бизнес или, как минимум, нанести серьёзные потери. Работать в таких условиях мы не хотим. mkdev всегда будет предоставлять услуги для российских клиентов, но после недавних событий мы решили отдавать приоритет другим рынкам.