Кабинет
RU

Все инструкции

Свой сайт на имени .lopux

У вас есть имя в Лопух-Интернете; эта инструкция ставит за ним настоящий сайт, доступный всем, у кого есть приложение. Если имени пока нет — сначала займите его.

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

На скриншотах — английский интерфейс. Кабинет говорит на шести языках: выберите свой кнопкой EN в правом верхнем углу.

1. Что нужно и что не подойдёт

Машина, где TLS на порту 443 в ваших руках. VPS, выделенный сервер, коробка дома с доступным адресом. Это всё требование целиком, и оно настоящее.

Управляемые площадки для этого не годятся, по двум независимым причинам. Vercel, Netlify, Cloudflare Pages, большинство PaaS: вы добавляете свой домен, а сертификат получают и отдают они. Весь смысл здесь в том, что сервер доказывает владение ключом, который опубликовали вы; площадка, отдающая собственный ключ, такого доказательства не даёт, и приложение посетителя откажется открывать сайт — и будет право. Да и само имя они не примут: привязка домена проверяется через обычный DNS, где mysite.lopux не существует и существовать не будет.

CDN впереди тоже не помогает — он терминирует TLS, а это та же самая проблема.

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

2. Почему сертификат самоподписанный

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

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

В одном отношении это строже удостоверяющего центра. С центром сертификат на ваше имя могли бы выпустить сотни организаций, и любой из них поверили бы. Здесь работает только тот ключ, который опубликовали вы.

3. Сделайте сертификат

Десять лет, без пароля, и все имена, которые вы обслуживаете, перечислены в subjectAltName:

openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
  -keyout site.key -out site.crt -days 3650 -nodes \
  -subj "/CN=mysite.lopux" \
  -addext "subjectAltName=DNS:mysite.lopux,DNS:www.mysite.lopux"

Три вещи про эту команду:

4. Что работает рядом с сайтом

Ваш сайт говорит по обычному HTTP и сертификата вообще не видит. Перед ним стоит nginx, который терминирует TLS опубликованным ключом и передаёт запрос внутрь.

Этот фронт нужен потому, что у источника в Лопух-Интернете несколько настроек противоположны тому, что даёт обычный «защищённый» шаблон nginx, и каждая ломает всё так, что в браузере выглядит нормально:

ПравилоЧем оборачивается нарушение
никакого HSTS — и снимать его, если сайт присылает свойзаголовок намертво привязывает браузер к https:// для этого имени, а это ломает режим обычного http://, с которого посетитель начинает до установки чего бы то ни было
никаких переадресаций на https:// — и сказать сайту, что запрос уже пришёл по TLSиначе фреймворк выдаст такую переадресацию сам и сломает тот же режим изнутри
отклонять рукопожатия, где SNI не ваше имясканер, обходящий адреса, соберёт ваш сертификат, а в сертификате написано ваше имя
только 443приложения стучатся в 443 и никуда больше; порт 80 не обслуживает никого, кто пришёл через Лопух-Интернет
сроки на рукопожатие и чтениеодно соединение, которое открылось и молчит, способно занять сервер. Публичный адрес собирает такие в первые же минуты
ключ живёт на фронте, а путь внутрь идёт по обычному HTTPзначит, этот путь не должен покидать машину: не публикуйте наружу порт самого сайта

Вот этот nginx целиком. Замените имя, пути и адрес внутреннего сайта:

map $http_upgrade $connection_upgrade { default upgrade; '' close; }
server_tokens off;

# не ваше имя: закрытая дверь, до отправки сертификата
server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    ssl_reject_handshake on;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name mysite.lopux;

    ssl_certificate     /etc/ssl/site.crt;   # ключ, чей отпечаток вы публикуете
    ssl_certificate_key /etc/ssl/site.key;
    ssl_protocols       TLSv1.2 TLSv1.3;     # самоподписанный: сшивать не с кем

    client_header_timeout 10s;   # ими ограничено рукопожатие — см. ниже
    client_body_timeout   10s;
    send_timeout          10s;
    keepalive_timeout     30s;
    reset_timedout_connection on;

    proxy_hide_header Strict-Transport-Security;

    location / {
        proxy_pass http://127.0.0.1:8080;   # ваш сайт, обычный HTTP, не наружу
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Forwarded-Proto https;   # правило 2: без переадресации
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        $connection_upgrade;
        proxy_connect_timeout 5s;
        proxy_read_timeout    60s;
    }
}

Одна ловушка в этих таймаутах, из-за которой nginx просто не запустится: ssl_handshake_timeout в http-модуле nginx не существует — он относится к stream. В http рукопожатие ограничено значением client_header_timeout, и именно оно здесь выполняет эту работу.

Про запрет по SNI стоит сказать отдельно, потому что он делает кое-что менее очевидное, чем укрытие от сканеров. Без него сервер отдаёт один и тот же сертификат — и, значит, одно и то же предупреждение браузера — двум посетителям в противоположных положениях: тому, чьё приложение сверило ваш ключ с записью до того, как сдвинулся первый байт страницы, и тому, кто набрал ваш IP-адрес, где не сверялось вообще ничего. Запрет убирает второго. Он не превращает предупреждение в проверку: кто знает ваше имя, впишет его себе в hosts и придёт непроверенным ровно как раньше.

