Vai al contenuto principale

Come esporre una porta Docker

Scopri come esporre e pubblicare correttamente le porte in Docker per abilitare la comunicazione tra i tuoi container e il mondo esterno. Questa guida copre tutto, dalla configurazione del Dockerfile e dei flag a runtime fino all'orchestrazione con Docker Compose e alle tecniche di troubleshooting.
Aggiornato 29 set 2026  · 11 min leggi

Scopri con l'IA

ChatGPTClaudePerplexity

Quando lavori con i container Docker, uno degli aspetti più importanti che ho incontrato è abilitare la comunicazione di rete tra i container e il mondo esterno. Senza una corretta configurazione delle porte, le applicazioni containerizzate restano isolate e inaccessibili. In questo articolo ti guiderò nel processo di esposizione delle porte Docker, una competenza fondamentale per chiunque lavori con applicazioni containerizzate.

Questa guida è pensata in particolare per sviluppatori software, ingegneri DevOps e professionisti IT che devono rendere le proprie applicazioni containerizzate accessibili a utenti, ad altri servizi o a sistemi esterni. Che tu stia distribuendo un server web, una API o un database all'interno di un container, capire come esporre le porte è essenziale per costruire sistemi funzionali basati su Docker.

Al termine di questo articolo, avrai una chiara comprensione di come funziona il networking in Docker, dei diversi metodi per esporre le porte e delle tecniche pratiche per applicare questi concetti nei tuoi progetti.

Se sei alle prime armi con Docker, valuta di seguire uno dei nostri corsi, come Introduction to Docker, Containerization and Virtualization with Docker and Kubernetes, Intermediate Docker o Containerization and Virtualization Concepts.

Cosa significa esporre una porta in Docker?

Prima di entrare nei dettagli tecnici, è importante capire cosa significa esposizione delle porte nell'ecosistema Docker.

Principi di isolamento della rete dei container

I container Docker sono progettati con l'isolamento come principio fondamentale. Questo isolamento è ottenuto tramite funzionalità del kernel Linux come i namespaces e i cgroups. I namespaces forniscono isolamento dei processi, garantendo che i processi all'interno di un container non possano vedere o interagire con processi di altri container o del sistema host. I cgroups, invece, gestiscono l'allocazione delle risorse, limitando quanto CPU, memoria e altre risorse un container può consumare.

Dal punto di vista della rete, ogni container riceve il proprio namespace di rete, completo di un'interfaccia Ethernet virtuale (coppia veth). Questa interfaccia si collega di default a una rete bridge di Docker, permettendo la comunicazione tra container pur mantenendo l'isolamento dalla rete dell'host. È come se ogni container avesse il proprio indirizzo di rete privato, invisibile al mondo esterno.

Nella configurazione predefinita, un container Docker è completamente isolato. I servizi in esecuzione al suo interno possono comunicare tra loro, ma sono irraggiungibili dall'esterno del container, persino dalla macchina host. Ed è qui che l'esposizione delle porte diventa necessaria.

Expose vs publish: distinzione semantica

Quando configuri le porte in Docker, incontrerai due concetti correlati ma distinti: esporre e pubblicare le porte.

Esporre le porte è principalmente una funzionalità di documentazione. Quando esponi una porta in Docker, stai essenzialmente aggiungendo metadati all'immagine del container, indicando che l'applicazione containerizzata ascolta su porte specifiche. 

Tuttavia, esporre una porta non la rende effettivamente accessibile dall'esterno del container. Serve da documentazione per gli utenti della tua immagine.

Pubblicare le porte è ciò che rende davvero i servizi containerizzati disponibili al mondo esterno. La pubblicazione crea una mappatura tra una porta sulla macchina host e una porta all'interno del container. Quando pubblichi una porta, Docker configura la rete dell'host per inoltrare il traffico dalla porta host specificata alla corrispondente porta del container.

