はじめに
PenpotはFigma風のUIデザインツールで、オープンソースとして提供されています。
Reactで画面を実装する前にレイアウトを固めておきたかったため、今回はPenpotを自宅サーバーにDockerで構築してみました。
オンプレ環境で完結するUIデザインツールが欲しい方の参考になればうれしいです。
Penpotをオンプレ構築しようと思った理由
UIレイアウトを作る環境を自宅サーバーで完結させたかった
Reactで実際に画面を組み立てる前に、まずレイアウトだけを視覚的に固めておきたい場面があります。しかし、Figmaのようなクラウドサービスは外部依存が大きく、データを自分の環境に保管しておきたいときにやや使いづらい側面があります。
開発環境をすべて自分のコントロール下に置けるという点も、オンプレでUIデザイン環境を整えたかった理由のひとつです。
Penpotを選んだ理由は様々
- Figmaと似た操作性でレイアウトを作れる
- オープンソースなので自宅サーバー上で動かせる
- Dockerで構築できるため環境を壊しても簡単に立て直せる
- React実装時のデザイン迷いを減らせる
特に、「オンプレでUIデザインが完結する」という点は、開発環境を自宅に集約したい人には大きなメリットです。
これらの理由から、まずはDockerでPenpotを構築してみることにしました。
今回の構成と前提条件
Penpot公式の推奨構成に従い、動作の安定性が高い、オンプレ用途として最低限でありつつ十分実用的な構成を狙った環境を構築します。
サーバー環境
今回、Penpotを構築したサーバー環境は次のとおりです。
- OS:Ubuntu 22.04 LTS
- CPU/メモリ:一般的な自宅サーバー用途(特別なスペックは不要)
- ローカルネットワーク内でアクセス(オンプレ環境)
- インターネット接続:Dockerイメージ取得のため外部へ通信できること
Penpotはコンテナとして動作するため、サーバーに高い性能は求められず、Dockerが動く環境であればほとんど問題ありません。
インストール済みソフトウェア
事前に、以下のソフトウェアがインストールされていることを前提としています。
- Docker
- Docker Compose
特に、Composeが使えると複数コンテナ(PostgreSQL / Redis / Penpot本体)をまとめて扱えるため、構築が楽になります。
Dockerのインストール方法は以下の記事をご覧ください。合わせて、docker-composeも使えるようになります。
Dockerで立ち上げるサービス構成
今回の最小構成では、Penpotを次の4サービスで動かします。
- penpot-frontend(UI部分)
- penpot-backend(メイン処理)
- postgres(データベース)
- redis(キュー処理)
PenpotをDockerで構築する手順
ここからは、実際にPenpotをDockerで立ち上げる手順を紹介します。
手順はシンプルで、作業用フォルダを準備して docker-compose.yml を配置し、コンテナを起動するだけです。Docker環境さえ整っていれば、数分でPenpotを動かすことができます。
作業用ディレクトリを作成する
まずは、Penpotの構築に使用するディレクトリを作成します。
mkdir penpot-docker
cd penpot-dockerこのフォルダに docker-compose.yml を置き、データ永続化のボリュームもここから管理します。
docker-compose.yml を作成する
ここでは、Penpot公式の docker-compose をベースにしつつ、オンプレ環境で使いやすい最小構成に絞った docker-compose.yml を作成します。
最小構成とは、オンプレ環境でPenpot が動作することを目標にした、必要な 4 つのサービス(frontend / backend / postgres / valkey)だけを使い、Traefik や MinIO を省いた構成です。
version: "3.8"
networks:
penpot:
volumes:
penpot_postgres_v15:
penpot_assets:
services:
penpot-frontend:
image: "penpotapp/frontend:2.11.1"
restart: unless-stopped
ports:
- "9001:8080"
volumes:
- penpot_assets:/opt/data/assets
depends_on:
- penpot-backend
- penpot-exporter
networks:
- penpot
environment:
PENPOT_FLAGS: "disable-email-verification enable-smtp disable-secure-session-cookies"
PENPOT_HTTP_SERVER_MAX_BODY_SIZE: 31457280
PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE: 367001600
penpot-backend:
image: "penpotapp/backend:2.11.1"
restart: unless-stopped
volumes:
- penpot_assets:/opt/data/assets
depends_on:
penpot-postgres:
condition: service_healthy
penpot-valkey:
condition: service_healthy
networks:
- penpot
environment:
PENPOT_PUBLIC_URI: "http://サーバーのIPアドレスまたはホスト名:9001"
PENPOT_DATABASE_URI: "postgresql://penpot-postgres/penpot"
PENPOT_DATABASE_USERNAME: "penpot"
PENPOT_DATABASE_PASSWORD: "penpot"
PENPOT_REDIS_URI: "redis://penpot-valkey/0"
PENPOT_ASSETS_STORAGE_BACKEND: "assets-fs"
PENPOT_STORAGE_ASSETS_FS_DIRECTORY: "/opt/data/assets"
PENPOT_TELEMETRY_ENABLED: "true"
PENPOT_TELEMETRY_REFERER: "compose"
PENPOT_SECRET_KEY: "change-this-insecure-key"
PENPOT_FLAGS: "disable-email-verification"
penpot-exporter:
image: "penpotapp/exporter:2.11.1"
restart: unless-stopped
depends_on:
penpot-valkey:
condition: service_healthy
networks:
- penpot
environment:
PENPOT_SECRET_KEY: "change-this-insecure-key"
PENPOT_PUBLIC_URI: "http://penpot-frontend:8080"
PENPOT_REDIS_URI: "redis://penpot-valkey/0"
penpot-postgres:
image: "postgres:15"
restart: unless-stopped
stop_signal: SIGINT
healthcheck:
test: ["CMD-SHELL", "pg_isready -U penpot"]
interval: 2s
timeout: 10s
retries: 5
start_period: 2s
volumes:
- penpot_postgres_v15:/var/lib/postgresql/data
networks:
- penpot
environment:
- POSTGRES_INITDB_ARGS=--data-checksums
- POSTGRES_DB=penpot
- POSTGRES_USER=penpot
- POSTGRES_PASSWORD=penpot
penpot-valkey:
image: "valkey/valkey:8.1"
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "valkey-cli ping | grep PONG"]
interval: 1s
timeout: 3s
retries: 5
start_period: 3s
networks:
- penpot
environment:
- VALKEY_EXTRA_FLAGS=--maxmemory 128mb --maxmemory-policy volatile-lfu
penpot-mailcatch:
image: "sj26/mailcatcher:latest"
restart: unless-stopped
expose:
- "1025"
ports:
- "1080:1080"
networks:
- penpotこの構成のポイント
- 執筆時点では Penpot 本体の安定版を 2.11.1 として固定している(frontend / backend / exporter は同じバージョンを指定)
- データベースは公式と同じく PostgreSQL 15 を利用している
- キャッシュ兼通知には、公式が Redis の代わりに採用している Valkey 8.1(
valkey/valkey:8.1) を使用している PENPOT_REDIS_URIの値はredis://penpot-valkey/0のままだが、これは Valkey が Redis 互換で動作するためで、公式 compose と同じ指定PENPOT_PUBLIC_URIはあとでブラウザからアクセスするときの URL に合わせて、自分のサーバーの IP アドレスやホスト名に書き換えるPENPOT_SECRET_KEYはサンプル値のままだとセキュリティ的に弱いため、本番運用する場合はランダムな文字列に置き換えるPENPOT_FLAGS=disable-email-verificationを指定して メールアドレスの確認機能を無効化
この構成の公式との差分とバージョンの注意点
Traefik や MinIO は省いてます。公式リポジトリの docker-compose には、Traefik や MinIOの記載がありますが、これは、外部公開向けのサービスです。今回は、オンプレ上で動作させる最小構成で組むことが目的であるため、Traefik や MinIO は省いた構成になっています。
最新の情報は公式の Release や docker-compose を確認して、合わせるようにしてください。
なお、Penpot 本体の最新バージョン番号は docker-compose.yml には明記されていないため、
最新版を確認する場合は公式の Release ページをご覧ください。
コンテナを起動する
以下のコマンドでコンテナをバックグラウンド起動します。
docker compose up -d初回はイメージのダウンロードが入るため、数十秒ほどかかります。
状態を確認する
起動後、各コンテナの状態を確認します。
docker compose psすべてのサービスが running になっていればOKです。以下のサービス名を確認してください。
- penpot-frontend
- penpot-backend
- penpot-postgres
- penpot-redis
どれかが exit になっている場合はログを確認してみてください。
docker logs penpot-backend※ penpot-backend サービスがexit時の例です
(任意)サーバー再起動時も自動起動させたい場合
自宅サーバーで運用する場合、再起動後に自動起動にすると便利です。
その場合、Compose ファイルの各サービスに以下の例を参考に追加します。
penpot-backend:
image: penpotapp/penpot-backend:latest
restart: unless-stoppedブラウザからアクセスして初期設定する
コンテナの起動ができたら、次はブラウザからPenpotにアクセスして初期設定を行います。ここでは、管理者ユーザーの作成と、ログインできるところまでを確認します。
初回アクセス用のURLを開く
まずはクライアントPCのブラウザから、PenpotのURLを開きます。
http://サーバーのIPアドレス:9001docker-compose.yml で 9001:80 を指定しているため、ブラウザからはポート9001でアクセスします。
以下の画面が出れば成功です。

