Configurar Reverse-Proxy com Docker + Traefik + Nginx + PHP + MySQL + Mosquitto + phpMyAdmin + Basic Authentication

Este artigo serve para explicar como fazer um sub-domínio apontar para um determinado container de uma forma simples e eficiente. Eu estou a escrevê-lo, porque me deparei com uma série de dificuldades quando o tentei fazer.

Por exemplo, eu usava algo como: https://example.org (web), https://example.org:8080 (phpMyAdmin), wss://example.org:1884 (mosquitto), etc. O meu objectivo era simplificar e passar a usar algo como: https://example.org (web), https://pma.example.org (phpMyAdmin), wss://example.org/mqtt (mosquitto), etc.

Ou seja, para além de apontar um subdomínio para um determinado container, eu também queria usar a mesma porta para protocolos diferentes.

Foi então que eu descobri o Traefik. Para além de satisfazer as minhas necessidades de uma forma muito simples, também gera os certificados SSL para todos os domínios/subdomínios necessários.

Para que tudo funcione como expectável, só precisamos dos ficheiros que se seguem, sendo apenas necessário alterar o e-mail, domínio e sub-domínios nos ficheiros traefik.toml e docker-compose.yml.

acme.json

touch acme.json
sudo chmod 600 acme.json

nginx.conf

server {
listen 80;
listen [::]:80;

mosquitto.conf

# Config file for mosquitto
#
# See mosquitto.conf(5) for more information.
#
# Default values are shown, uncomment to change.
#
# Use the # character to indicate a comment, but only if it is the
# very first character on the line.

traefik.toml

defaultEntryPoints = ["http", "https"]

docker-compose.yml

version: "3"

networks:
proxy:
external: true
internal:

services:
traefik:
container_name: traefik
image: traefik:1.7.4-alpine
restart: always
depends_on:
- web
- mqtt
command: --docker
ports:
- 80:80
- 443:443
labels:
- traefik.backend=traefik
- traefik.frontend.rule=Host:monitor.example.org
- traefik.port=8080
networks:
- proxy
- internal
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- $PWD/traefik.toml:/traefik.toml
- $PWD/acme.json:/acme.json

web:
container_name: web
image: nginx:1.15.7-alpine
restart: always
labels:
- traefik.backend=web
- traefik.frontend.rule=Host:example.org
- traefik.port=80
networks:
- internal
depends_on:
- php
- database
volumes:
- $PWD/nginx.conf:/etc/nginx/conf.d/default.conf
- $PWD/app:/usr/share/nginx/html

database:
container_name: database
image: mariadb:10.4.0
restart: always
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_USER=user
- MYSQL_PASSWORD=user
networks:
- internal
labels:
- traefik.enable=false

phpmyadmin:
container_name: phpmyadmin
image: phpmyadmin/phpmyadmin
restart: always
depends_on:
- database
labels:
- traefik.backend=phpmyadmin
- traefik.frontend.rule=Host:pma.example.org
- traefik.port=80
networks:
- internal
environment:
- PMA_ARBITRARY=1
- PMA_HOST=database
- PMA_PORT=3306
volumes:
- /sessions

php:
container_name: php
image: php:7.3-fpm-alpine
restart: always
networks:
- internal
labels:
- traefik.enable=false
volumes:
- $PWD/app:/var/www/html

mqtt:
container_name: mqtt
image: eclipse-mosquitto:1.4.12
restart: always
networks:
- internal
labels:
- traefik.backend=mqtt
- traefik.frontend.rule=Host:example.org;PathPrefix:/mqtt
- traefik.port=9001
- traefik.protocol=ws
volumes:
- $PWD/mosquitto.conf:/mosquitto/config/mosquitto.conf
- $PWD/mosquitto/data:/mosquitto/data
- $PWD/mosquitto/log:/mosquitto/log

app/index.php

<?php echo 'Olá!' ?>

Após a criação destes ficheiros, basta executar o comando:

docker-compose up -d

Agora ao aceder ao URL configurado irás receber a mensagem “Olá!”. Também poderás usar o URL configurado no container do Traefik para verificar o estado atual dos teus containers.

Para experimentar os Mosquitto, apenas necessitas de usar um cliente MQTT (por exemplo MQTT.js), subscrever um tópico e publicar qualquer coisa para esse mesmo tópico, por exemplo:

mqtt sub -t 'teste' -h 'example.org/mqtt' -v

Basic Authentication

Se quiseres adicionar uma camada extra de segurança à tua aplicação, apenas precisas de adicionar o seguinte ao teu ficheiro traefik.toml:

[entryPoints.https.auth.basic]
users = ["user:password"]

traefik.toml

defaultEntryPoints = ["http", "https"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[entryPoints.https.auth.basic]
users = ["user:password"]
[web]
address = ":8080"
[acme]
email = "email@example.org"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
[[acme.domais]]
main = "example.org"
sans = ["monitor.example.org", "pma.example.org"]

As passwords podem ser codificadas em MD5, SHA1 e BCrypt: podes usar o htpasswd para gerá-las. (Ex. http://www.htaccesstools.com/htpasswd-generator/)

MQTT

mqtt sub -t 'teste' -h 'user:password@example.org/mqtt' -v
mqtt pub -t 'teste' -h 'user:password@example.org/mqtt' -m 'Olá!'

Full Stack Web Developer

Full Stack Web Developer