Hello,
Pour faire suite au tuto récent sur ADWIREGUARD où j'utilisais NPM une petite explication sur ce dernier en docker avec un docker network qui permet de se passer des ports published pour les webui, et de taper sur le nom du container plutôt qu'une ip qui peut changer au reboot blabla...

En partant du principe que ton OS c'est Debian, que docker est déjà installé et que ton utilisateur peut taper les commandes docker voici un truc simple et rapide !

On commence par créer le docker network :

docker network create npm-proxy

retiens le nom de ce network, on s'en servira à chaque fois et bien évidemment tu peux le nommer comme tu le sens du moment que tu t'en rappellera plus tard 😅.

Une fois ce network crée, tu devrais avoir ceci :

Voilà une base, passons au lancement de NPM en docker cli ( je n'utiliserais pas docker compose ici ).

On va commencer par préparer 2 dossiers dans notre dossier docker, chaque container que je lance qui a besoin de configs sont rangé chez moi dans {$HOME}/docker/nomducontainer/{config,data,etc}.
Ce qui me permet de faire une archive et de la déplacer ou de la sauvegarder aisément pour pouvoir relancer rapidement.

mkdir -p {$HOME}/docker/npm/{data,letsencrypt}

Ici on a besoin de 2 dossiers : un data pour la config etc et un letsencrypt pour les certificats ssl ( facilement importable le coup ).

docker run -d --name npm --network npm-proxy -p 80:80 -p 81:81 -p 443:443 --restart unless-stopped -v /home/ubuntu/docker/npm/data:/data -v /home/ubuntu/docker/npm/letsencrypt:/etc/letsencrypt jc21/nginx-proxy-manager

Petites explications :

  • ce sera le seul container dont on publiera les ports essentiels pour un serveur web : 80 et 443.
  • le 81 sera effacé après parce qu'on en aura plus besoin.
  • --name npm : nom du container
  • --network npm-proxy : le network sur lequel on attachera chaque container, ce qui permettra à npm d'accéder à ces derniers sans avoir à ouvrir de port ou de gymnastique tel 127.0.0.1:8080:8080 par exemple.
  • --restart unless-stopped : la base hein après tu met ce que tu veut xD
  • pour les 2 volumes, ici mon user c'est ubuntu ( sur une distrib debian 🤣 ) donc je serais dans /home/ubuntu/docker.

Et ici j'utilise l'image de jc21 par habitude et parce que celle de lesage ne supportait pas l'ipv6 au début.

Tadaaa :

On a quelques trucs à faire, mais avant tout petit passage par notre registrar pour la zone dns, ou par son serveur dns si vous êtes maitre de ce dernier 😉
Un petit record A ( + AAAA si t'es ipv6 addict ) pour npm.ndd.tld par exemple et pendant que ça se propage on va préparer npm.
On se rend donc sur http://IP;81 pour accéder à la page d'admin.

Les logins par défaut sont :

login : admin@example.com
pass : changeme

La première chose qu'il va nous proposer c'est de changer ces infos là :

Donc Fullname, nickname pour la forme, le plus important c'est le mail qui sert de login.
Et puis on change le mot de passe hein !

Alors où t'es un psychopathe comme Greg, tu génères un mot de passe de 128 caractères pour la forme ou bien pour te rappeler une chose tu mets : raidisnotbackup XD.
Maintenant qu'on a notre utilisateur admin, on se rend dans Hosts -> Proxy Hosts

Et on va ajouter notre premier truc pour accéder à l'interface de npm, avec un beau npm.ndd.tld et pouvoir supprimer le port 81 de l'équation.

Donc domain names on met npm.ndd.tld en accordance avec le record fait précédemment sur notre zone dns, scheme http, forward host npm et le port 81.

A chaque container qu'on ajoutera le nom ira dans forward host et le port est celui qui normalement est publié pour accéder à la webui mais je te montre avec un exemple concret après ( Portainer ).
Pour les 3 options, cache assets, permet de mettre en cache certaines choses entre le reverse proxy et le container on gagne souvent en réactivité, block common exploits embarque une config direct pour bloquer rapidement les bots etc en général, c'est pas sur à 100% mais ca couvre les trucs de base et le websocket support toujours utile 😉

Direction l'onglet SSL pour y générer un certificat SSL.

Ici on à 2 choix, ou bien on fait une requête ssl pour chaque fqdn, donc tu utilises les infos de base mail + accept et chaque hostname aura sont certificat ou bien tu connais un peu et tu fais un requête pour un certificat wildcard en utilisant le dns challenge qui te permet d'utiliser plein de provider ( cloudflare, gandi, powerdns...)
Je n'aborderais pas le sujet ici.

On fera donc une requête classique, avec HTTP2 support et force ssl.
Le HSTS est aussi quelques chose a ne cocher que si on maitrise 😉
On clique sur SAVE, on attend et hop nous voila avec notre premier proxy host.

On peut cliquer sur l'encadré vert et accéder directement a l'url renseignée et édit en cliquant à droite.

Nous voilà donc avec ce premier truc qui va nous permettre de faire sauter le port 81 et de n'exposer que 80 et 443 ( voire même uniquement le 443 selon les besoins ).

Et si on faisait un exemple concret, on va installer Portainer, si on suit la doc ca se passe en 2 étapes :

  1. création des volumes
  2. docker run

C'est parti !

docker volume create portainer_data

Après tu peux en soi, binder un dossier directement sur l'hôte donc tu fais bien comme tu le sens xD
Une fois le volume crée la doc nous donne ça :

docker run -d -p 8000:8000 -p 9000:9000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
  • -p 8000:8000 : portainer-agent ( à moins d'en avoir besoin, pas utile )
  • -p 9000:9000 : webui http
  • -p 9443:9443: webui https

On va le corriger :

docker run -d --network npm-proxy --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

On remplace donc le -p 8000:8000 -p 9443:9443 -p 9000:9000 par un --network npm-proxy et avant la même procédure que précédemment :
Hosts -> Proxy hosts -> Add Proxy hosts ( en haut a droite )
On remplit le fqdn donc par exemple portainer.ndd.tld, scheme http, forward host c'est ... voyons voir si tu suis ?! le nom du container donc ici portainer et le port on va prendre le 9000 pas besoin du https selfsigned

On coche bien les 3 options : cache assets, bloc common exploits et websocket puis direction l'onget SSL.
On sélectionne Request new ssl certificate on coche http2, force ssl, on rentre le mail, et on accepte les règles de LE puis on save on laisse tourner et BOOOM !

Dernière petite manip on va viré le port 81 de npm.

docker stop npm
docker rm npm

Donc on le stoppe, on l'efface ( pas d'inquiétude si tu le relances avec les mêmes dossiers de configs : tu ne perds rien ! ) et puis on relance la commande qu'on a lancée au début mais corrigé :

docker run -d --name npm --network npm-proxy -p 80:80 -p 443:443 --restart unless-stopped -v /home/ubuntu/docker/npm/data:/data -v /home/ubuntu/docker/npm/letsencrypt:/etc/letsencrypt jc21/nginx-proxy-manager

et hop nous revoila online, avec un NPM qui n'ecoute seulement sur 80 et 443, portainer accessible sans avoir eu des ports exposés, pas de gymnastique a coup de 127.0.0.1:9000:9000 bla bla

Prochaine écriture : découverte des ACL avec NPM pour "sécuriser" un peu le truc.

Si t'a des questions, des suggestions, des idées je te laisse m'en faire part soit dessous ce post sinon --> discord 😃

On peut également bloquer toutes les connexions entrantes sauf les ports 80/443
en contournant Docker qu'y s'immisce dans iptables
https://github.com/chaifeng/ufw-docker

/etc/ufw/after.rules

# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward

-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN

-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12

-A DOCKER-USER -j RETURN

-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP

COMMIT
# END UFW AND DOCKER

Cela permet au réseau public d'accéder à tous les ports publiés dont le port conteneur est 80 :
ufw route allow proto tcp from any to any port 80

2 mois plus tard

Bonjour et merci beaucoup pour se tuto très clair, je me pose tout de même une question peut être con mais j'essaie ^^. Vu que le port des containers et supprimer comment fait npm pour savoir sur quel port écouter pour diffuser le container ensuite ? Et nous même comment fait on pour savoir quel port noté dans npm ? Cette technique fonctionne avec n'importe quel container ? Je pense notamment à adguard home qui et plutôt chiant avec les port demandé.
Merci encore, Cordialement

Tu reportes dans NPM le port utilisé normalement par l'application, exemple 9000 pour Portainer :

proxy

Pour résumer le tuto :
Tu créée normalement le conteneur de l'application et tu testes via ip:port (ex : 127.0.0.1:9000 pour Portainer)
Tu configures le proxy via NPM (voir capture écran)
Tu recréé le conteneur de l'application en retirant le port et en ajoutant le network (npm-proxy dans l'exemple)

NB : les étapes liées au network sont facultatives lors de l'utilisation de docker-compose, car celui créé un network compose_default

Merci pour l'explication sa paraît logique maintenant ^^

Bonjour,
Je reviens avec une nouvelle question ^^. Comme dit plus haut je me posais des questions pour ce tuto sur adguardhome et pas manqué je sèche. J'ai donc mon container adguardhome sur mon dédié et chez moi mon routeur sous openwrt qui me demande donc comme dns une adresse IP avec ou sans port mais du coup si je ferme mes port + adresse IP cela ne fonctionne plus. Quelqu'un à eu le problème ? Ou pour cette exception il faut laisser les ports ouverts ?
Cordialement

Si tu accédais via IP:port, tu configures ce port dans NPM et tu accèdera à Adguard via adguard.ndd.tld par exemple
(ce sous-domaine doit être préalablement configuré au niveau de la zone DNS)

    spider1163 Merci beaucoup pour l'aide. Oui c'est se que j'avais en tête mais pour l'instant mes essais ne sont pas très concluant. Je regarderai plus en détail ce weekend. Merci encore

    9 mois plus tard

    Pourtant ça marche bien ici sur un rpi4 et une autre machine.
    Tu le lance de quelle manière ? cli ou compose ?

      je le lance comme cela MattProd

      docker run -dt --network npm-proxy --name=rutorrent --restart always -v /home/diesel/docker/rutorrent:/config -v /home/diesel/mnt/torrent:/data/downloads -v /home/diesel/mnt/sourcetorrents/PreSeries:/data/.watch -v /home/diesel/docker/rutorrentseries/session:/data/.session mondedie/rutorrent:latest

      dns cloudfare en dns only mai erreur 502

      edit : probleme resolu je le lancer en port 8081 au lieu de 8080

        Diesel tu devrais ajouter quand même : -p 45000:45000 pour le port torrent 😅

        2 mois plus tard

        Bonjour voulant mettre a jour l'image mondedie/rutorrent je n'arrive plus a acceder a celle ci avec npm

        je lance :

        docker run -dt --network npm-proxy --name=rutorrent \
         -p 45000:45000 -p 8081:8081 --restart always \
         -v /home/diesel/docker/rutorrent:/config \
         -v /home/diesel/mnt/torrent:/data/downloads \
         -v /home/diesel/mnt/sourcetorrents/PreSeries:/data/.watch \
         -v /home/diesel/docker/rutorrentseries/session:/data/.session \
        mondedie/rutorrent:latest

        dans mon npm j'ai :

        si je le lance via 8080:8080 il ne se lance pas car crowdsec utilise déjà ce port
        et quand je vais sur le seedbox.tld.com de NPM j'ai une erreur 502
        obligé de l'ip en entier mettre pour accéder j'avais eu le même soucis mai je ne sais plus comment on la résolu

        Hello @Diesel

        Alors :
        1) si tu met rutorrent derrière NPM tu peux éviter de publier le port de la WebUI, seulement le 45000/tcp.
        2) si tu met 8081:8081 on ira nulle part dans le container c'est 8080 donc au pire tu fais un -p8081:8080.
        3) si tu lances ton container avec pour nom rutorrent alors dans NPM tu dois appeler http://rutorrent:8080

        Donc pour rappel, à moins de vouloir y'a accéder par IP😛ORT si on met un container dans le network NPM / Traefik / Zoraxy etc on a pas besoin de publier le port pour l'accès à la webui. Seulement les ports qui ont besoin de communiquer depuis l'extérieur.
        Par exemple : rutorrent on a besoin d'un port 45000/tcp, wireguard 51820/udp etc

        Matt

          MattProd

          docker run -dt --network npm-proxy --name=seedbox -p 45000:45000 -p 8080:8081 --restart always -v /home/diesel/docker/rutorrent:/config -v /home/diesel/mnt/torrent:/data/downloads -v /home/diesel/mnt/sourcetorrents/PreSeries:/data/.watch -v /home/diesel/docker/rutorrentseries/session:/data/.session mondedie/rutorrent:latest
          4af2f6915e3fd762b18fa117a99a0f665ad3c2ab69de27b79a623b3b2a75919b
          docker: Error response from daemon: driver failed programming external connectivity on endpoint seedbox (c1385e2f6370410d612598f91db3bffd8f668637fd44797a0e8c1bdb5b5194e4): Error starting userland proxy: listen tcp4 0.0.0.0:8080: bind: address already in use.

          vue que crowdsec tourne aussi sur le serveur dedie en 8080....

            Diesel
            -p8080:8081 -> -p exterieur:intérieur -> donc oui ca va être bloquant... Cependant comme indiqué dans mon message précedant : -p8081:8080 devrait fonctionner.
            Je le redis aussi : pas besoin d'exposer le port de la webui si le container est dans le network de NPM:

            docker run -dt --name=seedbox \
             -p 45000:45000 \
             -v /home/diesel/docker/rutorrent:/config \
             -v /home/diesel/mnt/torrent:/data/downloads \
             -v /home/diesel/mnt/sourcetorrents/PreSeries:/data/.watch \
             -v /home/diesel/docker/rutorrentseries/session:/data/.session \
             --restart always \
            --network npm-proxy \
            mondedie/rutorrent:latest

            devrait être fonctionnel...

            Matt

              MattProd

              je l'ai lancer 8081:8080
              et c'est nikel
              merci MattProd
              et donc si je met seedbox et port 45000 dans npm ca fonctionnera meme si je le lance sans port ?