もしこの時点でページが開かない場合は、次の点を確認します。
- サーバーのIPアドレスが正しいか
docker compose psでpenpot-frontendがrunningになっているか- ファイアウォールでポート9001がブロックされていないか
管理者ユーザーを作成する
初回アクセス時は、Penpotのセットアップ画面が表示されます。
ここで、最初のユーザー(=管理者)を作成します。
ログインボタンのすぐ下の、Create an accountをクリックしてユーザー登録します。
入力する内容の例は次のとおりです。
- 名前
- メールアドレス
- パスワード
このユーザーがPenpot全体を管理するアカウントになるので、忘れないメールアドレスとパスワードを設定しておきます。今回はメール認証をしない構成にしていますので、メールチェックすることなくユーザー作成が出来ていると思います。
初回セットアップ
Penpot では初回ログイン時に 3ステップの簡単なセットアップ画面が表示されます。
この画面の内容は Penpot のバージョンによって異なるそうですが、アンケートの様なもので機能に影響はありません。
日本語フォントを設定する
まずは日本語の設定をしましょう。画面左したのユーザー名をクリックすると表示されるYour accountをクリック。SettingsタグからLANGUAGEを日本語に変更します。※ 部分的にしか日本語化されませんでした・・・
使ってみた感想
思ったより難しかった【最初の壁はここ】
いざ自分でゼロから画面を作ってみようとすると、「背景を置く」「文字を書く」くらいは何とかできても、そこから UI として形にするのが思ったより難しいことに気づきました。
なんだこれは?と思われるかもしれませんが、今回試しに触ってみたのがこちらです。

