Вопрос или проблема
Я пытаюсь установить mailcow-dockerized на своем сервере, но у меня есть проблемы с сетью Docker. Я пробовал несколько способов, но у меня много таймаутов соединения в контейнерах.
Чтобы разобраться с проблемой, я решил оставить Mailcow и установил только Docker, чтобы попытаться выявить источник этих таймаутов соединения.
Итак, я установил свежий образ Ubuntu 20.04 от моего провайдера VPS и настроил брандмауэр ufw следующим образом:
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw limit ssh
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw allow smtp
sudo ufw allow submission
sudo ufw allow submissions
sudo ufw allow pop3
sudo ufw allow pop3s
sudo ufw allow imap2
sudo ufw allow imaps
sudo ufw allow 4190/tcp
sudo ufw allow 8080/tcp
sudo systemctl enable ufw
sudo ufw enable
Я установил Docker с помощью скрипта get-docker.sh
с https://get.docker.com
Затем я включил IPV6 в файле /etc/docker/daemon.json следующим образом:
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1::/64"
}
Перезагрузил сервер и создал файл docker-compose.yaml:
version: '2.1'
services:
S2:
image: nginx:latest
ports:
- 80:80
restart: always
networks:
n1:
ipv4_address: 172.22.1.254
aliases:
- s2
S3:
image: nginx:latest
ports:
- 8080:80
restart: always
networks:
n1:
ipv4_address: 172.22.1.248
aliases:
- s3
networks:
n1:
driver: bridge
driver_opts:
com.docker.network.bridge.name: n1
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.22.1.0/24
- subnet: fd4d:6169:6c63:6f77::/64
Эту конфигурацию сети я взял из docker-compose.yaml в репозитории Mailcow и изменил ее, чтобы адаптировать к своему тесту.
И я запустил контейнеры с помощью docker-compose up -d
.
Когда я выполняю curl localhost 80
на хост-сервере, он возвращает стандартное содержимое index.html от Nginx, но… соединение зависает на несколько минут, а затем в терминале появляется следующее сообщение в конце:
curl: (28) Failed to connect to 80 port 80: Connection timed out
Когда я запускаю curl <myservername.com> 80
на своем локальном компьютере, он также возвращает содержимое index.html от стандартного Nginx, но с сообщением в конце:
curl: (7) Failed to connect to 0.0.0.80 port 80 after 0 ms: Network unreachable
Есть ли какие-либо подсказки о том, почему я получаю эти ошибки?
PS: статус моего ufw:
# ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
25/tcp ALLOW IN Anywhere
587/tcp ALLOW IN Anywhere
465/tcp ALLOW IN Anywhere
110/tcp ALLOW IN Anywhere
995/tcp ALLOW IN Anywhere
143/tcp ALLOW IN Anywhere
993/tcp ALLOW IN Anywhere
4190/tcp ALLOW IN Anywhere
8080/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
25/tcp (v6) ALLOW IN Anywhere (v6)
587/tcp (v6) ALLOW IN Anywhere (v6)
465/tcp (v6) ALLOW IN Anywhere (v6)
110/tcp (v6) ALLOW IN Anywhere (v6)
995/tcp (v6) ALLOW IN Anywhere (v6)
143/tcp (v6) ALLOW IN Anywhere (v6)
993/tcp (v6) ALLOW IN Anywhere (v6)
4190/tcp (v6) ALLOW IN Anywhere (v6)
8080/tcp (v6) ALLOW IN Anywhere (v6)
А вот результаты lsof:
# lsof -i -P -n | grep LISTEN
sshd 967 root 3u IPv4 35459 0t0 TCP *:22 (LISTEN)
sshd 967 root 4u IPv6 35461 0t0 TCP *:22 (LISTEN)
docker-pr 1290 root 4u IPv4 39102 0t0 TCP *:80 (LISTEN)
docker-pr 1308 root 4u IPv6 38124 0t0 TCP *:80 (LISTEN)
docker-pr 1322 root 4u IPv4 38165 0t0 TCP *:8080 (LISTEN)
docker-pr 1328 root 4u IPv6 38172 0t0 TCP *:8080 (LISTEN)
Мониторинг Termshark при выполнении curl localhost 80
на хосте:
No. - Time - Source - Destination - Protocol - Length - Info -
1 0.000000 fd4d:6169:6c63 fd4d:6169:6c63 TCP 94 39946 → 80 [SYN] Seq=0 Win=64800 Len=0 MSS=
2 0.000047 fd4d:6169:6c63 fd4d:6169:6c63 TCP 94 80 → 39946 [SYN, ACK] Seq=0 Ack=1 Win=64260
3 0.000088 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 39946 → 80 [ACK] Seq=1 Ack=1 Win=64896 Len=
4 0.000516 fd4d:6169:6c63 fd4d:6169:6c63 HTTP 159 GET / HTTP/1.1
5 0.000544 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 80 → 39946 [ACK] Seq=1 Ack=74 Win=64256 Len
6 0.000765 fd4d:6169:6c63 fd4d:6169:6c63 TCP 324 HTTP/1.1 200 OK [TCP segment of a reassemb
7 0.000791 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 39946 → 80 [ACK] Seq=74 Ack=239 Win=64768 L
8 0.000821 fd4d:6169:6c63 fd4d:6169:6c63 HTTP 701 HTTP/1.1 200 OK (text/html)
9 0.000829 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 39946 → 80 [ACK] Seq=74 Ack=854 Win=64256 L
10 65.01291 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 80 → 39946 [FIN, ACK] Seq=854 Ack=74 Win=64
11 65.05677 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 39946 → 80 [ACK] Seq=74 Ack=855 Win=64256 L
12 130.8576 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 39946 → 80 [FIN, ACK] Seq=74 Ack=855 Win=64
13 130.8577 fd4d:6169:6c63 fd4d:6169:6c63 TCP 74 80 → 39946 [RST] Seq=855 Win=0 Len=0
14 131.0647 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 [TCP Retransmission] 39946 → 80 [FIN, ACK]
15 131.0648 fd4d:6169:6c63 fd4d:6169:6c63 TCP 74 80 → 39946 [RST] Seq=855 Win=0 Len=0
16 131.2727 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 [TCP Retransmission] 39946 → 80 [FIN, ACK]
17 131.2728 fd4d:6169:6c63 fd4d:6169:6c63 TCP 74 80 → 39946 [RST] Seq=855 Win=0 Len=0
18 131.6888 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 [TCP Retransmission] 39946 → 80 [FIN, ACK]
19 131.6888 fd4d:6169:6c63 fd4d:6169:6c63 TCP 74 80 → 39946 [RST] Seq=855 Win=0 Len=0
20 132.5208 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 [TCP Retransmission] 39946 → 80 [FIN, ACK]
21 132.5209 fd4d:6169:6c63 fd4d:6169:6c63 TCP 74 80 → 39946 [RST] Seq=855 Win=0 Len=0
22 134.1847 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 [TCP Retransmission] 39946 → 80 [FIN, ACK]
23 134.1850 fd4d:6169:6c63 fd4d:6169:6c63 TCP 74 80 → 39946 [RST] Seq=855 Win=0 Len=0
24 137.5129 fd4d:6169:6c63 fd4d:6169:6c63 TCP 86 [TCP Retransmission] 39946 → 80 [FIN, ACK]
25 137.5131 fd4d:6169:6c63 fd4d:6169:6c63 TCP 74 80 → 39946 [RST] Seq=855 Win=0 Len=0
Результаты Termshark при выполнении curl <myserver.com> 80
на моем компьютере:
No. - Time - Source - Destination - Protocol - Length - Info -
1 0.000000 170.78.36.7 172.22.1.254 TCP 66 62787 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=
2 0.000063 172.22.1.254 170.78.36.7 TCP 66 80 → 62787 [SYN, ACK] Seq=0 Ack=1 Win=64240
3 0.007119 170.78.36.7 172.22.1.254 TCP 54 62787 → 80 [ACK] Seq=1 Ack=1 Win=131840 Len
4 0.009563 170.78.36.7 172.22.1.254 HTTP 133 GET / HTTP/1.1
5 0.009628 172.22.1.254 170.78.36.7 TCP 54 80 → 62787 [ACK] Seq=1 Ack=80 Win=64256 Len
6 0.009884 172.22.1.254 170.78.36.7 TCP 292 HTTP/1.1 200 OK [TCP segment of a reassemb
7 0.010001 172.22.1.254 170.78.36.7 HTTP 669 HTTP/1.1 200 OK (text/html)
8 0.019889 170.78.36.7 172.22.1.254 TCP 54 62787 → 80 [ACK] Seq=80 Ack=854 Win=130816
9 0.039001 170.78.36.7 172.22.1.254 TCP 54 62787 → 80 [FIN, ACK] Seq=80 Ack=854 Win=13
10 0.039211 172.22.1.254 170.78.36.7 TCP 54 80 → 62787 [FIN, ACK] Seq=854 Ack=81 Win=64
11 0.046453 170.78.36.7 172.22.1.254 TCP 54 62787 → 80 [ACK] Seq=81 Ack=855 Win=130816
Будьте осторожны, что с некоторыми брандмауэрами Docker добавляет специфические правила для правильной работы. Я не уверен, связано ли это также с UFW, но может быть.
Когда это произошло со мной с Iptables, мне пришлось добавить некоторые правила для перенаправления входящего соединения на конкретном порту к конкретному порту моего сервиса в сети Docker. Так что если я получаю соединение на порту 80, но мой контейнеризованный сервис открывает порт 8080, в некоторых случаях, даже если вы указываете отображение: “80:8080”, все равно необходимо добавить некоторые правила перенаправления к вашему брандмауэру.
Еще одна вещь, которую вы можете проверить дважды, это сможет ли хост-сервер “позвонить” самому себе.
Одна команда, которая может помочь вам в диагностике,:
curl -Ivvv host port
Я изменил область моего теста на простой VPS-сервер с установленным NGinx, без Docker, и проблема таймаута http сохранялась, так что… я выяснил, что проблема была вызвана инфраструктурой моего локального провайдера VPS…
Я сменил своего провайдера на другого, и все заработало отлично…
Ответ или решение
Решение проблем с тайм-аутами HTTP в Docker при использовании сетевого моста
Введение
Отказ в соединениях и тайм-ауты HTTP в контейнерах Docker на сервере могут возникать по различным причинам, даже если порты в брандмауэре открыты. В данном анализе мы рассмотрим ситуацию, когда вы пытаетесь установить Mailcow на чистый образ Ubuntu 20.04 и сталкиваетесь с тайм-аутами, несмотря на открытые порты в UFW. Вы будете наглядно изучать все шаги, от настройки Docker до изучения вариантов возникновения проблемы.
Конфигурация системы
Ваша конфигурация системы включает следующие элементы:
-
Установка и настройка UFW:
sudo ufw default allow outgoing sudo ufw default deny incoming sudo ufw limit ssh sudo ufw allow ssh sudo ufw allow http sudo ufw allow https sudo ufw allow smtp sudo ufw allow submission sudo ufw allow pop3 sudo ufw allow pop3s sudo ufw allow imap2 sudo ufw allow imaps sudo ufw allow 4190/tcp sudo ufw allow 8080/tcp sudo systemctl enable ufw sudo ufw enable
-
Настройка Docker с поддержкой IPv6:
{ "ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64" }
-
Создание docker-compose файла:
version: '2.1' services: S2: image: nginx:latest ports: - 80:80 restart: always networks: n1: ipv4_address: 172.22.1.254 aliases: - s2 S3: image: nginx:latest ports: - 8080:80 restart: always networks: n1: ipv4_address: 172.22.1.248 aliases: - s3 networks: n1: driver: bridge driver_opts: com.docker.network.bridge.name: n1 enable_ipv6: true ipam: driver: default config: - subnet: 172.22.1.0/24 - subnet: fd4d:6169:6c63:6f77::/64
Проблемы с подключением и их диагностика
При попытке подключения к Nginx, запущенному в контейнере Docker, вы столкнулись со следующими проблемами:
-
Локальный хост:
curl localhost 80 curl: (28) Failed to connect to 80 port 80: Connection timed out
-
С удаленного компьютера:
curl <myservername.com> 80 curl: (7) Failed to connect to 0.0.0.80 port 80 after 0 ms: Network unreachable
Варианты решения:
-
Проблемы с маршрутизацией или сетевыми настройками:
Иногда конфигурация сети Docker может мешать установлению соединений. Убедитесь, что пакеты направляются должным образом в соответствии с правилами маршрутизации. -
Проблемы с конфигурацией iptables:
Docker автоматически добавляет правила в iptables для управления трафиком. Ваша конфигурация UFW может конфликтовать с этими правилами. Проверьте с помощью команды:sudo iptables -L -n -v
Возможно, вам потребуется добавить правила для пересылки трафика.
-
Проверка состояния UFW:
Убедитесь, что UFW действительно позволяет входящие соединения на порты 80 и 8080. Проверьте это командой:sudo ufw status verbose
-
Использование инструментов диагностики:
Для более детальной диагностики используйте команды:curl -Ivvv localhost:80 curl -Ivvv <myservername.com>:80
-
Проверка работы на другом VPS:
Вы упомянули, что проблема исчезла при смене хостинг-провайдера. Это могло быть связано с сетевой инфраструктурой вашего предыдущего провайдера. Всегда полезно проверить ваше приложение на другом сервере, чтобы исключить влияние оборудования или сетевой конфигурации.
Заключение
Сложности с HTTP тайм-аутами в Docker могут быть вызваны множеством факторов — от конфигурации брандмауэра до особенностей сетевого окружения. Важно систематически проверять каждую часть конфигурации и использовать доступные инструменты для диагностики. Ваш переход на другого поставщика хостинга продемонстрировал, как инфраструктура может влиять на работоспособность приложения. При внедрении решений всегда учитывайте все детали, чтобы избежать повторения подобных проблем.