proxy nginx do docker com poste.io mailserver

1

Eu queria saber se é possível, e em caso afirmativo, como eu conseguiria executar ambos nginx-proxy e poste.io mailserver em um servidor dedicado?

Eu posso rodar os dois separadamente, mas quando tento rodar os dois ao mesmo tempo, digo que não posso rodar o último container porque a porta 443 já está sendo usada pelo outro.

Agora, quando eu uso apenas meu proxy reverso nginx, faço isso para executar vários sites no meu servidor, todos expõem as portas 80 e 443 junto com o próprio proxy, o que me confundiu porque não consigo executar outro container fazendo o mesmo (Sim, eu sei que normalmente 2 processos não devem poder usar a mesma porta sem mexer um pouco).

Eu uso o seguinte proxy: link

Eu uso o link para meu servidor de e-mail

e este é um exemplo de um dos meus sites docker-compose que eu executo no meu servidor.

application:
build: code
volumes:
    - /websites/domain:/var/www/laravel
    - /docker/webs/domain/logs:/var/www/laravel/storage/logs
tty: true
redis:
    image: redis:alpine
db:
    image: mariadb:10.2
    environment:
        MYSQL_ROOT_PASSWORD: toor
        MYSQL_DATABASE: laravel
        TEST_DB_NAME: laravel_test
        MYSQL_USER: laravel
        MYSQL_PASSWORD: laravel
php:
    build: php7-fpm
    volumes_from:
        - application
    links:
        - db
        - redis
nginx:
    build: nginx
    links:
        - php
    volumes_from:
        - application
        - nginx-proxy
    volumes:
        - ./logs/nginx/:/var/log/nginx
    environment:
        - VIRTUAL_HOST=www.domain.com

Dentro do Dockerfile do meu nginx, eu exponho as portas 80 e 443

FROM debian:jessie

MAINTAINER Purinda Gunasekara <[email protected]>

RUN apt-get update && apt-get install -y \
    nginx

ADD nginx.conf /etc/nginx/

ADD *.conf /etc/nginx/sites-enabled/

RUN rm /etc/nginx/sites-enabled/default
RUN rm /etc/nginx/sites-enabled/nginx.conf

# remove the https for local development
#RUN rm /etc/nginx/sites-enabled/*.ssl.conf

RUN echo "upstream php-upstream { server php:9000; }" > 
/etc/nginx/conf.d/upstream.conf

RUN usermod -u 1000 www-data

CMD ["nginx"]

EXPOSE 80
EXPOSE 443

Então é isso que está me deixando confuso. Por que o docker permite que meu site seja executado (mesmo que o proxy nginx já esteja em execução nas portas 80 e 443) sem problemas. Mas quando eu tento rodar meu servidor de e-mail, ele está dizendo que a porta 443 já está em uso?

Aqui está o erro real postado pelo docker

docker: Error response from daemon: 
  driver failed programming external connectivity on endpoint 
  nginx_proxy <containerID>: Bind for 0.0.0.0:443 failed: port is already allocated.

Idealmente, eu seria capaz de executar este servidor de e-mail e meus sites em um servidor, isso porque há apenas uma pequena mão cheia de sites que serão hospedados e nenhum deles deve crescer muito em um curto período de tempo. tempo.

ATUALIZADO

Os sites usam volumes do nginx-proxy e, portanto, eles podem ser executados ao lado dele enquanto expõem as portas 80 e 443, mas quando eu tentei vincular o mesmo volume do nginx-proxy ao servidor de e-mails, continuei recebendo mesmo erro das portas que estão sendo usadas.

    
por killstreet 14.08.2018 / 19:21

1 resposta

4

Se um contêiner do estivador já se vincular à porta 443 em um dos IPs de suas interfaces (ou 0.0.0.0 significando todas as interfaces), outros contêineres do docker não poderão se vincular ao mesmo IP. Verifique com o netstat, enquanto um contêiner 1 está ativo:

sudo netstat -nalp64 | grep 443
tcp     0    0    0.0.0.0:443     0.0.0.0:*    LISTEN     26547/docker-proxy

Como a porta 443 em 0.0.0.0 já é usada por um contêiner do docker, novos contêineres não podem ser vinculados a esse IP + Porta.

Visualização

  0.0.0.0:443   (Error: Port 443 already in use)
        |               \
+--------------+    +--------------+
|  CONTAINER   |    |  CONTAINER   |
|   172.0.0.2  |    |   172.0.0.3  |
+--------------+    +--------------+

Em vez de vincular vários contêineres à mesma Porta, você precisa de uma vinculação de software à porta, redirecionando as conexões para o contêiner apropriado.