Одно правило про сами страницы, и его легко упустить: ставьте относительные ссылки. /about, а не https://mysite.lopux/about. Посетитель в режиме обычного http:// не сможет перейти по абсолютной https://-ссылке на ваш же сайт, а Лопух-Интернет намеренно не переписывает ваши страницы. Ссылки на другие сайты — ваше дело, их это не касается.

5. Опубликуйте отпечаток ключа

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

Раздел «Сертификаты», пока ничего не опубликовано

Загрузите site.crt кнопкой Выбрать файл сертификата… или вставьте его текстом. Только сертификат — файл, который начинается с -----BEGIN PRIVATE KEY-----, остаётся на вашем сервере, и кабинет откажется его принять, а не сохранит куда-нибудь.

Сертификат вставлен в поле, под ним кнопка публикации

Нажмите Опубликовать отпечаток ключа. Кабинет разберёт сертификат, возьмёт SHA-256 от его открытого ключа и запишет результат в вашу зону.

Опубликованный отпечаток и подтверждение, какой ключ распознан

Сверьте этот отпечаток со своим — они должны совпасть:

openssl x509 -in site.crt -noout -pubkey \
  | openssl pkey -pubin -outform der | openssl dgst -sha256

Панель — это парадный вход к обычной записи. То же значение лежит в списке записей как запись TLSA на _443._tcp, и его там видно:

Запись TLSA в обычном списке записей

6. Направьте имя на свой сервер

В том же разделе добавьте запись A, значение которой — публичный адрес вашего сервера. @ означает само имя.

Форма записи A с адресом сервера

Теперь в зоне обе записи, и вместе они — всё, что нужно приложению посетителя: запись A говорит, где ваш сервер, запись TLSA — какой ключ он обязан предъявить.

Обе записи в списке: TLSA и A

Заложите около десяти минут, прежде чем ждать, что изменение видно везде. На пути стоят два кэша — резолвера и приложения — по пять минут каждый.

7. Проверьте

Кабинет забирает ваш сайт так же, как это сделал бы посетитель, и сообщает, что помешает работе: ключ, не совпадающий с опубликованным, отсутствующий отпечаток, заголовок HSTS, переадресация на https://, абсолютные ссылки на себя или сервер, который не ответил.

Проверка сообщает, что адрес не публичный

На этом снимке проверка отказалась выполняться: адрес в примере — документационный, а кабинет не станет опрашивать то, что недоступно из интернета: направив имя на частный адрес или на петлевой, вы превратили бы проверку в зондирование чужой сети. С настоящим сервером на настоящем адресе она отвечает, что с сайтом всё в порядке, либо называет, что именно не так.

Две проверки, которые можно сделать самому, и это как раз самые важные:

# без SNI — отказ
openssl s_client -connect YOUR_ADDRESS:443 </dev/null

# ваш сертификат
openssl s_client -connect YOUR_ADDRESS:443 -servername mysite.lopux </dev/null

Вторая должна отдать сертификат, отпечаток которого вы опубликовали. Возьмите отпечаток его ключа так же, как в §5, и сравните: если строки разойдутся, каждому посетителю будет отказано, а выглядеть для него это будет ровно как попытка подмены.

8. Что видит посетитель

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

Сайт lopux.ipvx, открытый под своим именем

Это lopux.ipvx — собственный сайт проекта. Он живёт в пространстве имён так же, как будет жить ваш, и развёрнут ровно по этой схеме. Ключ, который он отдаёт, совпадает с его опубликованным отпечатком — именно поэтому приложение открывает его без единого предупреждения.

Что получают разные посетители:

ПосетительЧто он видит
приложение, имя внутри открытой зоны вроде .lopuxобычный замочек, всё работает
приложение, собственное корневое имяпредупреждение браузера о сертификате каждый раз — отпечаток при этом всё равно сверяется
приложение, в адресной строке http://страница выглядит простой; путь до вашего сервера всё равно зашифрован и ключ всё равно сверен
без приложенияничего. Имя не разрешается за пределами Лопух-Интернета

Последняя строка — это смысл пространства имён, а не его недостаток. Но обратите внимание на строку выше: ваш сервер — обычная публичная машина, и добраться до неё по адресу может кто угодно. Пространство имён его не прячет, а сертификат называет ваш сайт всякому, кто завершил рукопожатие — для этого и нужен запрет по SNI из §4.

9. Как беречь ключ

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

старый;

10. Когда что-то не так

Приложение называет неполадку, а не показывает пустую страницу. Что означает каждая:

Что сказали посетителюЧто это значитЧей ход
Для этого имени не опубликован отпечаток ключав зоне нет записи TLSAваш — §5
Это не тот сайт, за который он себя выдаётключ вашего сервера не тот, что опубликованваш — вы сменили сертификат, не опубликовав новый отпечаток
Сайт не ответилс именем и ключом всё хорошо, сервер не отозвалсяваш — проверьте сервер и запись A
Эта страница не может работать по обычному httpабсолютные https://-ссылки на ваш же сайтваш — сделайте их относительными (§4)
Этому приложению нужно обновление, чтобы открыть этот сайтприложение посетителя старше вашей зоныего — пусть обновится; с сайтом всё в порядке

Все инструкции