Доступ к домашнему серверу без публичного IP

26.06.23

Интеграция - WEB-интеграция

У меня была идея поднять дома сервер, доступный из интернета, с шифрованием трафика и, что самое главное, бесплатный!

Рецепт сервера обычной компании:

  1. Белый IP
  2. Веб-сервер (nginx, apache, IIS, winow и т.д.)
  3. Сертификаты для протокола https

Если есть много денег, то купить ssl сертификаты, белый IP и группу сисадминов для поддержки - это не проблема. Но если ты хочешь создать пет проект в вебе, или создать свой сервис, платить деньги - не вариант. А значит, некоторые ингредиенты рецепта надо заменить на бесплатные альтернативы

 

Рецепт бесплатного сервера:

  1. DynamicDNS
  2. Веб-сервер
  3. Сертификаты Let's Encrypt
  4. Docker, потому что пора бы наконец научиться пользоваться.
  5. Какой-никакой роутер с root доступом и возможностью проброса портов

Итак, начнем по порядку.

 

1. Dynamic DNS

Динамический DNS (далее по тексту DDNS) нужен для того, чтобы вы могли стучаться в свою локальную сеть. Как это работает? Вам дается адрес, чаще всего состоящий из ВашСубДомен.ДоменПоставщика.com/org или любое другое расширение. При отправке запроса на этот адрес, вызов перенаправляется в вашу локальную сеть. Для того, чтобы DDNS знал, куда пересылать запрос, вы периодически обновляете информацию о вашем текущем IP адресе на хосте DDNS. Для каждого DDNS есть своя инструкция по обновлению информации об IP адресе.

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

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

 

 

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

Запомним токен и домен, далее эти данные нам понадобятся.

 

2. Веб-сервер

Я думаю для 1Сников не надо объяснять что такое веб-сервер. Практически все так или иначе слышали слова apache и IIS. Но на всякий случай, веб-сервер - это такая хитрая штука, которая умеет принимать http-запросы и выдавать http-ответы. Но! Это важно. В нашем случае мы не будем настраивать веб-сервер в привычном для этой фразы понимании. Дело в том, что нам нужен обратный прокси-сервер. Это такая штука, которая принимает http-запросы и пересылает их дальше по требованию. 

 

Почему именно так?

Потому что мы будем настраивать возможность обмена информацией через защищенный протокол https. Наш прокси должен получить https-запрос, дешифровать его в незащищенный http-запрос и передать его на нужный порт в нашей локальной сети. Далее, из нашей локальной сети от принимает незащищенный http-ответ, шифрует его в защищенный https-ответ и отдает клиенту. Такая "архитектура" позволит нам не заморачиваться с сертификатами в наших сервисах, а отдать все действия по шифровке/дешифровке обратному прокси-серверу.

Обратный прокси-сервер мы будем поднимать в докер контейнере, потому что он нам в локальной сети вообще никуда не упал. Это отдельный сервис, пусть живет отдельной жизнью. Поскольку это будет не единственный контейнер, мы будем использовать docker-compose.  

Да, кстати, для обратного прокси-сервера мы будем использовать nginx, потому что пора узнать что есть что-то кроме apache и IIS.

 

Пример конфигурации контейнера в docker-compose файле:

version: '3'

services:
  nginx:
    container_name: nginx
    image: nginx:stable-alpine3.17-slim 
    ports:
      - 8080:80
      - 8443:443
    volumes:
      - ./nginx:/etc/nginx
      - ./letsencrypt:/etc/letsencrypt
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
    extra_hosts:
      - "host.docker.internal:host-gateway"

Что означают все эти буквы?

"version: '3'" - объявляем, какую версию compose файла мы используем

"services:" - внутри мы будем описывать, какие сервисы мы будем использовать

"nginx:" - имя сервиса (придумываем сами)

"container_name: nginx" - имя контейнера (придумываем сами)

"image: nginx:stable-alpine3.17-slim" - указываем, какой docker образ мы будем использовать в сервисе. Все образы можно посмотреть в docker hub

"ports:
      - 8080:80
      - 8443:443"
