Unverified Commit a45dc99b authored by Sandro Jäckel's avatar Sandro Jäckel Committed by GitHub
Browse files

Merge pull request #287565 from RatCornu/pingvin-share

parents 7d65cd21 edf938b9
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -17165,11 +17165,11 @@
    name = "Szymon Scholz";
  };
  ratcornu = {
    email = "ratcornu@skaven.org";
    email = "ratcornu+programmation@skaven.org";
    github = "RatCornu";
    githubId = 98173832;
    name = "Balthazar Patiachvili";
    matrix = "@ratcornu:skweel.skaven.org";
    matrix = "@ratcornu:skaven.org";
    keys = [ { fingerprint = "1B91 F087 3D06 1319 D3D0  7F91 FA47 BDA2 6048 9ADA"; } ];
  };
  ratsclub = {
+2 −0
Original line number Diff line number Diff line
@@ -61,6 +61,8 @@

- [wg-access-server](https://github.com/freifunkMUC/wg-access-server/), an all-in-one WireGuard VPN solution with a web ui for connecting devices. Available at [services.wg-access-server](#opt-services.wg-access-server.enable).

- [Pingvin Share](https://github.com/stonith404/pingvin-share), a self-hosted file sharing platform and an alternative for WeTransfer. Available as [services.pingvin-share](#opt-services.pingvin-share.enable).

- [Envision](https://gitlab.com/gabmus/envision), a UI for building, configuring and running Monado, the open source OpenXR runtime. Available as [programs.envision](#opt-programs.envision.enable).

- [Localsend](https://localsend.org/), an open source cross-platform alternative to AirDrop. Available as [programs.localsend](#opt-programs.localsend.enable).
+1 −0
Original line number Diff line number Diff line
@@ -1467,6 +1467,7 @@
  ./services/web-apps/phylactery.nix
  ./services/web-apps/photoprism.nix
  ./services/web-apps/pict-rs.nix
  ./services/web-apps/pingvin-share.nix
  ./services/web-apps/plantuml-server.nix
  ./services/web-apps/plausible.nix
  ./services/web-apps/powerdns-admin.nix
+43 −0
Original line number Diff line number Diff line
# Pingvin Share {#module-services-pingvin-share}

A self-hosted file sharing platform and an alternative for WeTransfer.

## Configuration {#module-services-pingvin-share-basic-usage}

By default, the module will execute Pingvin Share backend and frontend on the ports 8080 and 3000.

I will run two systemd services named `pingvin-share-backend` and `pingvin-share-frontend` in the specified data directory.

Here is a basic configuration:

```nix
{
  services-pingvin-share = {
    enable = true;

    openFirewall = true;

    backend.port = 9010;
    frontend.port = 9011;
  };
}
```

## Reverse proxy configuration {#module-services-pingvin-share-reverse-proxy-configuration}

The prefered method to run this service is behind a reverse proxy not to expose an open port. This, you can configure Nginx such like this:

```nix
{
  services-pingvin-share = {
    enable = true;

    hostname = "pingvin-share.domain.tld";
    https = true;

    nginx.enable = true;
  };
}
```

Furthermore, you can increase the maximal size of an uploaded file with the option [services.nginx.clientMaxBodySize](#opt-services.nginx.clientMaxBodySize).
+226 −0
Original line number Diff line number Diff line
{
  config,
  pkgs,
  lib,
  ...
}:

let
  cfg = config.services.pingvin-share;
  inherit (lib)
    mkOption
    mkEnableOption
    mkIf
    mkPackageOption
    types
    ;
in

{
  options = {
    services.pingvin-share = {
      enable = mkEnableOption "Pingvin Share, a self-hosted file sharing platform";

      user = mkOption {
        type = types.str;
        default = "pingvin";
        description = ''
          User account under which Pingvin Share runs.
        '';
      };

      group = mkOption {
        type = types.str;
        default = "pingvin";
        description = ''
          Group under which Pingvin Share runs.
        '';
      };

      openFirewall = mkOption {
        type = types.bool;
        default = false;
        description = ''
          Whether to open the firewall for the port in {option}`services.pingvin-share.frontend.port`.
        '';
      };

      dataDir = mkOption {
        type = types.path;
        default = "/var/lib/pingvin-share";
        example = "/var/lib/pingvin";
        description = ''
          The path to the data directory in which Pingvin Share will store its data.
        '';
      };

      hostname = mkOption {
        type = types.str;
        default = "localhost:${toString cfg.backend.port}";
        defaultText = lib.literalExpression "localhost:\${options.services.pingvin-share.backend.port}";
        example = "pingvin-share.domain.tdl";
        description = ''
          The domain name of your instance. If null, the redirections will be made to localhost.
        '';
      };

      https = mkOption {
        type = types.bool;
        default = false;
        example = true;
        description = ''
          Whether to enable HTTPS for the domain.
        '';
      };

      backend = {
        package = mkPackageOption pkgs [
          "pingvin-share"
          "backend"
        ] { };

        port = mkOption {
          type = types.port;
          default = 8080;
          example = 9000;
          description = ''
            The port that the backend service of Pingvin Share will listen to.
          '';
        };
      };

      frontend = {
        package = mkPackageOption pkgs [
          "pingvin-share"
          "frontend"
        ] { };

        port = mkOption {
          type = types.port;
          default = 3000;
          example = 8000;
          description = ''
            The port that the frontend service of Pingvin Share will listen to.
          '';
        };
      };

      nginx = {
        enable = mkEnableOption "a Nginx reverse proxy for Pingvin Share.";
      };
    };
  };

  config = mkIf cfg.enable {

    users.groups = mkIf (cfg.group == "pingvin") { pingvin = { }; };

    users.users = mkIf (cfg.user == "pingvin") {
      pingvin = {
        group = cfg.group;
        description = "Pingvin Share daemon user";
        isSystemUser = true;
      };
    };

    networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.frontend.port ];

    systemd.services.pingvin-share-backend = {
      description = "Backend service of Pingvin Share, a self-hosted file sharing platform.";

      wantedBy = [
        "multi-user.target"
        "pingvin-share-frontend.service"
      ];
      before = [ "pingvin-share-frontend.service" ];
      after = [
        "network.target"
        "network-online.target"
      ];
      wants = [ "network-online.target" ];

      environment = {
        PRISMA_SCHEMA_ENGINE_BINARY = "${pkgs.prisma-engines}/bin/schema-engine";
        PRISMA_QUERY_ENGINE_BINARY = "${pkgs.prisma-engines}/bin/query-engine";
        PRISMA_QUERY_ENGINE_LIBRARY = "${pkgs.prisma-engines}/lib/libquery_engine.node";
        PRISMA_INTROSPECTION_ENGINE_BINARY = "${pkgs.prisma-engines}/bin/introspection-engine";
        PRISMA_FMT_BINARY = "${pkgs.prisma-engines}/bin/prisma-fmt";
        PORT = toString cfg.backend.port;
        DATABASE_URL = "file:${cfg.dataDir}/pingvin-share.db?connection_limit=1";
        DATA_DIRECTORY = cfg.dataDir;
      };

      path = with pkgs; [
        cfg.backend.package
        openssl
        prisma-engines
      ];

      serviceConfig = {
        User = cfg.user;
        Group = cfg.group;
        Type = "simple";
        Restart = "on-failure";
        ExecStartPre = [
          "${cfg.backend.package}/node_modules/.bin/prisma migrate deploy"
          "${cfg.backend.package}/node_modules/.bin/prisma db seed"
        ];
        ExecStart = "${cfg.backend.package}/node_modules/.bin/ts-node dist/src/main";
        StateDirectory = mkIf (cfg.dataDir == "/var/lib/pingvin-share") "pingvin-share";
        WorkingDirectory = cfg.backend.package;
      };
    };

    systemd.services.pingvin-share-frontend = {
      description = "Frontend service of Pingvin Share, a self-hosted file sharing platform.";

      wantedBy = [ "multi-user.target" ];
      wants = [
        "network-online.target"
        "pingvin-share-backend.service"
      ];
      after = [
        "network-online.target"
        "pingvin-share-backend.service"
      ];

      environment = {
        PORT = toString cfg.frontend.port;
        API_URL = "${if cfg.https then "https" else "http"}://${cfg.hostname}";
      };
      path = [ cfg.frontend.package ];

      serviceConfig = {
        User = cfg.user;
        Group = cfg.group;
        Type = "simple";
        Restart = "on-failure";
        ExecStart = "${cfg.frontend.package}/node_modules/.bin/next start";
        StateDirectory = mkIf (cfg.dataDir == "/var/lib/pingvin-share") "pingvin-share";
        WorkingDirectory = cfg.frontend.package;
      };
    };

    services.nginx = mkIf cfg.nginx.enable {
      enable = lib.mkDefault true;
      virtualHosts."${cfg.hostname}" = {
        enableACME = cfg.https;
        forceSSL = cfg.https;

        locations."/" = {
          proxyPass = "http://localhost:${toString cfg.frontend.port}";
          recommendedProxySettings = true;
        };
        locations."/api" = {
          proxyPass = "http://localhost:${toString cfg.backend.port}";
          recommendedProxySettings = true;
        };
      };
    };
  };

  meta = {
    maintainers = with lib.maintainers; [ ratcornu ];
    doc = ./pingvin-share.md;
  };
}
Loading