Mini-test 5

Ports & services

Reperer qui ecoute, ouvrir un port, comprendre EXPOSE et -p

9 questions ciblees

verification debug redaction docker

Cliquez Voir la solution sur chaque slide

← → naviguer · S solution · M manuel · R recommencer

Question 1 / 9 firewall - ouvrir un port

Ouvrir le port et le verifier

Votre script d'installation doit ouvrir le port 6667 dans le pare-feu Ubuntu, puis verifier que la regle est bien en place.

Donnez 2 commandes differentes qui montrent qui ecoute sur le port 6667 (avec le nom du processus si possible) :

SS(8) - extrait du manuel
NAME
       ss - une autre utilite pour examiner les sockets

SYNOPSIS
       ss [OPTIONS] [FILTRE]

OPTIONS frequentes
       -t        TCP
       -u        UDP
       -l        LISTEN seulement (sockets qui ecoutent)
       -n        pas de resolution (port numerique, pas "ssh")
       -p        afficher le PROCESSUS (sudo requis)
       -a        tous (listening + connectes)

FILTRES de port
       sport = :PORT     port source (cote serveur)
       dport = :PORT     port destination

EXEMPLES
       # Qui ecoute sur quels ports TCP ?
       sudo ss -tlnp

       # Filtrer sur un port precis
       sudo ss -tlnp sport = :6667
       sudo ss -tlnp | grep :6667

SORTIE TYPIQUE
       State  Recv-Q  Local Address:Port  ...
       LISTEN 0       0.0.0.0:6667        ... users:(("ircd-hybrid",pid=4321,fd=5))
LSOF(8) - extrait du manuel
NAME
       lsof - list open files (sockets inclus, sous Linux "tout est fichier")

SYNOPSIS
       lsof [-i [PROTO][@HOST][:PORT]] [-u USER] [+D DIR]

OPTIONS
       -i :PORT          processus qui utilisent ce port
       -i TCP:PORT       limite a TCP
       -i UDP:PORT       limite a UDP
       -u USER           filtrer par utilisateur
       +D DIR            tous les fichiers ouverts dans un dossier
       -p PID            par pid

EXEMPLES
       sudo lsof -i :6667
       sudo lsof -i TCP:80
       sudo lsof -u www-data
       sudo lsof +D /var/log
# La plus moderne (remplace netstat)
sudo ss -tlnp | grep :6667

# Equivalent avec lsof (parfois plus expressif)
sudo lsof -i :6667

# Le classique (encore largement utilise)
sudo netstat -tlnp | grep 6667

Anatomie des switches communs :

Sortie typique : LISTEN ... 0.0.0.0:6667 ... users:(("ircd-hybrid",pid=4321,fd=5))

Question 2 / 9 verifier qui ecoute localement

Qui ecoute sur le port 6667 ?

Apres avoir installe un serveur IRC ircd-hybrid, vous voulez verifier localement sur le serveur que quelque chose ecoute bien sur le port 6667 (IRC).

Donnez une commande qui teste seulement l'ouverture du port (sans envoyer de donnees), et une qui teste la reponse HTTP d'un service web sur le port 80 :

NC(1) - extrait du manuel
NAME
       nc - arbitrary TCP and UDP connections and listens (netcat)

SYNOPSIS
       nc [-zuv] [-w SEC] HOTE PORT

OPTIONS frequentes
       -z        mode "zero I/O" : scan, ne transmet pas de donnees
       -v        verbeux (affiche "succeeded!" ou "refused")
       -u        UDP (defaut : TCP)
       -w SEC    timeout en secondes
       -l        ecouter au lieu de se connecter (faire un serveur)

EXEMPLES
       # Le port repond-il ?
       nc -zv irc.quebec-libre.net 6667

       # Scanner plusieurs ports
       nc -zv serveur.com 20-25

       # Test UDP (ex: DNS port 53)
       nc -zuv serveur.com 53

       # Creer un faux serveur pour test
       nc -l 9999