背景画像を敷いて、タイトルを置いて、右側にメニューの枠を作ってみたのですが、バランスが難しく、UIデザインの奥深さを痛感しました。
まずはライブラリを使うのが正解【UI設計の基礎が分かる】
ライブラリからダウンロードして取り込んでみたのがこちらです。

分かったことは、左側のツリーを見ると段落のようになっていることが分かります。ブロックをいくつか作成し、その中に更にパーツを作っていくように作成されています。こういったライブラリを参考に使い方を学ぶのが正解と感じました。
まとめ:Penpotはオンプレでも手軽に動く、使い方には慣れが必要
今回、Linux を入れたミニPC上に Penpot を Docker で構築し、クライアント側は Windows からアクセスしてみましたが、動作は非常に軽快でした。
オンプレミス環境でも問題なく使えることを実感できました。
一方で、実際にUIをゼロから作ろうとすると、背景を置いたり文字を書く程度なら簡単でも、UIとして形にするには慣れが必要で、デザインの奥深さも感じました。
ただし、Penpot には便利なライブラリが多数用意されており、プロが作ったUI構造を参考にしながら学べるため、最初の習得にはライブラリを活用するのが正解だと感じました。
オンプレで UI デザイン環境を構築したい方には、Penpot は「軽快に動く × 自由度が高い」おすすめの選択肢です。


コメント