- проброс портов в формате "порт локального хоста : порт контейнера". В данном случае контейнер будет слушать порт 8080 и 8443 вашего хоста и передавать на порт 80 и 433 соответственно внутренней сети контейнера. Порт контейнера нужно устанавливать такой же, который прописан в конфигурационном файле нашего прокси-сервера (доберемся и до него в порядке живой очереди). Порт хоста нужно задать такой же, как в настройках проброса портов в роутере 

Например: у меня роутер настроен так, все входящее на порт 80 он пробрасывает на порт 8080 моего компьютера, а входящие сообщения на порт 443 отправляет на порт 8443 компьютера.

"volumes:
      - ./nginx:/etc/nginx
      - ./letsencrypt:/etc/letsencrypt"
- монтируем папки в контейнер. То есть папка nginx на вашем компьютере и папка /etc/nginx в контейнере - это одна и та же папка с файлами. Это нужно для того, чтобы мы могли отдавать в контейнер нужные файлы (например конфигурацию или сертификаты) и менять эти файлы в режиме реального времени. 

"command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"" - команда, которая выполнится при старте контейнера. Это рекомендованная строка для запуска nginx взятая из гайдов в интернете. И она работает. Все. Идем дальше.

"extra_hosts:
      - "host.docker.internal:host-gateway""
- эти строки говорят о том, что мы настраиваем связь между сетью контейнера и хостом. Нужна она для того, чтобы мы могли из докера стучаться в сеть хоста. (далее по тексту будет пример, как это работает)

 

Пример конфигурации nginx:

 

events {}
http {

  server {
    listen 80;
    location / {
      return 301 https://domain.duckdns.org$request_uri;
    }
  }

  server {
    listen 443 ssl http2;

    ssl_certificate /etc/letsencrypt/live/domain.duckdns.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/domain.duckdns.org/privkey.pem;
    ssl_session_cache shared:le_nginx_SSL:10m;
    ssl_session_timeout 1440m;
    ssl_session_tickets off;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

     location / {
      add_header Cache-Control "public, must-revalidate";
      add_header Front-End-Https on;
      add_header Strict-Transport-Security "max-age=2592000; includeSubdomains";
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_pass http://host.docker.internal:443;   
     }
  }
} 

Тут мы остановимся только на тех строках, которые что-то для нас значат. В остальном - это стандартная конфигурация nginx для обратного прокси-сервера.

"listen 80" - сюда пишем порт, который мы указывали в docker-compose файле, для http-запросов

"return 301 https://domain.duckdns.org$request_uri" - если мы получили незашифрованный http-запрос, мы делаем редирект на https, чтобы получить защищенный https-запрос. Вместо domain нужно указать ваш домен в duckdns, который вы придумали и создали.

"listen 443 ssl http2" - сюда пишем порт, который мы указывали в docker-compose файле, для https-запросов.

"ssl_certificate /etc/letsencrypt/live/domain.duckdns.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.duckdns.org/privkey.pem;"
- путь до сертификатов, которые мы получим позже. Что делать со словом domain, думаю, догадаетесь :)

"ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;" - невероятно важный файлик, без которого наш прокси просто не запустится. Скачать можно с официального репозитория

"proxy_pass http://host.docker.internal:443;" - а вот и отправка расшифрованного сообщения на хост. "host.docker.internal" в нашей конфигурации - это IP адрес хоста (вашего ПК/ноута или с чего вы там все это запускаете). А вот с портом сложнее. Тут надо указать такой порт, который слушает ваш сервис/приложение.

Так должен выглядеть файл с названием nginx.conf.

Ну, вроде с nginx более менее разобрались, по крайней мере в контексте настройки нашего прокси.

 

3. Сертификаты

Есть такая компания Let's Encrypt. Эта компания поставила перед собой задачу - перевести весь интернет на протокол https. Как это сделать? Правильно. Дать бесплатные сертификаты. Я не работал с платными TLS сертификатами, так как моя сфера работы чуть чуть другая, поэтому вся разница для меня состоит в цене (учитывая что я поднимаю свой домашний сервер). 