CURL(1) - extrait du manuel
NAME
       curl - transfer a URL

SYNOPSIS
       curl [OPTIONS] URL

OPTIONS frequentes (debug HTTP)
       -v        verbeux (negociation HTTP/TLS, headers envoyes/recus)
       -I        HEAD seulement (juste les headers)
       -L        suivre les redirections (301, 302)
       -k        accepter les certificats invalides (debug HTTPS)
       -o FILE   sauver la sortie dans un fichier
       -X VERB   methode HTTP (POST, PUT, DELETE)
       -d DATA   corps POST
       -H "X:Y"  ajouter un header

EXEMPLES
       # Tester un site (voir headers + corps)
       curl -v http://example.com

       # Juste les headers
       curl -I https://example.com

       # Suivre les redirections vers HTTPS
       curl -L http://example.com

       # POST JSON
       curl -X POST -H "Content-Type: application/json" \
            -d '{"nom":"test"}' https://api.example.com/v1/users
# Tester juste l'ouverture du port (mode "zero I/O" + verbose)
nc -zv irc.quebec-libre.net 6667
# Sortie : "Connection to irc.quebec-libre.net 6667 port [tcp/*] succeeded!"

# Tester un service web (suit aussi les redirections HTTPS, voir headers)
curl -v http://irc.quebec-libre.net
curl -I https://irc.quebec-libre.net    # juste les headers HEAD

Distinction importante :

Un port ouvert ne signifie pas que le service derriere fonctionne. D'ou l'interet d'avoir les deux couches dans une procedure de verification.

Question 3 / 9 tester depuis un client distant

Le port repond-il depuis l'exterieur ?

Depuis votre poste de developpement, vous voulez tester si le serveur irc.quebec-libre.net repond bien sur le port 6667 sans installer de client IRC.

Donnez :

UFW(8) - extrait du manuel
NAME
       ufw - uncomplicated firewall

SYNOPSIS
       ufw [enable|disable|status|reload]
       ufw default ACTION
       ufw allow|deny|reject REGLE
       ufw delete [REGLE | NUM]

REGLES (forme courte)
       allow 22                        port 22, tcp ET udp
       allow 22/tcp                    port 22, tcp seulement
       allow 6667/tcp
       allow from 192.168.1.0/24
       allow from 1.2.3.4 to any port 22

STATUS
       status                          liste les regles
       status numbered                 avec numeros (utile pour delete)
       status verbose                  avec defaults et logging

COMMANDES utiles
       sudo ufw enable                 activer (attention SSH !)
       sudo ufw disable
       sudo ufw reload
       sudo ufw default deny incoming
       sudo ufw default allow outgoing
       sudo ufw delete 3               efface la regle no 3
       sudo ufw delete allow 6667/tcp

PIEGES classiques
       - ufw doit etre ACTIVE pour appliquer les regles
       - enable sans "allow ssh" prealable = session SSH coupee
       - une regle DENY plus prioritaire bloque silencieusement
# Ouvrir
sudo ufw allow 6667/tcp

# Verifier (avec numeros de regle, utile pour effacer ensuite)
sudo ufw status numbered

# Retirer par numero de regle (vu dans 'status numbered')
sudo ufw delete 3

# Retirer par syntaxe (equivalent au allow inverse)
sudo ufw delete allow 6667/tcp

Pieges classiques :

Question 4 / 9 debug - regrouper par phase

Le port refuse - regrouper les actions par phase

Vous lancez curl http://monsite.example.com depuis un autre poste et obtenez "Connection refused", alors qu'Apache est cense tourner sur le serveur. Vous avez plusieurs actions a faire ; on les regroupe en trois phases. L'ordre entre les actions d'une meme phase est flexible.

Glissez chaque action dans la phase qui convient. Une phase peut contenir plusieurs actions. Cliquez sur une etiquette deposee pour la retirer.

