{{indexmenu_n>20}}
# Rendre un service accessible publiquement
## Préambule
Quand un conteneur Docker doit être accessible depuis l'extérieur de la machine, il y a deux solutions :
* Mapper un port de l'hôte sur un port du conteneur
* Utiliser [[technique:tech_team:traefik|Traefik]]
La règle générale est la suivante : on utilise un mapping de port pour les services **non-web** (*e.g.* LDAP, mail, SFTP...) et Traefik pour tous les services web. Une explication se trouve sur la [[technique:tech_team:traefik|page dédiée à Traefik]].
## Mapping de port
C'est la technique la plus simple. Supposons qu'un conteneur écoute sur son port interne 8080, et qu'on veuille le rendre accessible depuis l'extérieur. On va choisir arbitrairement un port de l'hôte que l'on va mapper dessus, par exemple :
```yaml
services:
example:
image:
ports:
- 2000:8080
```
Dans cet exemple, tout ce qui arrive sur le port `2000` de la machine sera redirigé sur le port `8080` du conteneur.
Par contre, pour tout ce qui concerne la gestion de TLS ou d'autres fonctionnalités de Traefik, on n'en profite pas, car on ne passe pas du tout par lui.
## Utiliser Traefik
Pour les services web, on préfère largement passer par Traefik, car on pourra utiliser un port standard (`80` ou `443`) et profiter de toutes ses fonctionnalités (HTTPS automatique, etc).
On configure le fait de router vers un conteneur grâce aux [labels Docker](https://docs.docker.com/config/labels-custom-metadata/). Voici un extrait commenté permettant de router toutes les requêtes arrivant sur Traefik à destination de `app.picasoft.net` vers le conteneur `exemple`, sur son port `8080` :
```yaml
networks:
proxy:
external: true
services:
exemple:
container_name: example
networks:
- proxy
labels:
# Traefik va prendre ce conteneur en compte
traefik.enable: true
# websecure correspond au port 443 de la machine (config Traefik)
# Remplacer par le nom du conteneur
traefik.http.routers..entrypoints: websecure
# Il redirigera vers ce port, exposé par le conteneur
# Remplacer par le nom du conteneur
# Remplacer app.picasoft.net par l'URL souhaitée
traefik.http.routers..rule: Host(`app.picasoft.net`)
# Lorsque l'utilisateur consulte cette URL
# Remplacer par le nom du conteneur
# Remplacer 8080 par le port du service
traefik.http.services..loadbalancer.server.port: 8080
```
Il est essentiel que le conteneur soit dans le même réseau que Traefik, qui est fixé à `proxy` ! C'est le sens des directives `networks`.
`websecure` désigne, dans la configuration Traefik, le port 443. Tout ce qui arrive vers Traefik est redirigé vers cet entrypoint, il faut donc se coller dessus.
Il est possible d'être plus fin sur l'URL à laquelle répondra le conteneur, et même d'utiliser des chemins spécifiques ou des expressions régulières. Voir [la documentation officielle](https://doc.traefik.io/traefik/v2.0/routing/routers/#rule).
## Sécuriser une sous-partie du service par authentification
Il y a pas mal de cas d'utilisation où une sous-partie d'un site doit être sécurisée par authentification :
- La partie `/admin` d'un service exposé sur internet mais sans authentification intégrée au service
- La partie `/metrics` d'un service qui doit être accessible à [[technique:adminsys:monitoring:metrologie:victoriametrics|la solution de monitoring]] mais pas aux internautes...
La solution consiste à créer un second point d'entrée à l'aide des labels. En reprenant l'exemple de la section précédente, on rajouterait ces labels :
```yaml
# Toujours le même point d'entrée : HTTPS
traefik.http.routers.-metrics.entrypoints: websecure
# Ce point d'entrée sera sélectionné uniquement pour les requêtes
# vers app.picasoft.net/metrics et ses dérivés.
traefik.http.routers.-metrics.rule: "Host(`app.picasoft.net`) && PathPrefix(`/metrics`)"
# Indique que ce point d'entrée passe par un middleware nommé -metrics-auth et qui est
# configuré via les labels Docker (voir juste en dessous)
traefik.http.routers.-metrics.middlewares: "-metrics-auth@docker"
# Ce middleware est simplement une authentification, qui vient se mettre entre le point d'entrée
# et l'application.
traefik.http.middlewares.-metrics-auth.basicauth.users: "test:$2y$10$7Gv5tUZC1UBsTyQs/ZTwmu0jamzBJFnNEY4SMxqdfIYfTyLBDTINm"
```
La chaîne `$2y$10$7Gv5tUZC1UBsTyQs/ZTwmu0jamzBJFnNEY4SMxqdfIYfTyLBDTINm` correspond au mot de passe `test` hashé avec [bcrypt](https://fr.wikipedia.org/wiki/Bcrypt).
Pour éviter de versionner la chaîne d'identification, on préfère plutôt utiliser une variable pour le label `basicauth.users`, qui vaudra "${METRICS_AUTH}". La valeur sera placée dans un fichier `.env` sur la machine de production, sous le format suivant :
```
METRICS_AUTH=test:$2y$10$7Gv5tUZC1UBsTyQs/ZTwmu0jamzBJFnNEY4SMxqdfIYfTyLBDTINm
```
En effet, Docker Compose lit les fichiers `.env` et remplace les variables par leur valeur dans le fichier Compose. De plus, Git ignore les fichiers cachés par défaut, on ne risque pas de commiter les secrets par erreur.
Pour générer la chaîne d'authenticiation Basic Auth qui est donnée au label Traefik, on commence par définir un nom d'utilisateur (ici ''test'') et par générer un mot de passe (par exemple avec ''pwgen -sB 64''). On place ces identifiants dans le [[asso:tuto:vaultwarden|vaultwarden]].
On utilise ensuite la commande suivante pour générer la chaîne d'authentification qu'il faut renseigner dans le label.
```
$ echo $(htpasswd -nb USER PASSWORD)
USER:$apr1$4WpORg/6$.bUMzTnrDPivUXfu7.vvP0
```