Ecco quando usare ciascun approccio:

  • Usa expose quando crei immagini destinate ad altri utenti Docker, per documentare quali porte usa la tua applicazione.
  • Usa publish quando hai bisogno che sistemi esterni (incluso l'host) accedano ai servizi in esecuzione nel tuo container.
  • Usali entrambi insieme per una documentazione completa e funzionalità effettiva, soprattutto in ambienti di produzione.

Come esporre le porte Docker

Ora che abbiamo capito i concetti, vediamo gli aspetti pratici dell'esposizione delle porte Docker in diversi contesti.

Strategie di dichiarazione nel Dockerfile

Il modo più basilare per esporre una porta è usare l'istruzione EXPOSE nel tuo Dockerfile. Questa dichiara le porte che il container è progettato per utilizzare.

FROM my-image:latest
EXPOSE 80
EXPOSE 443

In questo esempio, ho specificato che il container utilizzerà le porte 80 e 443, che sono standard per il traffico HTTP (Hypertext Transfer Protocol) e HTTPS (Hypertext Transfer Protocol Secure). Puoi anche combinarle in un'unica istruzione:

EXPOSE 80 443

Quando specifichi le porte, è buona pratica includere il protocollo, TCP (Transmission Control Protocol) o UDP (User Datagram Protocol) se la tua applicazione ne usa uno specifico:

EXPOSE 53/udp
EXPOSE 80/tcp

Se non viene specificato alcun protocollo, per impostazione predefinita si assume TCP. Questo è appropriato per la maggior parte delle applicazioni web, ma servizi come il DNS (Domain Name System) o i server di gaming spesso richiedono UDP.

Dal punto di vista della sicurezza, raccomando di esporre solo le porte di cui la tua applicazione ha effettivamente bisogno. Ogni porta esposta rappresenta un potenziale vettore di attacco, quindi ridurre al minimo il numero di porte esposte segue il principio del privilegio minimo.

Gestione delle porte in fase di esecuzione

Sebbene l'istruzione EXPOSE documenti quali porte usa un container, per rendere queste porte accessibili dall'host o da altre macchine, devi pubblicarle quando avvii il container.

Ecco come associare esplicitamente una porta del container a una specifica porta dell'host:

docker run -p 8081:80 my-image

Il flag -p (o --publish) ti permette di associare una singola porta o un intervallo di porte del container all'host.

Questo comando mappa la porta 80 all'interno del container alla porta 8081 sull'host. Dopo aver eseguito questo comando, puoi accedere al server web navigando su http://localhost:8081 nel browser.

Per comodità durante lo sviluppo, Docker fornisce il flag -P, P maiuscola o --publish-all, che pubblica automaticamente tutte le porte esposte su porte casuali con numerazione alta sull'host:

docker run -P my-image

Per scoprire quali porte host sono state assegnate, posso usare il comando docker ps:

docker ps

Mostrerà un output simile a:

CONTAINER ID   IMAGE  COMMAND    CREATED  STATUS  PORTS                                  NAMES
a7c53d9413bf   image  "/docker-.…"  10 s ago   Up 9 s    0.0.0.0:49153->80/tcp, :::49153->80/tcp   wizardl

Qui, la porta 80 all'interno del container è mappata alla porta 49153 sull'host.

Quando lavori con servizi che usano sia TCP che UDP sulla stessa porta (come i server DNS), devi specificare il protocollo durante la pubblicazione:

docker run -p 53:53/tcp -p 53:53/udp dns-server

Orchestrazione con Docker Compose

Per applicazioni multi-container, Docker Compose offre un modo più gestibile per configurare rete e porte.

In un file YAML di Docker Compose, puoi specificare le mappature delle porte sotto la chiave ports per ciascun servizio:

services:
  web:
    image: my-image
    ports:
      - "8081:80"
      - "443:443"
  api:
    build: ./api
    ports:
      - "3000:3000"

Docker Compose fa un'importante distinzione tra ports ed expose. La sezione ports crea mappature pubblicate delle porte accessibili dall'esterno, mentre expose rende disponibili le porte solo ai servizi collegati all'interno della stessa rete di Compose:

services:
  web:
    image: my-image
    ports:
      - "8081:80"
  database:
    image: postgres
    expose:
      - "5432"

In questo esempio, il servizio web è accessibile dall'host alla porta 8081, ma il database PostgreSQL è accessibile solo agli altri servizi all'interno del file Compose, non direttamente dall'host.

Per configurazioni flessibili, soprattutto tra ambienti diversi, posso usare variabili d'ambiente nelle mappature delle porte:

services:
  web:
    image: my-image
    ports:
      - "${WEB_PORT:-8081}:80"

Questa sintassi mi consente di specificare la porta host tramite una variabile d'ambiente (WEB_PORT), con default a 8081 se non impostata.

Esposizione delle porte Docker - Esempio pratico

Vediamo un esempio completo di esposizione delle porte Docker per un'applicazione web con un database backend.

Immagina di costruire una semplice applicazione web composta da un servizio API Python Flask e un database PostgreSQL. Il servizio API ascolta sulla porta 5000 e PostgreSQL usa la sua porta predefinita 5432.

Ecco come potrebbe apparire la nostra semplice applicazione Flask (app.py). Questa applicazione creerà un database myapp e recupererà i dati dalla tabella items, una volta che questa tabella sarà creata all'interno del database.

from flask import Flask, jsonify
import os
import psycopg2

app = Flask(__name__)

# Database connection parameters from environment variables
DB_HOST = os.environ.get('DB_HOST', 'db')
DB_NAME = os.environ.get('DB_NAME', 'myapp')
DB_USER = os.environ.get('DB_USER', 'postgres')
DB_PASS = os.environ.get('DB_PASSWORD', 'postgres')

@app.route('/')
def index():
    return jsonify({'message': 'API is running'})

@app.route('/items')
def get_items():
    # Connect to the PostgreSQL database
    conn = psycopg2.connect(
        host=DB_HOST,
        database=DB_NAME,
        user=DB_USER,
        password=DB_PASS
    )
    
    # Create a cursor and execute a query
    cur = conn.cursor()
    cur.execute('SELECT id, name FROM items')
    
    # Fetch results and format as list of dictionaries
    items = [{'id': row[0], 'name': row[1]} for row in cur.fetchall()]
    
    # Close connections
    cur.close()
    conn.close()
    
    return jsonify(items)

if __name__ == '__main__':
    # Run the Flask app, binding to all interfaces (important for Docker)
    app.run(host='0.0.0.0', port=5000)

Successivamente, creerò il nostro file requirements.txt:

flask
psycopg2-binary

Ora devo creare un Dockerfile per il nostro servizio API Python:

FROM python:3.9-slim
WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose the port Flask runs on
EXPOSE 5000

# Command to run the application
CMD ["python", "app.py"]

Infine, creerò un file Docker Compose per orchestrare entrambi i servizi:

services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
      tags:
        - "my-custom-image:latest"
    container_name: my-custom-api
    ports:
      - "5000:5000"
    environment:
      - DB_HOST=db
      - DB_NAME=myapp
      - DB_USER=postgres
      - DB_PASSWORD=postgres
    depends_on:
      - db
  
  db:
    container_name: my-custom-db
    image: postgres:13
    expose:
      - "5432"
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

In questa configurazione:

  1. Il servizio API viene buildato dal nostro Dockerfile e pubblica la porta 5000, rendendola accessibile dalla macchina host.
  2. Il servizio PostgreSQL espone la porta 5432 ma non la pubblica, rendendola accessibile solo agli altri servizi all'interno della rete di Compose.
  3. Il servizio API può accedere al database usando l'hostname db (che è il nome del servizio) e la porta 5432.

Per eseguire questa applicazione, usa:

docker-compose up

Ora posso accedere all'API su http://localhost:5000, mentre l'istanza di PostgreSQL non è direttamente accessibile dall'esterno della rete Docker, il che è una buona pratica di sicurezza per i servizi di database. Ma puoi accedere a PostgreSQL dal container in esecuzione:

docker compose exec db psql -U postgres -d myapp

Questo comando accederà alla CLI di PostgreSQL, dove posso visualizzare il database e creare una tabella items. Una volta creata, posso visualizzare i dati su http://localhost:5000/items

Come esporre più porte Docker

Se la mia applicazione Python deve esporre più porte, posso specificarle tutte nel Dockerfile:

FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000 8081 9090
CMD ["python", "app.py"]

Questo Dockerfile espone:

  • Porta 5000 per l'applicazione Flask principale (attualmente attiva)
  • Porta 8081 per un potenziale dashboard di monitoraggio 
  • Porta 9090 per una futura interfaccia di debugging

È importante notare che, sebbene io abbia esposto le porte 8081 e 9090 nel Dockerfile come documentazione, la mia attuale applicazione Flask è configurata per ascoltare solo sulla porta 5000. Le ulteriori porte esposte indicano dove potrebbero essere implementate funzionalità future.

Come pubblicare le porte esposte

Per pubblicare le porte esposte in un Dockerfile, uso il flag -p o -P quando eseguo il container:

docker run -p 8081:5000  my-custom-image

Questo mappa la porta 5000 nel container (che è esposta nel Dockerfile e dove Flask è in ascolto) alla porta 8081 sull'host. Dopo aver eseguito questo comando, posso accedere alla mia applicazione Flask navigando su http://localhost:8081 nel browser.

Posso anche usare il flag -P per pubblicare automaticamente tutte le porte esposte su porte casuali dell'host:

docker run -P my-custom-image

Per verificare quali porte sono state pubblicate, posso usare:

docker ps

Per informazioni più dettagliate, posso usare:

docker port [container_id]
5000/tcp -> 0.0.0.0:32768
8081/tcp -> 0.0.0.0:32769
9090/tcp -> 0.0.0.0:32770

Questo comando mostra tutte le mappature delle porte per un container specifico. Ad esempio, se la mia applicazione Flask ascolta solo sulla porta 5000 ma ho esposto più porte nel Dockerfile, docker port mi mostrerà esattamente quali porte host sono mappate a quali porte del container. Quindi, se la porta 5000 è stata mappata a 32768, posso accedere alla mia applicazione Flask su http://localhost:32768

Tecniche di diagnostica e troubleshooting

Anche con una configurazione accurata, possono sorgere problemi con il mapping delle porte in Docker. Ecco alcune tecniche che uso per diagnosticare e risolvere i problemi più comuni.

Ispezione delle mappature delle porte

Il primo passo nella diagnosi di problemi legati alle porte è verificare che le mappature siano configurate correttamente. Uso questi comandi:

Elenca tutti i container in esecuzione con le mappature delle porte:

docker ps

Ottieni informazioni dettagliate su un container specifico:

docker inspect [container_id]

Controlla le mappature delle porte per un container specifico:

docker port [container_id]

Il comando docker inspect fornisce informazioni dettagliate, incluse le impostazioni di rete. Per concentrarti sui dettagli relativi alla rete, usa:

docker inspect --format='{{json .NetworkSettings.Ports}}' [container_id] | jq

Se hai bisogno di un'analisi più approfondita del traffico, strumenti come tcpdump e netstat  possono essere molto utili. Innanzitutto, assicurati che siano installati all'interno del container. Se il container non include già questi strumenti, puoi installarli eseguendo il seguente comando:

docker exec -u root -it f5c6cac71492 bash -c "apt-get update && apt-get install -y net-tools tcpdump"

Per vedere su quali porte l'applicazione è in ascolto all'interno del container:

docker exec -it [container_id] netstat -tuln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:5000            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.11:42265        0.0.0.0:*               LISTEN
udp        0      0 127.0.0.11:34267        0.0.0.0:*

Questo mostra, per esempio, che l'app Flask è in ascolto su tutte le interfacce sulla porta 5000.

Per monitorare il traffico in ingresso e in uscita sull'interfaccia di rete principale del container (solitamente eth0):

docker exec -it [container_id] tcpdump -i eth0
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes

Questo comando ti permette di tracciare il traffico e identificare se le richieste raggiungono il container o se i pacchetti vengono scartati o instradati in modo errato.

Analisi delle regole iptables

Docker utilizza iptables per gestire la Network Address Translation (NAT) e controllare il flusso di traffico tra host e container. Inserisce automaticamente regole per inoltrare le porte dell'host agli IP e alle porte dei container, abilitando un accesso senza soluzione di continuità ai servizi containerizzati.

Su host Linux nativi, puoi ispezionare queste regole utilizzando comandi come:

sudo iptables -t nat -L DOCKER -n -v

Questo mostra come Docker mappa il traffico in ingresso su porte specifiche dell'host verso gli endpoint del container. In base al file Docker Compose visto prima, vedrai le porte inoltrate:

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
   50  3000 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0
  100  6000 RETURN     all  --  br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0
  500 30000 DNAT       tcp  --  !br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0            tcp dpt:5000 to:172.18.0.2:5000
  400 24000 DNAT       tcp  --  !br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8081 to:172.18.0.2:5000
  300 18000 DNAT       tcp  --  !br-xxxxxxx *       0.0.0.0/0            0.0.0.0/0            tcp dpt:9090 to:172.18.0.2:5000

Qui:

  • DNAT reindirizza il traffico dall'host al container.
  • RETURN garantisce il corretto instradamento del traffico interno alla rete Docker.

Tuttavia, a seconda dell'ambiente (ad esempio, Docker Desktop su Windows o WSL2), Docker può gestire il port forwarding in modo diverso e le regole iptables potrebbero non essere visibili o modificabili dall'interno del sistema. In questo caso, puoi controllare il port forwarding con il seguente comando:

sudo ss -tulnp
Netid    State       Recv-Q      Send-Q            Local Address:Port         Peer Address:Port 
tcp        LISTEN     0                 4096                                          *:5000           	        *:*           
tcp        LISTEN     0                 4096                          		   *:8081                               *:*    
tcp        LISTEN     0                 4096                          		   *:9090                              *:*    

Suggerimenti per il troubleshooting:

  • Conferma le mappature delle porte con docker ps e docker port [container].
  • Verifica se il firewall del sistema host o software di sicurezza stanno bloccando le porte.
  • Usa i log del container e strumenti di rete come netstat e tcpdump per verificare il comportamento di rete della tua applicazione.

Conclusione

Esporre le porte Docker è una competenza fondamentale che colma il divario tra l'isolamento dei container e l'usabilità pratica. In questo articolo ho spiegato come funziona il modello di networking di Docker, la differenza tra esporre e pubblicare le porte e ho fornito esempi pratici per vari scenari.

Tieni a mente questi punti chiave:

  • Usa EXPOSE nei Dockerfile per documentare quali porte usa la tua applicazione
  • Usa -p o -P quando esegui i container per rendere queste porte accessibili dall'esterno
  • Sfrutta Docker Compose per gestire applicazioni complesse multi-container
  • Usa strumenti di diagnostica per risolvere i problemi quando si presentano

Padroneggiare questi concetti e tecniche ti permetterà di progettare applicazioni containerizzate più robuste che comunicano efficacemente sia internamente sia con l'esterno. Che tu stia sviluppando una semplice applicazione web o un'architettura a microservizi complessa, una corretta gestione delle porte è fondamentale per il successo.

Poiché i container continuano a dominare le strategie moderne di deployment delle applicazioni, la capacità di gestire con sicurezza il networking e le porte di Docker rimarrà una competenza essenziale nel toolkit di ogni sviluppatore.

Per continuare a imparare, dai un'occhiata alle seguenti risorse:

Exposing a Docker Port FAQs

Cosa significa esporre una porta in Docker?

Esporre una porta in Docker è un modo per documentare su quali porte la tua applicazione containerizzata è in ascolto, ma non rende la porta accessibile al di fuori del container.

Come rendo accessibile la porta di un container Docker dalla mia macchina host?

Pubblichi una porta usando il flag -p con docker run o la sezione ports in Docker Compose, che mappa una porta dell'host alla porta del container.

Qual è la differenza tra `EXPOSE` e `-p` in Docker?

EXPOSE si usa nel Dockerfile per dichiarare le porte a scopo di documentazione, mentre -p pubblica e mappa quelle porte per l'accesso esterno.

Posso esporre più porte per un singolo container Docker?

Sì, puoi esporre più porte usando più istruzioni EXPOSE nel Dockerfile o specificando più porte nella sezione ports di Docker Compose.

Come risolvo i problemi di mapping delle porte in Docker?

Usa comandi come docker ps, docker port, docker inspect e strumenti di rete all'interno del container (ad es. netstat, tcpdump) per verificare le mappature delle porte e il flusso di traffico.


Benito Martin's photo
Author
Benito Martin
LinkedIn

Come fondatore di Martin Data Solutions e Data Scientist/ML & AI Engineer freelance, porto un portfolio vario che include Regression, Classification, NLP, LLM, RAG, reti neurali, metodi ensemble e computer vision.

  • Ho sviluppato con successo diversi progetti ML end-to-end, includendo data cleaning, analytics, modellazione e deployment su AWS e GCP, offrendo soluzioni efficaci e scalabili.
  • Ho realizzato applicazioni web interattive e scalabili con Streamlit e Gradio per casi d’uso in settori diversi.
  • Ho insegnato e fatto mentoring a studenti di data science e analytics, supportandone la crescita professionale con approcci di apprendimento personalizzati.
  • Ho progettato contenuti didattici per applicazioni di retrieval-augmented generation (RAG) su misura per le esigenze enterprise.
  • Ho scritto articoli tecnici di grande impatto su AI & ML, trattando temi come MLOps, database vettoriali e LLM, ottenendo un notevole coinvolgimento.

In ogni progetto che affronto, applico pratiche aggiornate di ingegneria del software e DevOps, come CI/CD, linting del codice, formattazione, monitoraggio dei modelli, tracciamento degli esperimenti e gestione robusta degli errori. Mi impegno a fornire soluzioni complete, trasformando gli insight dai dati in strategie pratiche che aiutano le aziende a crescere e a sfruttare al meglio data science, machine learning e AI.

Argomenti
Docker
Data Engineering

I migliori corsi su Docker

Programma

Containerizzazione e virtualizzazione con Docker e Kubernetes

13 ore
Impara la potenza di Docker e Kubernetes: questa traccia interattiva ti permetterà di costruire e distribuire applicazioni in ambienti moderni.
Vedi i dettagliRight Arrow
Inizia Il Corso
Mostra altroRight Arrow
Correlato

blog

Che cos'è Snowflake? Guida per principianti alla piattaforma dati cloud

Esplora le basi di Snowflake, la piattaforma dati cloud. Scopri la sua architettura, le sue funzionalità e come integrarla nelle tue pipeline di dati.
Tim Lu's photo

Tim Lu

12 min

blog

I 15 migliori server MCP remoti che ogni AI builder dovrebbe conoscere nel 2026

Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Abid Ali Awan's photo

Abid Ali Awan

15 min

blog

Tokenizzazione nel NLP: come funziona, sfide e casi d'uso

Guida al preprocessing NLP nel machine learning. Copriamo spaCy, i transformer di Hugging Face e come funziona la tokenizzazione in casi d'uso reali.
Abid Ali Awan's photo

Abid Ali Awan

10 min

Mostra AltroMostra Altro