systemctl status apache2
ss -tlnp | grep apache
ufw status numbered
curl -v depuis un client
dig monsite.example.com
Phase 1 - reflexe
la question evidente, locale
Phase 2 - tests locaux
sur le serveur lui-meme
Phase 3 - tests distants
depuis un autre poste / cote reseau

Phase 1 - reflexe (le service tourne-t-il ?)

sudo systemctl status apache2

C'est gratuit, instantane, et 9 fois sur 10 ca repond a la question.

Phase 2 - tests locaux (toujours sur le serveur)

sudo ss -tlnp | grep apache
sudo ufw status numbered

Ecoute-t-il sur la bonne interface ? Y a-t-il un filtrage IP local qui bloque ?

Phase 3 - tests distants (cote reseau)

curl -v http://monsite.example.com   # depuis un autre poste
dig monsite.example.com              # la chaine DNS est-elle OK ?

On a epuise les causes locales. Reste DNS, routage, security group du fournisseur cloud.

L'ordre entre phases est defendable (du moins cher au plus cher). L'ordre a l'interieur d'une phase est libre.

Question 5 / 9 debug - lire le diagnostic

Quel symptome trahit quelle couche ?

Vous avez lance vos verifications. Chaque commande peut retourner une sortie revelant une couche particuliere. Associez chaque extrait de sortie a la couche en panne.

Glissez chaque sortie vers la couche qu'elle revele.

Status: inactive (dead)
LISTEN 127.0.0.1:80
[ 6] DENY 6667/tcp
;; status: SERVFAIL
Couche processus
le service n'est pas demarre
Couche port / interface
il ecoute mais pas la ou il faut
Couche firewall
une regle bloque le paquet
Couche DNS
le nom ne resout pas correctement

Savoir lire la sortie d'une commande de diagnostic = la moitie du debug.

Question 6 / 9 debug - quelle commande fait quoi

Quelle commande teste quelle couche ?

Maintenant qu'on connait les couches et qu'on sait lire les symptomes, on choisit le bon outil pour chaque diagnostic. Associez chaque commande a la question qu'elle repond.

Glissez chaque commande vers la question qu'elle teste.

systemctl status
ss -tlnp
ufw status
dig
Le service tourne-t-il ?
verifier que le process est actif
Ecoute sur quel port / interface ?
voir les sockets en LISTEN
Le pare-feu laisse-t-il passer ?
regles de filtrage IP local
Le DNS pointe-t-il au bon endroit ?
resolution du nom de domaine

La question suivante demande les syntaxes exactes, avec les flags.

Question 7 / 9 debug - le port refuse (syntaxes)

Le port refuse - les 4 commandes exactes

Meme scenario : curl http://monsite.example.com -> "Connection refused", Apache cense tourner sur le serveur. Vous avez identifie les 4 couches dans la question precedente. Maintenant, donnez les commandes exactes pour chacune.

Une ligne par verification (process -> port -> firewall -> DNS) :

SYSTEMCTL(1) - extrait du manuel
NAME
       systemctl - controler le gestionnaire systeme et de services systemd

SYNOPSIS
       systemctl [OPTIONS] COMMANDE [UNITE...]

COMMANDES principales sur les unites (services)
       status SERVICE       etat detaille + extrait des logs recents
       start SERVICE        demarrer
       stop SERVICE         arreter
       restart SERVICE      redemarrer
       reload SERVICE       recharger la config (sans redemarrer)
       enable SERVICE       activer au boot
       disable SERVICE      ne plus activer au boot
       is-active SERVICE    sortie 0 si actif (utile dans un script)
       is-enabled SERVICE   sortie 0 si actif au boot

LISTAGE
       list-units --type=service            services charges
       list-units --type=service --state=failed  services en echec
       list-unit-files --type=service       tous les services connus

LOGS (via journalctl)
       journalctl -u SERVICE               logs du service
       journalctl -u SERVICE -n 50          50 dernieres lignes
       journalctl -u SERVICE -f            suivre en temps reel

