Penpot è una piattaforma di design open-source che si propone come alternativa self-hosted a strumenti come Figma e Adobe XD. È sviluppata da un team spagnolo (Kaleidos) e supportata da una community in costante crescita, con il codice sorgente disponibile su GitHub sotto licenza MPL 2.0. La piattaforma permette di creare interfacce utente, prototipi interattivi e sistemi di design completi, il tutto direttamente dal browser senza installare alcun software sui dispositivi dei designer.

A differenza di molte alternative, Penpot utilizza standard web aperti come SVG per la grafica e CSS per il layout, rendendo i progetti facilmente esportabili e riutilizzabili al di fuori della piattaforma stessa. Questo approccio lo rende particolarmente interessante per team che vogliono mantenere il pieno controllo sui propri asset di design senza vincolarsi a formati proprietari.

Processo di Installazione

Dopo aver installato Docker Engine e Docker Compose, è possibile procedere con l’installazione di Penpot. L’architettura del servizio è composta da diversi container che lavorano insieme: il frontend che serve l’interfaccia web, il backend che gestisce la logica applicativa, un servizio di esportazione per generare file PDF e SVG, un database PostgreSQL per la persistenza dei dati e Valkey (fork open-source di Redis) per la gestione delle notifiche WebSocket, delle sessioni e delle code di esportazione.

Il diagramma seguente illustra come i servizi comunicano tra loro all’interno della rete Docker:

graph TD User["🌐 Browser"] subgraph Docker Network Frontend["Frontend
Nginx · :8080"] Backend["Backend
Clojure/JVM"] Exporter["Exporter
Chromium headless"] Postgres["PostgreSQL 15
Database"] Valkey["Valkey 8.1
Cache / WebSocket"] Assets[("📁 Volume
penpot_assets")] end User -- "porta 9001" --> Frontend Frontend -- "API proxy" --> Backend Frontend -. "serve file statici" .-> Assets Backend -- "query SQL" --> Postgres Backend -- "notifiche real-time" --> Valkey Backend -. "legge/scrive asset" .-> Assets Exporter -- "renderizza progetti" --> Frontend Exporter -- "gestione code" --> Valkey

Creiamo il File Docker Compose

Il file docker-compose.yml qui sotto configura l’intero stack di Penpot seguendo le ultime raccomandazioni ufficiali. Il servizio sarà raggiungibile sulla porta 9001.

yaml
services:
  penpot-frontend:
    image: penpotapp/frontend:${PENPOT_VERSION:-latest}
    container_name: penpot_frontend
    restart: always
    ports:
      - 9001:8080
    volumes:
      - penpot_assets:/opt/data/assets
    depends_on:
      - penpot-backend
      - penpot-exporter

  penpot-backend:
    image: penpotapp/backend:${PENPOT_VERSION:-latest}
    container_name: penpot_backend
    restart: always
    volumes:
      - penpot_assets:/opt/data/assets
    depends_on:
      penpot-postgres:
        condition: service_healthy
      penpot-valkey:
        condition: service_healthy
    environment:
      PENPOT_FLAGS: ${PENPOT_FLAGS}
      PENPOT_PUBLIC_URI: ${PENPOT_PUBLIC_URI}
      PENPOT_SECRET_KEY: ${PENPOT_SECRET_KEY}
      PENPOT_DATABASE_URI: postgresql://penpot-postgres/${PENPOT_DATABASE_NAME}
      PENPOT_DATABASE_USERNAME: ${PENPOT_DATABASE_USER}
      PENPOT_DATABASE_PASSWORD: ${PENPOT_DATABASE_PASSWORD}
      PENPOT_REDIS_URI: redis://penpot-valkey/0
      # Configurazione Storage (Versione 2.11+)
      PENPOT_OBJECTS_STORAGE_BACKEND: fs
      PENPOT_OBJECTS_STORAGE_FS_DIRECTORY: /opt/data/assets
      PENPOT_HTTP_SERVER_MAX_BODY_SIZE: 384000000
      PENPOT_TELEMETRY_ENABLED: "false"
      PENPOT_TELEMETRY_REFERER: compose
      ## Configurazione SMTP (opzionale, vedi sezione dedicata)
      # PENPOT_SMTP_DEFAULT_FROM: no-reply@example.com
      # PENPOT_SMTP_HOST: penpot-mailcatch
      # PENPOT_SMTP_PORT: 1025

  penpot-exporter:
    image: penpotapp/exporter:${PENPOT_VERSION:-latest}
    container_name: penpot_exporter
    restart: always
    depends_on:
      penpot-valkey:
        condition: service_healthy
    environment:
      PENPOT_PUBLIC_URI: http://penpot-frontend:8080
      PENPOT_SECRET_KEY: ${PENPOT_SECRET_KEY}
      PENPOT_REDIS_URI: redis://penpot-valkey/0

  penpot-postgres:
    image: postgres:15
    container_name: penpot_postgres
    restart: always
    stop_signal: SIGINT
    volumes:
      - penpot_database:/var/lib/postgresql/data
    environment:
      POSTGRES_INITDB_ARGS: --data-checksums
      POSTGRES_DB: ${PENPOT_DATABASE_NAME}
      POSTGRES_USER: ${PENPOT_DATABASE_USER}
      POSTGRES_PASSWORD: ${PENPOT_DATABASE_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${PENPOT_DATABASE_USER} -d ${PENPOT_DATABASE_NAME}"]
      interval: 5s
      timeout: 5s
      retries: 5

  penpot-valkey:
    image: valkey/valkey:8.1
    container_name: penpot_valkey
    restart: always
    environment:
      - VALKEY_EXTRA_FLAGS=--maxmemory 128mb --maxmemory-policy volatile-lfu
    healthcheck:
      test: ["CMD-SHELL", "valkey-cli ping | grep PONG"]
      interval: 2s
      timeout: 3s
      retries: 5

  # Servizio opzionale per testare le email localmente
  penpot-mailcatch:
    image: sj26/mailcatcher:latest
    container_name: penpot_mailcatch
    restart: always
    ports:
      - "1080:1080" # Interfaccia Web per leggere le email

volumes:
  penpot_database:
  penpot_assets:

Servizio Frontend

Il frontend è un server Nginx che serve l’interfaccia web e fa da proxy verso il backend. Il volume penpot_assets è condiviso per servire direttamente file statici, immagini e font caricati dagli utenti.

Servizio Backend

È il cuore dell’applicazione. Dalla versione 2.11, Penpot utilizza le variabili PENPOT_OBJECTS_STORAGE_* per gestire i file binari. La variabile PENPOT_PUBLIC_URI è fondamentale per la corretta generazione dei link nelle email e per le operazioni dell’exporter.

Servizio Exporter

Gestisce la generazione di PDF e immagini. Ora richiede l’accesso a Valkey (PENPOT_REDIS_URI) e la PENPOT_SECRET_KEY per coordinare le code di esportazione in modo sicuro.

Servizio Database

PostgreSQL 15 con checksum dei dati abilitato. Il database non è esposto all’esterno per sicurezza.

Servizio Valkey

Viene utilizzata l’ultima versione di Valkey (8.1), un fork open-source di Redis ad alte prestazioni. Gestisce le notifiche real-time, le sessioni e le code di lavoro.

Creiamo il File .env

Il file .env contiene le credenziali e le impostazioni fondamentali.

Per generare la PENPOT_SECRET_KEY (stringa di almeno 64 caratteri), puoi usare:

bash
python3 -c "import secrets; print(secrets.token_urlsafe(64))"
bash
PENPOT_VERSION=latest
PENPOT_PUBLIC_URI=http://localhost:9001

PENPOT_FLAGS=disable-registration enable-login-with-password disable-secure-session-cookies

PENPOT_SECRET_KEY=SOSTITUIRE-CON-CHIAVE-GENERATA

PENPOT_DATABASE_NAME=penpot
PENPOT_DATABASE_USER=penpot
PENPOT_DATABASE_PASSWORD=5up3r_P4s5w0rd_DB

La variabile PENPOT_FLAGS controlla le funzionalità attive. In questa configurazione la registrazione pubblica è disabilitata (disable-registration) e i cookie sicuri sono disattivati per l’uso in locale senza HTTPS.

Cookie sicuri e HTTPS

Una volta configurato un reverse proxy con HTTPS, rimuovi il flag disable-secure-session-cookies e assicurati che PENPOT_PUBLIC_URI utilizzi il protocollo https://.

Primo Avvio

Una volta creati i file docker-compose.yml e .env, è possibile avviare lo stack con il comando:

bash
docker compose up -d

Al primo avvio i container impiegheranno qualche secondo in più per inizializzare il database e scaricare le dipendenze interne. Una volta pronto, il servizio sarà raggiungibile all’indirizzo http://<indirizzo-server>:9001.

Dato che la registrazione è disabilitata nella configurazione proposta, il primo utente va creato manualmente tramite il terminale con il seguente comando:

bash
docker exec -ti penpot_backend python3 manage.py create-profile

Lo script chiederà interattivamente email, nome completo e password per il nuovo account. Una volta completata la procedura sarà possibile effettuare il login dall’interfaccia web.

Registrazione aperta

Se si preferisce consentire la registrazione direttamente dall’interfaccia web, è sufficiente rimuovere il flag disable-registration dal file .env e riavviare lo stack. In questo caso il primo utente potrà registrarsi normalmente dal browser. È consigliabile riaggiungere il flag dopo aver creato tutti gli account necessari, soprattutto se il servizio è esposto su internet.

Configurazione SMTP

L’invio di email non è strettamente necessario per il funzionamento di Penpot, ma diventa importante se si vuole abilitare la verifica degli indirizzi email, il recupero password o le notifiche di invito ai team. Per attivare l’SMTP è sufficiente decommentare le variabili nel file docker-compose.yml e compilarle con i dati del proprio server di posta.

Dopo aver configurato l’SMTP, aggiungere il flag enable-email-verification alla variabile PENPOT_FLAGS nel file .env per attivare la verifica degli indirizzi email alla registrazione.

Troubleshooting & Consigli

Di seguito alcuni consigli utili per risolvere i problemi di configurazione più comuni:

  • Se Penpot mostra una pagina bianca dopo il login, verificare che la PENPOT_SECRET_KEY sia la stessa per tutti gli avvii. Se la chiave cambia, i token di sessione esistenti diventano invalidi. Rigenerare la chiave significa che tutti gli utenti dovranno effettuare nuovamente il login.
  • Se l’exporter non funziona e le esportazioni in PDF restano in attesa, verificare che il container penpot_exporter sia attivo e che la variabile PENPOT_PUBLIC_URI punti correttamente al frontend sulla rete Docker interna.
  • Per esporre Penpot su internet, configurare un reverse proxy (es. Caddy o NGINX Proxy Manager ) con HTTPS e un certificato SSL valido. Dopo la configurazione, rimuovere il flag disable-secure-session-cookies dal file .env e riavviare lo stack.
  • Per eseguire il backup del database, è possibile utilizzare pg_dump direttamente dal container PostgreSQL con il comando:
    bash
    docker exec penpot_postgres pg_dump -U penpot penpot > backup_penpot.sql
    Oltre al database, è consigliabile effettuare il backup anche del volume penpot_assets che contiene tutti i file caricati dagli utenti.
  • Per aggiornare Penpot, modificare la variabile PENPOT_VERSION nel file .env con la versione desiderata (o lasciare latest) ed eseguire docker compose pull && docker compose up -d.