Далее, для удобного получения сертификатов была написана программа/библиотека на python - Certbot. Теперь получить сертификат можно было командой в командной строке, или вызвав программный интерфейс библиотеки, если вы встроили эту библиотеку в свою программу. Но и это еще не все.

Чтобы получить сертификат, вы должны подтвердить, что защищаемый сертификатами домен принадлежит вам. Для этого вы должны разместить специальную строку в специальном месте, которую центр сертификации обязательно проверит. А поскольку мы используем DDNS, мы не можем просто так куда-то что-то там размещать и проверять. Поэтому, сервисы DDNS создали специальный API, используя который вы можете разместить TXT запись в вашем субдомене DDNS для проверки. А где появляются какие-то API, появляются и энтузиасты, пишущие свои библиотеки/программы для использования этого самого API.

В итоге, чтобы не изобретать велосипед, вы должны перелопатить интернет в поисках той самой библиотеки, у которой будет самая адекватная документация, чтобы не тратить много времени на изучения возможностей. И тут мы приходим к интересному проекту, который был написан для интеграции программы certbot c DDNS DuckDNS - certbot_dns_duckdns. Вот ее мы и будем использовать в нашем проекте.

 

Пример конфигурации контейнера в docker-compose файле:

 

version: '3'

services:
  certbot:
    image: "infinityofspace/certbot_dns_duckdns:latest"
    container_name: "certbot"
    volumes:
      - "./letsencrypt:/etc/letsencrypt"
      - "./logs:/var/log/letsencrypt"
    command: certonly
      --non-interactive
      --agree-tos
      --email {YOUR_EMAIL}
      --preferred-challenges dns
      --authenticator dns-duckdns
      --dns-duckdns-token {YOUR_TOKEN}
      --dns-duckdns-no-txt-restore
      --dns-duckdns-propagation-seconds 15
      -d "domain.duckdns.org"
      -d "*.domain.duckdns.org"

Со значениями полей мы уже знакомы. Тут нас интересует поле "command". Это та самая команда, которая при запуске запустит процесс получения сертификатов. Тут нужно исправить несколько значений. "{YOUR_EMAIL}" - тут надо указать свой почтовый адрес, для регистрации сертификата. "{YOUR_TOKEN}" - сюда нужно установить токен, который вы получили в DuckDNS. Токен нужен как раз для интеграции. Со словами "domain" делать тоже, что и всегда - менять на свой домен из DuckDNS.

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

version: '3'

services:
  nginx:
    container_name: nginx
    image: nginx:stable-alpine3.17-slim 
    ports:
      - 8080:80
      - 8443:443
    volumes:
      - ./nginx:/etc/nginx
      - ./letsencrypt:/etc/letsencrypt
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
    extra_hosts:
      - "host.docker.internal:host-gateway"
  
  certbot:
    image: "infinityofspace/certbot_dns_duckdns:latest"
    container_name: "certbot"
    volumes:
      - "./letsencrypt:/etc/letsencrypt"
      - "./logs:/var/log/letsencrypt"
    command: certonly
      --non-interactive
      --agree-tos
      --email {YOUR_EMAIL}
      --preferred-challenges dns
      --authenticator dns-duckdns
      --dns-duckdns-token {YOUR_TOKEN}
      --dns-duckdns-no-txt-restore
      --dns-duckdns-propagation-seconds 15
      -d "domain.duckdns.org"
      -d "*.domain.duckdns.org"

Вот так должен выглядеть файл, с необычным названием docker-compose.yml для запуска (конечно же с вашими правками, которые мы рассмотрели выше).

Структура проекта при этом будет выглядеть примерно так:

 - letsencrypt - директория

 -- ssl-dhparams.pem - файл из п.2

 - nginx - директория

 -- nginx.conf - файл конфигурации из п.2

 - docker-compose.yml - файл вместивший в себя описание контейнеров

Директории будут монтированы в контейнеры для обмена информации

 

4. Запуск

Сначала, надо установить docker и docker-compose

Открыть командную строку и перейти в корневую директорию проекта.

Выполнить команду "docker compose -f "docker-compose.yml" up -d --build"

При первом запуске контейнер с прокси-сервером выдаст ошибку, так как не сможет найти сертификаты, они еще не созданы.

