Files
kurogeek 08b5496980 Package Penpot 2.18.3 for Nix with NixOS module; afk devShell
Vendored from debling/nix-penpot (MIT). Fixes on top:
- pnpm fetchers: drop --config.fetch-* flags (UND_ERR_INVALID_ARG on pnpm 11.27)
  and pin real store hashes (frontend x3, exporter, mcp)
- deps-lock.json: add transitive funcool/beicon2 v2.0 so fake-git resolves
  potok2's pin during the shadow-cljs classpath build
- expose frontend pnpm stores via passthru for rehashing
- x86_64-linux only; devShell ships afk, jj, git
2026-10-20 17:45:02 +00:00

144 lines
6.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# penpot-nix
Nix packages and a NixOS module for self-hosting [Penpot](https://penpot.app)
(pinned to release **2.18.3**). Every component is built from upstream
source: the Clojure API backend, the static frontend (served by nginx), the
headless-Chromium exporter, the MCP server and the Rust/WASM renderer.
One module wires the stack together with PostgreSQL and Valkey, either
provisioned locally or pointed at infrastructure you already run.
Derived from [debling/nix-penpot](https://github.com/debling/nix-penpot)
(MIT, see [LICENSE](LICENSE)). `x86_64-linux` only.
## Packages
| Attribute | Output |
|-----------------------------|------------------------------------------------------------------------|
| `penpot-backend` | `bin/penpot-backend` (JVM wrapper), `bin/penpot-manage` |
| `penpot-frontend` | `dist/` static bundle (+ `plugins/`, `plugins/mcp/`), `config.js` |
| `penpot-exporter` | `bin/penpot-exporter` (node + nixpkgs chromium) |
| `penpot-mcp` | `bin/penpot-mcp` |
| `penpot-render-wasm` | `render-wasm.{js,wasm}`, `shared.js`, `worker/render.js` (frontend) |
| `penpot-render-wasm-export` | export flavor of the renderer (unused on 2.18.x) |
The same packages are exposed as an overlay (`overlays.default`:
`pkgs.penpot-backend`, `pkgs.penpot-frontend`, `pkgs.penpot-exporter`,
`pkgs.penpot-mcp`). The module's package defaults resolve through the
overlay, so it is required.
## Deploying on NixOS
```nix
# flake.nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
penpot-nix.url = "git+https://<this repo>";
};
outputs = { self, nixpkgs, penpot-nix }: {
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
{ nixpkgs.overlays = [ penpot-nix.overlays.default ]; }
penpot-nix.nixosModules.default
];
};
};
}
```
```nix
# configuration.nix
{
services.penpot = {
enable = true;
publicUri = "https://penpot.example.com";
secretKeyFile = "/run/secrets/penpot-secret-key";
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
}
```
That is a complete deployment: PostgreSQL and Valkey are provisioned
locally, the nginx vhost is generated, exporter and MCP run behind it.
Secrets are files loaded through systemd credentials; generate the master
key once (`openssl rand -base64 64 | tr -d '\n'`) and manage it with
agenix/sops-nix.
Commonly tuned options (all documented inline in
[`modules/penpot.nix`](modules/penpot.nix)):
| Option | Default | What it does |
|----------------------------------|-----------------------------|-------------------------------------------------------------|
| `publicUri` | – (required) | Public URL of the instance |
| `secretKeyFile` | – (required) | Master secret key file |
| `flags` | `[ "enable-prepl-server" ]` | Upstream feature flags |
| `admins` | `[ ]` | Emails granted admin on login |
| `database.createLocally` | `true` | Local PostgreSQL, or set `database.uri` for an external one |
| `redis.createLocally` | `true` | Local Valkey, or set `redis.uri` |
| `storage.backend` | `"fs"` | `"fs"` or `"s3"` (+ endpoint/bucket/keys) |
| `smtp.*` / `mailpit.enable` | off | Outgoing email, or a local throwaway SMTP sink |
| `exporter.enable` / `mcp.enable` | `true` | Toggle the auxiliary services |
| `nginx.forceHttps` | `false` | Force HTTPS (configure TLS yourself) |
### Users and admins
No default credentials. Register through the UI, or on the backend host:
```bash
penpot-manage create-profile -n "Jane Doe" -e jane@example.org -p 'secret'
```
Admin rights come from `services.penpot.admins = [ "jane@example.org" ];`.
## Trying it in a VM
```bash
nix build .#nixosConfigurations.penpot-vm.config.system.build.vm
./result/bin/run-penpot-vm-vm
```
Host port 8080 → nginx, 8025 → mailpit UI. `curl http://127.0.0.1:8080/readyz`
once the backend is up (~1–2 min). Needs ~3 GB RAM.
## Development
```bash
direnv allow # or: nix develop — devShell ships the afk harness, jj, git
nix flake check --no-build
nix build .#checks.x86_64-linux.penpot-vm-test # end-to-end VM test
nix fmt
```
Development runs under [afk](https://github.com/DavHau/afk) (`afk` is on
PATH in the devShell).
## Updating Penpot
1. Bump `penpot.url` **and** `penpotVersion` in `flake.nix` (upstream's
`package.json` version is stale, so it is pinned by hand).
2. Regenerate `deps-lock.json` with clj-nix from a writable copy of the
penpot source with the `RELEASE` pins from `packages/frontend.nix`
(`pinDepsEdn`) applied:
```bash
nix run github:jlesquembre/clj-nix/<pinned-rev>#deps-lock -- \
--deps-include backend/deps.edn --deps-include common/deps.edn \
--deps-include frontend/deps.edn --deps-include exporter/deps.edn \
--alias-exclude outdated --alias-exclude jvm-repl
```
3. Rehash the fixed-output derivations (set to `lib.fakeHash`, build, copy
`got:`): `penpot-frontend.{frontendPnpmDeps,pluginsPnpmDeps,mcpPnpmDeps}`,
`penpot-exporter.pnpmDeps`, `penpot-mcp.pnpmDeps`,
`penpot-backend.builtinTemplates` (after `nix flake update penpot-files`),
and `cargoDeps` / Rust / Skia hashes in `packages/render-wasm.nix` if
`render-wasm/Cargo.lock`, the Rust version or the Skia URL changed.
4. Rebase `packages/patches/*` if `frontend/src/app/plugins/library.cljs`
moved.
## License
Nix code: MIT ([LICENSE](LICENSE)). Penpot: MPL-2.0. The remaining stack
(PostgreSQL, Valkey, Chromium, …) ships under its own licenses.