PostgreSQL è un sistema di gestione di database relazionali open-source, considerato tra i più avanzati e affidabili disponibili oggi. Nato nel 1986 come progetto accademico all’Università di Berkeley, nel corso degli anni si è evoluto fino a diventare la scelta prediletta per chi necessita di un database robusto e conforme agli standard SQL.

Questo database è progettato per gestire carichi di lavoro complessi, grandi volumi di dati e accessi concorrenti da parte di più utenti e applicazioni. PostgreSQL supporta tipi di dato avanzati come JSON, array e dati geospaziali, rendendolo adatto a scenari molto diversi tra loro: dalle applicazioni web ai sistemi di analisi dati, dalla gestione di contenuti alla raccolta di metriche per il monitoraggio.

Metodi Alternativi

Cerchi prestazioni native o un’integrazione più stretta col sistema operativo? Consulta le nostre guide per installare PostgreSQL direttamente su Linux o in modo dichiarativo su NixOS .

Docker Compose

Il file docker-compose.yml qui sotto configura un’istanza PostgreSQL pronta all’uso, mentre il file .env contiene le credenziali separandole dalla configurazione. Il volume postgres_data garantisce la persistenza dei dati anche in caso di riavvio o aggiornamento del container. La porta 5432 viene esposta sull’host per consentire le connessioni da parte delle applicazioni e degli strumenti di amministrazione.

Creiamo il File Docker Compose

yaml
services:
  postgresql:
    image: postgres:17
    container_name: postgresql
    restart: unless-stopped
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

volumes:
  postgres_data:

L’healthcheck verifica periodicamente che il database sia pronto ad accettare connessioni tramite il comando pg_isready. In questo modo Docker è in grado di rilevare se il servizio diventa irraggiungibile e di segnalarne lo stato, informazione particolarmente utile quando altri container dipendono da PostgreSQL per funzionare.

Creiamo il File .env

Il file .env va creato nella stessa directory del docker-compose.yml e contiene le credenziali di accesso al database. Docker Compose lo legge automaticamente e sostituisce le variabili ${...} presenti nel Compose con i valori definiti qui. Separare le credenziali dalla configurazione è una buona pratica di sicurezza: il docker-compose.yml può essere condiviso o versionato senza rischiare di esporre password in chiaro.

bash
POSTGRES_USER=postgres
POSTGRES_PASSWORD=cambiami_con_una_password_sicura

Suggerimento

Utilizza il nostro metodo per generare password sicure con OpenSSL direttamente dal tuo terminale.

Le variabili POSTGRES_USER e POSTGRES_PASSWORD hanno effetto solo al primo avvio, quando il volume dati è vuoto. Una volta inizializzato il database, modificare questi valori nel file .env non cambierà le credenziali già salvate: per farlo sarà necessario intervenire direttamente dalla console PostgreSQL.

Per avviare il container è sufficiente posizionarsi nella directory contenente il file docker-compose.yml ed eseguire il comando:

bash
docker compose up -d

Primo Accesso al Database

Una volta che il container è in esecuzione possiamo accedere alla console del database tramite docker exec, che ci permette di eseguire comandi direttamente all’interno del container.

bash
docker exec -it postgresql psql -U postgres

La password dell’utente postgres è già stata configurata tramite il file .env. Se in futuro si desidera modificarla, è possibile farlo direttamente dalla console con il seguente comando:

sql
ALTER USER postgres WITH PASSWORD 'Nu0v4_P4ss0rd';

Il comando ALTER USER ha effetto immediato: la nuova password sarà richiesta a partire dalla prossima connessione al database.

Password di sistema e password del database

La password che gestiamo qui è quella del database PostgreSQL, utilizzata per l’autenticazione alle connessioni SQL, la quale è diversa dalla password di sistema dell’utente.

Gestione del Database

Una volta che PostgreSQL è attivo e funzionante, è buona pratica creare utenti e database dedicati per ogni servizio che andremo ad ospitare. Evitare di utilizzare l’utente postgres per le applicazioni è importante dal punto di vista della sicurezza: in questo modo si ottiene una compartimentazione dei dati e, nel caso in cui un utente venisse compromesso, l’impatto rimarrebbe limitato al singolo servizio senza coinvolgere l’intero sistema.

Sicurezza e gestione degli utenti

La configurazione presentata in questa guida rappresenta un singolo caso d’uso da utilizzare come punto di riferimento. La gestione della sicurezza, dei permessi e degli utenti del database dovrà essere adattata in base alle proprie necessità e alle politiche di sicurezza del proprio ambiente.

Tutti i comandi seguenti vanno eseguiti dalla console PostgreSQL, accessibile tramite il comando psql.

Creazione di un nuovo utente

Per ogni servizio è consigliato creare un utente dedicato con una password robusta. Questo garantisce che ogni applicazione acceda esclusivamente ai propri dati.

Suggerimento

Utilizza il nostro metodo per generare password sicure con OpenSSL direttamente dal tuo terminale.
sql
CREATE USER userxyz WITH PASSWORD '5up3rM3g4_P455w0rd';

Creazione di un database

Una volta creato l’utente è possibile creare il database assegnandolo direttamente come proprietario. In questo modo l’utente avrà automaticamente tutti i privilegi necessari sul database stesso.

sql
CREATE DATABASE service_01 OWNER userxyz;

Configurazione dei permessi

Anche se userxyz è il proprietario del database, è buona pratica assegnare esplicitamente i permessi di connessione, schema e tabelle. Questo rende la configurazione riutilizzabile anche per utenti che non sono proprietari del database e garantisce che alcuni servizi self-hosted, che richiedono permessi espliciti, funzionino correttamente.

sql
GRANT CONNECT ON DATABASE service_01 TO userxyz;

Una volta concessa la connessione è possibile assegnare all’utente anche i permessi per la gestione delle tabelle. Per farlo è necessario prima connettersi al database.

sql
\c service_01

A questo punto possiamo assegnare i privilegi sullo schema e sulle tabelle. I comandi ALTER DEFAULT PRIVILEGES garantiscono che i permessi vengano applicati automaticamente anche alle tabelle e sequenze che verranno create in futuro dal servizio, evitando di dover ripetere manualmente l’assegnazione ogni volta.

sql
GRANT USAGE ON SCHEMA public TO userxyz;
GRANT CREATE ON SCHEMA public TO userxyz;

GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO userxyz;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO userxyz;

GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO userxyz;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO userxyz;

Consigli Finali

  • Evitare di utilizzare l’utente postgres per le applicazioni: creare sempre un utente dedicato per ogni servizio, in modo da limitare i danni in caso di compromissione.
  • Sostituire il metodo di autenticazione md5 con scram-sha-256 dove possibile, in quanto offre una protezione più robusta delle credenziali durante il processo di autenticazione.
  • Restringere gli intervalli IP nella configurazione di pg_hba.conf ai soli indirizzi che necessitano realmente di accedere al database, evitando di lasciare 0.0.0.0/0 in ambienti di produzione.
  • Verificare periodicamente che i backup vengano eseguiti correttamente e testare il ripristino di un dump su un ambiente di prova.
  • Mantenere PostgreSQL aggiornato all’ultima minor release disponibile. Le minor release includono spesso correzioni di sicurezza importanti.
  • Valutare l’abilitazione di SSL (ssl = on) per cifrare le connessioni tra client e server, specialmente se il database è raggiungibile da reti non fidate.
  • Monitorare le dimensioni della directory dati e della directory di backup per evitare di esaurire lo spazio disco, configurando eventualmente degli alert tramite strumenti come Grafana o Prometheus.