Deploying Penpot with Docker
Today I deployed my own Penpot server. It was pretty straight forward for me, but that's because I already have my own SMTP server, and a reverse proxy set up, for which I could create a new SMTP user, and didn't have to worry about configuring traefik.
For those that don't know, Penpot is an open source solution that looks incredibly like Figma. However, being able to host it yourself means that we don't have to worry about the fact that Adobe acquired Figma.
Docker Compose File
The first thing we need is to create a docker-compose.yml
file. One can download the one referenced from the docs by using:
wget https://raw.githubusercontent.com/penpot/penpot/main/docker/images/docker-compose.yaml
However, I had to manipulate that quite a bit, and wanted to configure the settings through environment variables, so by the time I was finished, I had:
version: "3.5"
networks:
penpot:
services:
penpot-frontend:
image: "penpotapp/frontend:${VERSION}"
restart: always
ports:
- 80:80
volumes:
- penpot_assets:/opt/data/assets
depends_on:
- penpot-backend
- penpot-exporter
networks:
- penpot
environment:
- PENPOT_FLAGS=${PENPOT_FRONTEND_FLAGS}
penpot-backend:
image: "penpotapp/backend:${VERSION}"
restart: always
volumes:
- penpot_assets:/opt/data/assets
depends_on:
- penpot-postgres
- penpot-redis
networks:
- penpot
environment:
- PENPOT_FLAGS=${PENPOT_BACKEND_FLAGS}
- PENPOT_SECRET_KEY=${PENPOT_SECRET_KEY}
- PENPOT_PUBLIC_URI=${PUBLIC_URL}
- PENPOT_REDIS_URI=redis://penpot-redis/0
- PENPOT_TELEMETRY_ENABLED=false
# Database settings
- PENPOT_DATABASE_URI=postgresql://penpot-postgres/${DB_NAME}
- PENPOT_DATABASE_USERNAME=${DB_USER}
- PENPOT_DATABASE_PASSWORD=${DB_PASSWORD}
# Storage configuration
## Default configuration for assets storage: using filesystem based with all files
## stored in a docker volume.
- PENPOT_ASSETS_STORAGE_BACKEND=assets-fs
- PENPOT_STORAGE_ASSETS_FS_DIRECTORY=/opt/data/assets
## The PREPL host. Mainly used for external programMatic access to penpot backend
## (example: admin). By default it listen on `localhost` but if you are going to use
## the `admin`, you will need to uncomment this and set the host to `0.0.0.0`.
# - PENPOT_PREPL_HOST=0.0.0.0
# SMTP
- PENPOT_SMTP_DEFAULT_FROM=${SMTP_FROM}
- PENPOT_SMTP_DEFAULT_REPLY_TO=${SMTP_REPLY_TO}
- PENPOT_SMTP_HOST=${SMTP_HOST}
- PENPOT_SMTP_PORT=${SMTP_PORT}
- PENPOT_SMTP_USERNAME=${SMTP_USERNAME}
- PENPOT_SMTP_PASSWORD=${SMTP_PASSWORD}
- PENPOT_SMTP_TLS=true
- PENPOT_SMTP_SSL=false
penpot-exporter:
image: "penpotapp/exporter:${VERSION}"
restart: always
networks:
- penpot
environment:
# Don't touch it; this uses internal docker network to
# communicate with the frontend.
- PENPOT_PUBLIC_URI=http://penpot-frontend
## Redis is used for the websockets notifications.
- PENPOT_REDIS_URI=redis://penpot-redis/0
penpot-postgres:
image: "postgres:15"
restart: always
stop_signal: SIGINT
volumes:
- penpot_postgres_v15:/var/lib/postgresql/data
networks:
- penpot
environment:
- POSTGRES_INITDB_ARGS=--data-checksums
- POSTGRES_DB=${DB_NAME}
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
penpot-redis:
image: redis:7
restart: always
networks:
- penpot
volumes:
penpot_postgres_v15:
driver: local
penpot_assets:
driver: local
Env File
Now we need to provide all the settings. For this, create a .env
file at the same level as the docker-compose.yml
file with the following content:
COMPOSE_PROJECT_NAME=penpot
# Specify the penpot version here. This should be the tag used by the images in Dockerhub.
VERSION="1.17.1-1"
PUBLIC_URL="https://penpot.mydomain.com"
# Configure database details
DB_NAME=penpot
DB_USER=penpot
DB_PASSWORD=
# Configure SMTP
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_HOST=
SMTP_REPLY_TO=
SMTP_FROM=
SMTP_PORT=465
# Set a secret key with:
# python3 -c "import secrets; print(secrets.token_urlsafe(64))"
PENPOT_SECRET_KEY=
## Relevant flags for backend:
## - demo-users
## - email-verification
## - log-emails
## - log-invitation-tokens
## - login-with-github
## - login-with-gitlab
## - login-with-google
## - login-with-ldap
## - login-with-oidc
## - login-with-password
## - registration
## - secure-session-cookies
## - smtp
## - smtp-debug
## - telemetry
## - webhooks
## - prepl-server
##
## You can read more about all available flags and other
## environment variables for the backend here:
## https://help.penpot.app/technical-guide/configuration/#advanced-configuration
PENPOT_BACKEND_FLAGS="enable-login-with-password disable-registration disable-email-verification enable-smtp enable-prepl-server"
## Relevant flags for frontend:
## - demo-users
## - login-with-github
## - login-with-gitlab
## - login-with-google
## - login-with-ldap
## - login-with-oidc
## - login-with-password
## - registration
## - webhooks
##
## You can read more about all available flags on:
## https://help.penpot.app/technical-guide/configuration/#advanced-configuration
PENPOT_FRONTEND_FLAGS="enable-login-with-password"
Initial User Setup
The configurations above have disabled the ability to register, as I wanted a closed system just for me and people I manually invite.
Unfortunately, there are no initial/default users, so I needed to temporarily allow registration, before creating my initial user, and then disabling registration.
This is done by temporarily removing the disable-registration
value from the list of flags for the PENPOT_BACKEND_FLAGS
environment variable and re-deploying each time.
It might be better to go to the effort of setting this up so that one can login through your own OIDC server, which would likely allow you to manage users in a better way.
However, I don't have an easy off-the-shelf OIDC service to hand, other than setting one up through Terraform in AWS, which seems overly complicated/expensive.
No Admin Interface
I find it frustrating that there is no administrator interface. I hope that one will be added in time.
First published: 11th February 2023