Penpot design platform¶
Self-hosted Penpot (MPL-2.0, Clojure/ClojureScript) design and prototyping platform deployed at penpot.kup.tirol. It replaces paid Figma seats for team and customer design work.
Overview¶
Penpot runs as five deployments from the upstream Helm chart, wrapped in a K3S HelmChart resource.
Component |
Port |
Replicas |
Purpose |
|---|---|---|---|
Frontend |
8080 |
2 |
nginx serving the SPA and proxying every other component |
Backend |
6060 |
1 |
API, authentication, file storage |
Exporter |
6061 |
1 |
Headless Chromium for PNG, SVG, and PDF export |
MCP |
4401, 4402 |
1 |
Model Context Protocol server for agent access to designs |
Admin console |
3000 |
1 |
Instance and user administration |
Only the frontend is exposed through the ingress.
It proxies the other components internally over PENPOT_BACKEND_URI, PENPOT_EXPORTER_URI, PENPOT_MCP_URI, and PENPOT_ADMIN_CONSOLE_URI.
Access¶
Open the app at https://penpot.kup.tirol.
Registration is open only to email addresses in registrationDomainWhitelist, currently kleinundpartner.at.
Invitations do not bypass that whitelist, so onboarding a customer means adding their domain first.
See How to onboard team members and customers.
The admin console lives at /admin-console and redirects to the normal Penpot login.
Warning
Outgoing mail does not work while Penpot runs on a dedicated EX worker.
Mailjet resets connections from the egress IPs of kup6s-ex-hel-1 and
kup6s-ex-hel-2 on every port, so verification and invitation mails never
leave the cluster.
Mailjet support ticket 4282793 tracks the unblock request.
Until it is resolved, activate a new account manually — see
Troubleshoot Penpot.
Warning
The MCP endpoints under /mcp answer unauthenticated callers.
An anonymous client can complete the MCP handshake and list tools, including execute_code.
Penpot states that a user must first connect a design project with the Penpot MCP plugin before those tools act on anything, but the pairing model has not been audited here.
Treat the MCP surface as untrusted until it is restricted or verified.
Architecture¶
Concern |
Implementation |
|---|---|
Source |
|
Chart |
|
Database |
CloudNativePG |
Database backups |
barman-cloud plugin to |
Design assets |
Hetzner S3 |
Cache and sessions |
Valkey StatefulSet |
Secrets |
External Secrets Operator, bridged from the |
Mailjet relay, shared with the other deployments |
|
Ingress |
Traefik with |
File data stays in PostgreSQL (fileDataBackend: legacy-db).
Only assets go to S3, because the object storage backend for file data has an open upstream bug with shared library absorption.
There is no PgBouncer pooler.
The backend caps its own JDBC pool with PENPOT_DATABASE_MAX_POOL_SIZE, because Penpot otherwise holds 60 connections open per replica.