Контейнер certbot предпримет попытку создания сертификатов. Возможно, по какой-то причине не пройдет проверка домена. При этом в контейнере выйдет ошибка 

Certbot failed to authenticate some domains (authenticator: dns-duckdns). The Certificate Authority reported these problems:
   Domain: domain.duckdns.org
   Type:   unauthorized
   Detail: Incorrect TXT record "{какой-то ключ}" found at _acme-challenge.domain.duckdns.org

 Надо проверить, все ли вы правильно указали, соответствует ли ваш IP адрес в 2IP и DuckDNS, и запустить контейнер еще раз.

То, что сертификаты были правильно созданы, будет сопровождаться сообщением в логе:

 Successfully received certificate.
 Certificate is saved at: /etc/letsencrypt/live/domain.duckdns.org/fullchain.pem
 Key is saved at:         /etc/letsencrypt/live/domain.duckdns.org/privkey.pem
 This certificate expires on {какая-то дата окончания}.

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

При отправке HTTPS-запроса на адрес или http://domain.duckdns.org, прокси получит данные, расшифрует и отправит HTTP-запрос на ваш хост.

Запускам наш сервис, запускаем контейнер nginx, делаем запрос на адрес https://domain.duckdns.org, получаем результат

 

 

Браузер не ругается на небезопасное соединение, сервис отдает ответ, все работает как и задумывалось.

 

Итог

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

Также, вы должны понимать, что вам понадобится еще несколько настроек. Вам надо отправлять в duckdns свой текущий IP адрес для автоматического обновления. Как это сделать описано тут, ну или вы можете отправлять https-запрос типа https://www.duckdns.org/update?domains={YOURVALUE}&token={YOURVALUE}[&ip={YOURVALUE}]

Также, было бы неплохо настроить контейнер certbot на автоматический перевыпуск сертификатов после окончания их действия (срок жизни сертификата - 90 дней). В противном случае раз в 90 дней вы должны будете руками запускать контейнер для перевыпуска сертификатов.

nginx docker docker-compose прокси-сервер certbot letsencrypt

См. также

WEB-интеграция Анализ продаж Системный администратор Программист Пользователь Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Управленческий учет Платные (руб)

Модуль "Подсистема интеграции AmoCRM с 1С" позволяет обеспечить единое информационное пространство, в котором пользователи могут эффективно управлять клиентской базой, следить за статусами сделок и поддерживать актуальность данных как в AmoCRM, так и в 1С. Бесплатный период Техподдержки - 1 месяц.

60000 руб.

07.05.2019    34439    65    45    

26

WEB-интеграция Администрирование веб-серверов Платные (руб)

Веб-портал обеспечивает удобный доступ к конфигурации 1С:ITIL, 1С:ITILIUM, Управление IT-отделом 8 через интернет с любого устройства посредством браузера, увеличивая эффективность работы пользователей и снижая нагрузку на сервер. Быстрая инсталляция портала за пару часов, удобный и интуитивно понятный интерфейс и безопасность данных помогут упростить работу с порталом и ускорить выполнение бизнес-процессов компании.

128000 руб.

19.12.2023    2429    2    0    

9

Оптовая торговля Розничная торговля WEB-интеграция 1С:Управление торговлей 10 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Платные (руб)

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

57600 руб.

26.11.2024    2155    1    1    

4

Сайты и интернет-магазины WEB-интеграция Системный администратор Программист Пользователь Платформа 1С v8.3 1C:Бухгалтерия 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме.

36000 руб.

03.08.2020    18961    21    22    

18

WEB-интеграция Программист Руководитель проекта Платформа 1С v8.3 1C:Бухгалтерия 1С:Франчайзи, автоматизация бизнеса Платные (руб)

Расширение значительно упрощает написание API на 1С. Веб программисты получают простой и понятный доступ к 1С. Описание API создаётся автоматически и представляется в виде удобном как для человека, так и для программной обработки.

24000 руб.

27.09.2024    3793    3    2    

4

WEB-интеграция Программист Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бытовые услуги, сервис Платные (руб)

Внешняя обработка разрабатывалась для загрузки документов из Ветменеджер в 1С: Бухгалтерия 3.0

