Сервер в плену чужого NAT

Обложка

Боль – Proxmox-сервер живёт в чужой сети, за чужим NAT. Шлюз не мой, портов не даёт, статику режет (только DHCP). Белого IP нет вообще. Классика «сервер лежит непонятно где».

Но снаружи у меня всё работает: – HTTPS для lab.example (Caddy, сертификаты Let's Encrypt) – SSH-доступ к роутерам – Мониторинг, фото, локальные LLM — открываются из любого интернета

Решение Три кита, на которых вывез всю историю: 1) Виртуальная сеть, изолированная от внешней шизофрении – Поднял вторую сеть br1 (198.51.100.0/24) без IP на хосте. Внутри неё живут сервисы: Beszel, Uptime Kuma, Immich, Ollama, Hermes. – Шлюз и NAT — отдельный LXC-контейнер с Caddy (198.51.100.1): он делает masquerade из внутренней сети в наружу, ip_forward=1.

Врезка: схема NAT/туннель– Зачем? Сервисы получают стабильную адресацию и жизнь, независимую от капризов внешнего мира.

2) Туннель, который сам уходит из-под NAT – Контейнер с Caddy инициирует SSH reverse-туннель к моему MikroTik с белым IP (203.0.113.20). – Внешние порты 443 и 80 на роутере редиректятся на 8443 и 8080, которые поднял SSH-туннель, — и уже по туннелю трафик попадает в Caddy. – Схема: интернет → MikroTik (белый IP) → SSH reverse → Caddy → сервисы в br1. – Снаружи всё приходит на 443/80, внутри туннеля — на 8443/8080.

3) Один вход — одна дверь – Весь внешний трафик встречает Caddy: раздаёт по доменам, сам продлевает TLS-сертификаты, на нём же ACL для админок. Одна точка входа — меньше боли и хаоса.

Бонус: SSH reverse-туннель, или «костыль, который стал фичей» Суть – Обычный SSH-туннель (-L) тянет удалённый порт к тебе. Reverse (-R) делает наоборот: машина за NAT сама стучится наружу и «пробрасывает» свой локальный порт на стороне сервера. – Натурально подходит для железок за CGNAT, подвалов и «дач».

Правильная картинка в моём кейсе:

Caddy (за NAT)  ──ssh -R──>  MikroTik (белый IP)
      │                           │
      └── на MikroTik открыты 8443/8080 → идут в мой localhost:443/80

Команды — как у меня Шаг 1. На MikroTik — разрешить SSH-форвардинг:

/ip ssh forwarding-enabled=both

Шаг 2. На MikroTik — локально перенаправить внешние 443/80 на 8443/8080 (куда слушает sshd для -R):

/ip firewall nat add chain=dstnat protocol=tcp dst-port=443 action=redirect to-port=8443
/ip firewall nat add chain=dstnat protocol=tcp dst-port=80  action=redirect to-port=8080

Шаг 3. На MikroTik — пропустить эти порты в firewall (до drop-правила):

/ip firewall filter add chain=input protocol=tcp dst-port=8443,8080 action=accept

Шаг 4. На Caddy (Linux) — поднять сам reverse-туннель:

ssh -R 8443:localhost:443 -R 8080:localhost:80 \
    -N -o ServerAliveInterval=30 -o ExitOnForwardFailure=yes \
    admin@203.0.113.20

Шаг 5. Завернул это в systemd-сервис (mt-tunnel.service), чтобы жил после ребута и сам переподключался.

Итог: открываю https://router.lab.example — попадаю в Winbox роутера за NAT. Один вход — и весь дом за ним.

Почему это «костыль», но рабочий – SSH — это TCP поверх TCP: на потере пакетов ведёт себя хуже UDP-туннелей. – Одно длинное соединение, которое надо держать живым. – Ключ от роутера лежит на Caddy: его компрометация = доступ к роутеру.

Почему не WireGuard – Пробовал — не завёлся в непривилегированном LXC (нет /dev/net/tun). – SSH уже был настроен, ключи были — 5 минут до рабочего результата. – «Правильный» вариант — WG с TUN:

# на хосте PVE, в конфиге контейнера
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file 0 0

потом mknod /dev/net/tun c 10 200 внутри — и WG поднимается как надо.

Цифры и железки – Proxmox PVE 9.2: – br0 (192.0.2.0/24, DHCP, шлюз 192.0.2.1 — MAC от VMware, статику режут) – br1 (198.51.100.0/24, без IP на хосте) – Caddy lxc-gw: 198.51.100.1 (шлюз br1), NAT masquerade br1→wan, ip_forward=1 – SSH reverse-туннель: Caddy → admin@203.0.113.20 (MikroTik), 443→8443, 80→8080, keepalive=30 c, systemd-сервис mt-tunnel – MikroTik: /ip ssh forwarding-enabled=both; dstnat redirect 443→8443, 80→8080; firewall input accept tcp 8443/8080 (до drop) – Сертификаты: Let's Encrypt для lab.example (валиден до ноября 2026) – Сервисы в br1: – Beszel — 198.51.100.12 – Uptime Kuma — 198.51.100.14 – Immich — 198.51.100.15 – Hermes — 198.51.100.16 – Ollama — 198.51.100.17

Вывод Сервер может жить за любым NAT — хоть у соседа, хоть на «даче». Пока есть исходящий интернет, все сервисы доступны снаружи через один туннель и один шлюз. Костыль? Да. Рабочая фича? Тоже да.

#network #selfhosting