diff --git a/modules/apps/penpot/default.nix b/modules/apps/penpot/default.nix new file mode 100644 index 0000000..0ec01cd --- /dev/null +++ b/modules/apps/penpot/default.nix @@ -0,0 +1,220 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.homelab.apps.penpot; + + networkName = "penpot"; + UID = config.users.users.apps.uid; + GID = config.users.groups.apps.gid; + + version = "2.5.4"; + + srvPath = "/srv/penpot"; + assetsPath = "/opt/data/assets"; + + PENPOT_FLAGS = "enable-smtp enable-prepl-server disable-secure-session-cookies disable-onboarding disable-registration"; + # Max body size (30MiB); Used for plain requests, should never be + # greater than multi-part size + PENPOT_HTTP_SERVER_MAX_BODY_SIZE = "31457280"; + # Max multipart body size (350MiB) + PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE = "367001600"; + + dbName = "penpot"; + dbUser = "penpot"; + dbPass = "penpot"; + + docker = config.virtualisation.oci-containers.containers; +in { + options.homelab.apps.penpot.enable = lib.mkEnableOption "Penpot using Docker"; + + config = lib.mkIf cfg.enable { + homelab = { + users.apps.enable = true; + virtualisation.containers.enable = true; + }; + + fileSystems."${srvPath}" = { + device = "192.168.0.11:/mnt/SMALL/CONFIG/PENPOT"; + fsType = "nfs"; + options = [ + "rw" + "nfsvers=4.2" + "sync" "hard" "timeo=600" + "retrans=2" + "_netdev" + "nosuid" "tcp" + ]; + }; + + # Make sure the Docker network exists. + systemd.services."docker-${networkName}-create-network" = lib.mkIf cfg.enable { + description = "Create Docker network for ${networkName}"; + requiredBy = [ + "docker-penpot-frontend.service" + "docker-penpot-backend.service" + "docker-penpot-exporter.service" + "docker-penpot-postgres.service" + "docker-penpot-redis.service" + ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + if ! ${pkgs.docker}/bin/docker network ls | grep -q ${networkName}; then + ${pkgs.docker}/bin/docker network create ${networkName} + fi + ''; + }; + + virtualisation.oci-containers.containers = let + frontendPort = 8080; + redisUri = "redis://${docker.penpot-redis.hostname}/0"; + in { + penpot-frontend = { + hostname = "penpot-frontend"; + image = "penpotapp/frontend:${version}"; + # user = "${toString UID}:${toString GID}"; + user = "0:${toString GID}"; + ports = [ + # "9001:${toString frontendPort}/tcp" + ]; + extraOptions = [ + "--network=${networkName}" + ]; + environment = { + inherit PENPOT_FLAGS; + inherit PENPOT_HTTP_SERVER_MAX_BODY_SIZE; + inherit PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE; + }; + volumes = [ + "${srvPath}:${assetsPath}" + ]; + dependsOn = [ + docker.penpot-backend.hostname + docker.penpot-exporter.hostname + ]; + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.penpot.rule" = "Host(`penpot.depeuter.dev`)"; + "traefik.http.services.penpot.loadbalancer.server.port" = toString frontendPort; + "traefik.tls.options.default.minVersion" = "VersionTLS13"; + }; + autoStart = true; + }; + penpot-backend = { + hostname = "penpot-backend"; + image = "penpotapp/backend:latest"; + # user = "${toString UID}:${toString GID}"; + user = "0:${toString GID}"; + extraOptions = [ + "--network=${networkName}" + ]; + environmentFiles = [ + /home/admin/.penpot.secret + ]; + environment = { + inherit PENPOT_FLAGS; + inherit PENPOT_HTTP_SERVER_MAX_BODY_SIZE; + inherit PENPOT_HTTP_SERVER_MAX_MULTIPART_BODY_SIZE; + + PENPOT_PUBLIC_URI = "https://penpot.depeuter.dev"; + + ## Database connection parameters. Don't touch them unless you are using custom + ## postgresql connection parameters. + + PENPOT_DATABASE_URI = "postgresql://${docker.penpot-postgres.hostname}/${dbName}"; + PENPOT_DATABASE_USERNAME = dbUser; + PENPOT_DATABASE_PASSWORD = dbPass; + + ## Redis is used for the websockets notifications. Don't touch unless the redis + ## container has different parameters or different name. + + PENPOT_REDIS_URI = redisUri; + + ## 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 = assetsPath; + + ## Telemetry. When enabled, a periodical process will send anonymous data about this + ## instance. Telemetry data will enable us to learn how the application is used, + ## based on real scenarios. If you want to help us, please leave it enabled. You can + ## audit what data we send with the code available on github. + + PENPOT_TELEMETRY_ENABLED = "false"; + PENPOT_TELEMETRY_REFERER = "compose"; + + # PENPOT_SMTP_HOST = "smtp.gmail.com"; + # PENPOT_SMTP_PORT = "465"; + # PENPOT_SMTP_USERNAME: "kmtl.hugo@gmail.com"; + # PENPOT_SMTP_PASSWORD: + # PENPOT_SMTP_TLS: true + }; + volumes = [ + "${srvPath}:${assetsPath}" + ]; + dependsOn = [ + docker.penpot-postgres.hostname + docker.penpot-redis.hostname + ]; + autoStart = true; + }; + penpot-exporter = { + hostname = "penpot-exporter"; + image = "penpotapp/exporter:latest"; + extraOptions = [ + "--network=${networkName}" + ]; + environment = { + # Don't touch it; this uses an internal docker network to + # communicate with the frontend. + PENPOT_PUBLIC_URI = "http://${docker.penpot-frontend.hostname}:${toString frontendPort}"; + + ## Redis is used for the websockets notifications. + PENPOT_REDIS_URI = redisUri; + }; + dependsOn = [ + docker.penpot-redis.hostname + ]; + autoStart = true; + }; + penpot-postgres = { + hostname = "penpot-postgres"; + image = "postgres:15"; + extraOptions = [ + "--network=${networkName}" + "--health-cmd='pg_isready -U ${dbUser}'" + "--health-interval=2s" + "--health-retries=5" + "--health-timeout=10s" + "--health-start-period=2s" + ]; + environment = { + POSTGRES_INITDB_ARGS = "--data-checksums"; + POSTGRES_DB = dbName; + POSTGRES_USER = dbUser; + POSTGRES_PASSWORD = dbPass; + }; + volumes = [ + "penpot_postgres_v15:/var/lib/postgresql/data" + ]; + autoStart = true; + }; + penpot-redis = { + hostname = "penpot-redis"; + image = "redis:7.2"; + extraOptions = [ + "--network=${networkName}" + "--health-cmd='redis-cli ping | grep PONG'" + "--health-interval=1s" + "--health-retries=5" + "--health-timeout=3s" + "--health-start-period=3s" + ]; + autoStart = true; + }; + }; + }; +}