12000 руб.

02.02.2021    18724    53    50    

29

WEB-интеграция Программист Бизнес-аналитик Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Оптовая торговля, дистрибуция, логистика ИТ-компания Платные (руб)

Модуль "Экспортер" — это расширение для 1С, предназначенное для автоматизации процессов выгрузки данных. Оно позволяет эффективно извлекать, преобразовывать и передавать данные из систем 1С в интеграционную платформу Spot2D. Подсистема упрощает настройку, снижает количество ручных операций и обеспечивает удобный контроль данных.

14400 руб.

20.12.2024    744    3    1    

5

Обмен с ГосИС WEB-интеграция Бухгалтер Пользователь Платформа 1С v8.3 Управляемые формы 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Управление производственным предприятием 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия государственного учреждения 1С:Документооборот 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Платные (руб)

Обработка является альтернативой механизму, разработанному фирмой 1С и заполняющему реквизиты контрагента по ИНН или наименованию. Не требуется действующей подписки ИТС. Вызывается как внешняя дополнительная обработка, т.е. используется, непосредственно, из карточки контрагента. Заполнение по ИНН или наименованию реквизитов контрагента по данным сайта ФНС (egrul.nalog.ru) для БП 2.0, БП 3.0, БГУ 1.0, БГУ 2.0, УТ 10.3, УТ 11.x, КА 1.1, КА 2.x, УПП 1.x, ERP 2.x, УНФ 1.5, УНФ 1.6, УНФ 3.0, ДО 2.1

2400 руб.

28.04.2016    92746    187    217    

340
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. SerVer1C 874 26.06.23 14:05 Сейчас в теме
Если у вас серый динамический ip-адрес (т.е. вы сидите за NATом, или, не приснись, за двойным NATом),тогда DynDNS вам не поможет. Лично у меня краснояйцевый оператор таким грешит.
Trucker; kamisov; +2 Ответить
4. nemec 27 29.06.23 16:58 Сейчас в теме
(1) Решение тем не менее есть - покупаем вместо мусора в виде роутера, любое современное устройство компании которое начинается на буку К и на букву К заканчивается (бывшее подразделение компании З. - чтобы не сочли за рекламу), которые в своей прошивке обладает "массой ненужных функций" (ц) диванные интернет эксперты. У них есть совершенно бездвоздмездно, то есть даром, сервис динамического ДНС, в том числе и для серых адресов через собственное облако. В комплекте идет автоматически обновляемый LetsEncrypt, так что вашей задачей будет только указать настройки переадресации или просто добавить уникальное доменное имя для вашего сервера и на этом всё. Т.е. прямо для своего сервера задаете в настройках роутера адрес типа "1ссервер.мойроутердома.к.......к.линк" и вся маршрутизация заворачивается на него
Aleskey_K; Krahmalov; TerveRus; +3 1 Ответить
6. user716566 14.07.23 13:36 Сейчас в теме
(1)А связаться с Вами можно?
2. siamagic 26.06.23 14:47 Сейчас в теме
Я у себя хостинг так держал - докер опять засунули туда где не ждали, школота блин ) лижбы совать и перепечатывать инструкции с инета.
3. agentz 40 29.06.23 16:26 Сейчас в теме
Сидя за NAT вы можете сидеть в серой сети и провайдер а) не даст белый ip, даже динамический б) провайдер не даст открыть порты. Решение: проще не придумаешь ngrok , вариант по сложнее мелкий сервер в облаке и ВПН к нему
5. itmind 309 03.07.23 07:30 Сейчас в теме
Я думаю, что VPS за 150-300 руб в месяц у облачных провайдеров не такая уж и большая сумма для программиста.
7. webresurs 229 26.07.24 08:47 Сейчас в теме
ZeroTier - аналог LogMeIn Hamachi...
- в бесплатной версии до 25 пользователей
- подключение за белым,серым ип адресом, главное что бы был интернет

- при желании можно поднять свой сервер на virtualbox - бесплатно, без ограничений вроде, с серым ип адресом наверное прииидеться покумекать..
Оставьте свое сообщение