Self-hosting на мини-ПК с Docker и Cloudflare Tunnel
Как безопасно опубликовать несколько веб-сервисов с одного домашнего мини-ПК. Без открытия портов: HTTPS через Cloudflare Tunnel, запуск через Docker Compose.
Главное
Поднимаем сервисы на мини-ПК через Docker Compose и подключаем домен и HTTPS через Cloudflare Tunnel (cloudflared) без открытия портов. Не нужны ни настройка роутера, ни статический IP, ни продление сертификатов.
Содержание
Счета за облако для маленьких проектов ощутимо кусаются. Я держу несколько сервисов, включая этот блог, на одном домашнем мини-ПК. Делюсь, как это устроено.
Почему мини-ПК
- Всегда включён, а электричество стоит копейки в месяц
- С Docker окружение для деплоя ничем не отличается от облака
- Вырастет трафик - тогда и переедем
Проблема ровно одна: "как безопасно выставить домашнюю сеть наружу".
Не открывайте порты
Классический путь - проброс портов на роутере + DDNS + продление сертификатов. Это муторно и рискованно: по сути вы открываете домашнюю сеть прямо в интернет.
Вместо этого используем Cloudflare Tunnel. На мини-ПК cloudflared открывает соединение к Cloudflare изнутри наружу, и трафик приходит через этот туннель. Входящих портов, открытых наружу, ровно 0.
사용자 → Cloudflare(HTTPS) → 터널 → 미니 PC 의 컨테이너
- Публичный IP и проброс портов не нужны
- HTTPS-сертификаты Cloudflare обслуживает автоматически
- Динамический IP не помеха
Собираем сервисы через Docker Compose
Каждый сервис запускается в контейнере. Если это Next.js-приложение, собираем с output: "standalone", чтобы образ получился лёгким.
services:
blog:
build:
context: .
dockerfile: apps/blog/Dockerfile
container_name: why-next-blog
restart: unless-stopped
networks: [api]
networks:
api:
external: true # cloudflared 와 같은 네트워크
Ключевой момент: контейнер должен быть в той же docker-сети, что и cloudflared. Тогда туннель найдёт сервис по имени контейнера.
Подключаем домен
В дашборде Cloudflare (или в настройках туннеля) добавляем один Public Hostname.
blog.example.com → http://why-next-blog:3001
И всё. Запускаете docker compose up -d --build, и через пару минут сайт открывается по домену.
Итоги
- Мини-ПК + Docker = дёшево и деплой как в облаке
- Cloudflare Tunnel даёт HTTPS и домен без открытия портов
- Контейнеры размещаем в одной сети с cloudflared
- Public Hostname задаёт маппинг
도메인 → 컨테이너:포트
Для небольших сервисов этой связки хватит надолго. Я сам так запускаю несколько приложений и понемногу пополняю список того, что сделал.
Частые вопросы
У меня дома динамический IP, это не проблема?
Не проблема. Cloudflare Tunnel работает так, что мини-ПК сам открывает исходящее соединение к Cloudflare, поэтому публичный IP, проброс портов и DDNS вообще не нужны.
Сколько это стоит?
Сам Cloudflare Tunnel бесплатен. Для старта достаточно оплатить только домен.
Похожие статьи
- 💻 Разработка
Если у одного бакета два владельца, побеждает тот, чей apply был последним
Я добавил одно lifecycle-правило для S3, и terraform apply упал. Причина: конфигурацией lifecycle одного и того же бакета владели два ресурса, каждый сам по себе. S3 lifecycle работает не на уровне отдельных правил, а на уровне документа целиком, поэтому последний победитель тихо стирает правила соперника.
- 💻 Разработка
Тесты были зелёными, а уведомление не отправилось ни разу
Код, ставивший задачу в очередь, падал с первого дня, каждый раз. Ошибка проглатывалась, а тесты благодаря мокам оставались зелёными. История о том, как одно двоеточие тихо убило три фичи.
- 💻 Разработка
Пришло оповещение, что база упала. База не падала ни разу
За сутки накопилось четыре оповещения уровня CRITICAL. 504, Prisma P2028, 500 в админке и «сервис DATABASE недоступен». Я первым делом открыл метрики RDS: все 21 час база держала CPU максимум на 19,7% и чувствовала себя прекрасно. Тормозила не база, а круговые поездки через Атлантику, которых на один запрос приходилось двадцать пять. А оповещение о «недоступности» хелсчек сочинил сам про себя.