EXEMPLES
       # Le service est-il vivant ?
       sudo systemctl status apache2

       # Redemarrer apres modif de config
       sudo systemctl restart apache2

       # Activer au boot ET demarrer maintenant
       sudo systemctl enable --now apache2

       # Tester dans un script (sortie 0 si actif)
       if systemctl is-active --quiet apache2; then ... ; fi
DIG(1) - extrait du manuel
NAME
       dig - DNS lookup utility (outil d'interrogation DNS detaille)

SYNOPSIS
       dig [@SERVEUR] [OPTIONS] NOM [TYPE]

TYPES de requete courants
       A          adresse IPv4 (defaut)
       AAAA       adresse IPv6
       MX         serveurs mail
       NS         serveurs de noms (delegation)
       TXT        enregistrements texte (SPF, DKIM, verifs)
       CNAME      alias
       ANY        tout (souvent filtre)

OPTIONS utiles
       +short            une seule ligne par reponse (scriptable)
       +trace            suivre la chaine de delegation depuis la racine
       +noall +answer    n'afficher que la section reponse
       -x IP             reverse DNS (PTR pour cette IP)

EXEMPLES
       # Quelle IP repond pour ce nom ?
       dig monsite.example.com

       # Court (script friendly)
       dig +short monsite.example.com

       # Interroger un DNS specifique (debug propagation)
       dig @8.8.8.8 monsite.example.com

       # Reverse : a quel nom appartient cette IP ?
       dig -x 139.177.194.159

ALTERNATIVES
       nslookup NOM           outil classique, sortie un peu moins precise
       host NOM               tres compact
       getent hosts NOM       passe par la resolution systeme (incluant /etc/hosts)

1 - Le service tourne ?

sudo systemctl status apache2

2 - Le service ecoute sur le bon port ET la bonne interface ?

sudo ss -tlnp | grep apache
# Si on voit 127.0.0.1:80 : il n'ecoute que en local. Si on voit
# 0.0.0.0:80 ou *:80 : il ecoute partout. Editer /etc/apache2/ports.conf

3 - Le firewall laisse passer ?

sudo ufw status numbered
# Sur le cloud : verifier aussi le security group du fournisseur

4 - La resolution DNS pointe bien sur le bon serveur ?

dig monsite.example.com
# Ou plus simple : tester avec l'IP directement
curl http://<ip-du-serveur>

ss et ufw ont leur extrait de manuel aux questions 1 et 2.

Section Docker

Ports cote Docker

Publication et reseau dans les containers

2 questions ciblees

EXPOSE vs -p --network host.docker.internal

Specificites du networking Docker

Conseil : si tu n'as pas encore fait les mini-tests Docker (Mini-test 6 Commandes Docker et Mini-test 7 Directives Dockerfile), reviens faire cette section apres - les concepts EXPOSE, -p, --network y sont introduits en detail.

Question 8 / 9 Docker - EXPOSE vs -p

EXPOSE 80 dans le Dockerfile, c'est suffisant ?

Un collegue a ecrit ce Dockerfile et trouve que le port n'est pas accessible depuis son navigateur :
FROM nginx:alpine COPY ./site /usr/share/nginx/html EXPOSE 80

Il fait docker build -t site . puis docker run -d --name web site et curl http://localhost echoue. Pourquoi ? Comment corriger ?

DOCKER-RUN(1) - extrait : publication de ports
SYNOPSIS
       docker run [-p HOTE:CONTAINER] [-P] ... IMAGE

OPTIONS de publication
       -p HOTE:CONTAINER     publier UN port specifique
                             ex: -p 8080:80  -> hote 8080 vers container 80
       -p IP:HOTE:CONTAINER  binder sur une IP precise
                             ex: -p 127.0.0.1:8080:80 (acces local seul)
       -P                    publier TOUS les ports declares par EXPOSE
                             (sur des ports aleatoires de l'hote)

EXPOSE (Dockerfile)
       EXPOSE 80 = metadata SEULEMENT. Ne publie rien tout seul.
       Sert d'indication, et est utilise par -P pour savoir quels
       ports publier automatiquement.

EXEMPLES
       # Publier explicitement
       docker run -d -p 8080:80 --name web nginx

       # Restreindre a localhost (pas accessible du LAN)
       docker run -d -p 127.0.0.1:8080:80 nginx

       # Publication automatique de tous les EXPOSE
       docker run -d -P nginx
       docker port web        # voir ce qui a ete attribue

EXPOSE est purement documentaire. Cela indique aux humains et a Docker que le container ecoute sur le port 80, mais ne publie aucun port sur l'hote. C'est une metadata, pas une regle de routage.

Pour vraiment publier, il faut -p au moment du run :

docker run -d --name web -p 8080:80 site
# 8080 = port externe (l'hote)
# 80   = port interne (le container)
# Et donc : http://localhost:8080 fonctionne

Astuce : -P majuscule publie automatiquement TOUS les ports declares dans EXPOSE, en assignant des ports aleatoires de l'hote. Utile en developpement.

Question 9 / 9 Docker - localhost dans un container

Pourquoi localhost:5432 ne marche pas ?

L'application Flask dans le container essaie de se connecter a Postgres qui tourne sur la machine hote (et pas dans un autre container). Le code dit :
DB_HOST = os.environ.get('DB_HOST', 'localhost') DB_PORT = 5432
Connection refused: localhost:5432
... mais postgres repond bien sur le serveur hote.

Pourquoi ca echoue ? Donnez 2 solutions et la commande docker run corrigee.

DOCKER-RUN(1) - extrait : reseau
SYNOPSIS
       docker run [--network MODE] [--add-host H:IP] ...

OPTIONS reseau
       --network bridge     defaut, reseau isole derriere NAT
       --network host       partage la stack reseau de l'hote (Linux)
       --network NOM        attache a un docker network nomme
       --add-host HOST:IP   entree dans /etc/hosts du container
       --add-host H:host-gateway
                             IP magique pointant vers l'HOTE
       --hostname NOM       nom du container (visible cote container)

DANS un container, "localhost" = le container lui-meme,
PAS la machine hote. Pour parler a l'hote, voir ci-dessous.

ACCEDER A UN SERVICE DE L'HOTE
       # 1. IP de l'hote sur le LAN
       docker run -e DB_HOST=192.168.1.50 app

       # 2. host.docker.internal (portable Linux/Mac/Windows)
       docker run --add-host=host.docker.internal:host-gateway \
                  -e DB_HOST=host.docker.internal app

       # 3. --network host (Linux seulement, casse l'isolation)
       docker run --network host app

PARLER A UN AUTRE CONTAINER
       # Les deux containers sur le meme docker network nomme
       # -> resolution DNS automatique par nom de service
       docker network create monreseau
       docker run -d --name bdd --network monreseau postgres
       docker run -d --name app --network monreseau -e DB_HOST=bdd app

Pourquoi ? Chaque container a son propre stack reseau. Dans le container, localhost = le container lui-meme, et non la machine hote. Donc localhost:5432 cherche Postgres dans le container.

Solution 1 : utiliser l'IP de l'hote sur le LAN

docker run -d --name app -p 9090:80 \
    -e DB_HOST=192.168.1.50 \
    mon-app

Solution 2 : utiliser le nom magique host.docker.internal

docker run -d --name app -p 9090:80 \
    --add-host=host.docker.internal:host-gateway \
    -e DB_HOST=host.docker.internal \
    mon-app

Solution 3 : --network host (Linux, casse l'isolation reseau du container)

Mieux a long terme : mettre Postgres dans son propre container et les relier par un meme docker network. La resolution DNS Docker permet alors d'utiliser le nom du service.

Bilan

Ce que vous venez de pratiquer

Cote systeme :

Cote Docker :

Touche R pour recommencer ce mini-test

« Retour aux mini-tests