Isso é feito com mais facilidade através da execução de um proxy reverso dedicado, que é o único programa vinculado à porta (443). O propósito do proxy reverso é encaminhar as conexões de entrada com base no host HTTP solicitado.

O proxy reverso pode ser executado no host físico executando a janela de encaixe ou dentro de um contêiner docker.

O proxy reverso também pode finalizar conexões SSL, o que significa que essa instância nginx manipula todos os en / descriptografia de / para clientes, enquanto as conexões para o backend (containers) não são criptografadas.

Eu não acho que isso seja estritamente necessário, os navegadores modernos suportam SNI, então o nginx ainda pode encaminhar solicitações para o back-end apropriado sem descriptografar todo o tráfego. Mas, usando uma terminação SSL central, você só precisa de certificados em um local e o SSL só precisa ser configurado uma vez globalmente para a maioria dos casos de uso.

Para configurar tal proxy reverso com terminação SSL

  • Instale o nginx (proxy reverso) no host do docker
  • Definir IPs estáticos ou Hostnames para contêineres
  • Disponibilizar os arquivos SSL Certificate + Private Key dos contêineres para o proxy reverso nginx
  • Defina nginx upstreams para seus contêineres do Docker dentro da configuração de proxy reverso
  • Defina servidores nginx ("vhosts") para exibir nomes de domínio definidos por server_name
  • Encaminhar solicitações para upstreams definidas em location usando proxy_pass

Exemplo:

Meu /etc/nginx/sites-enabled/dockerproxy é assim:

# gitlab
upstream gitlab
{
    server 172.20.0.2;
}

# docker registry
upstream registry
{
    server 172.20.0.3:5050;
}

# dev.mycompany.org
server
{
    listen 10.10.10.40:80 default;
    listen 10.10.10.40:443 ssl default;
    server_name dev.mycompany.org;

    ssl_certificate         /data/run/certbot/data/live/dev.mycompany.org/fullchain.pem;
    ssl_certificate_key     /data/run/certbot/data/live/dev.mycompany.org/privkey.pem;

    location /
    {
        proxy_pass http://gitlab/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# registry.mycompany.org
server
{
    listen 10.10.10.40:443 ssl;
    server_name registry.mycompany.org;

    ssl_certificate         /data/run/certbot/data/live/registry.mycompany.org/fullchain.pem;
    ssl_certificate_key     /data/run/certbot/data/live/registry.mycompany.org/privkey.pem;
    ssl_session_cache       builtin:1000 shared:SSL:60m;
    ssl_session_timeout     60m;

    client_max_body_size 0;
    chunked_transfer_encoding on;

    location /
    {
        proxy_pass http://registry/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Observe que as diretivas proxy_set_header estritamente não são necessárias, elas dependem do que os aplicativos de back-end individuais esperam.

Como você pode ver, esta configuração diz ao nginx para:

  • Vincular a 10.10.10.40:443
  • Solicitações de proxy para dev.mycompany.org para 172.20.0.2 [: 80] (IP do contêiner do gitlab)
  • Solicitações de proxy para registry.mycompany.org para 172.20.0.3:5050 (IP do contêiner de registro)
  • Encerrar o SSL usando os arquivos de certificado fornecidos (diretamente de um contêiner do certbot, no meu caso)

Visualização

           0.0.0.0:443
                |
    +-----------------------+
    |       nginx           |
    +-----------------------+
        |               |
+--------------+    +--------------+
|   VHOST      |    |   VHOST      |
| web.app1.com |    | web.app2.com |
+--------------+    +--------------+
        |               |
+--------------+    +--------------+
|  CONTAINER   |    |  CONTAINER   |
|   172.0.0.2  |    |   172.0.0.3  |
+--------------+    +--------------+

Definindo outros objetos upstream e server usando diferentes diretivas server_name , você pode disponibilizar outros Serviços HTTP (S) usando a mesma Interface IP + Porta.

Observe que a diretiva listen 10.10.10.40:443 é usada várias vezes na configuração do nginx. Isso é possível porque o nginx apenas se vincula a esse IP uma vez e, em seguida, analisa o cabeçalho Host nas solicitações dos clientes para determinar qual server (vhost) atenderá a essa solicitação.

Minha configuração usa IPs estáticos na definição upstream , mas você também pode usar nomes de host de contêineres, apenas certifique-se de que eles sejam conhecidos de antemão (definidos no docker-compose, consulte link ) e resolvível pelo nginx.

E, por último, não mapeie os Portos dos contêineres / serviços para as Portas do Host! Eles não precisam estar disponíveis para o mundo exterior, apenas o nginx precisa acessá-los.

    
por 17.08.2018 / 10:38