From c1af9a9ca7646c403d565af5fee00c90125aa3cd Mon Sep 17 00:00:00 2001 From: Anish Lakhwara Date: Sun, 14 Jul 2024 20:20:49 -0700 Subject: [PATCH] fix(box): wallabag is working again!!! --- hosts/profiles/wallabag/default.nix | 80 +----- modules/nixos/default.nix | 1 + modules/nixos/wallabag.nix | 432 ++++++++++++++-------------- overlays/default.nix | 9 + pkgs/default.nix | 4 + pkgs/wallabag-data.patch | 51 +++- pkgs/wallabag.nix | 4 +- 7 files changed, 281 insertions(+), 300 deletions(-) diff --git a/hosts/profiles/wallabag/default.nix b/hosts/profiles/wallabag/default.nix index e2b3523f..119c9b5b 100644 --- a/hosts/profiles/wallabag/default.nix +++ b/hosts/profiles/wallabag/default.nix @@ -1,10 +1,10 @@ { self, pkgs, config, lib, ... }: { - # age.secrets.wallabag-password.file = "${self}/secrets/wallabag-password.age"; - # age.secrets.wallabag-secret.file = "${self}/secrets/wallabag-secret.age"; - # age.secrets.wallabag-password.owner = "wallabag"; - # age.secrets.wallabag-secret.owner = "wallabag"; + age.secrets.wallabag-password.file = "${self}/secrets/wallabag-password.age"; + age.secrets.wallabag-secret.file = "${self}/secrets/wallabag-secret.age"; + age.secrets.wallabag-password.owner = "wallabag"; + age.secrets.wallabag-secret.owner = "wallabag"; services.postgresql = { enable = true; package = pkgs.postgresql_15; @@ -18,74 +18,20 @@ } ]; authentication = '' - local wallabag all md5 + local wallabag all peer ''; }; services.wallabag = { enable = true; - hostName = "read.mossnet.lan"; + domain = "read.mossnet.lan"; + virtualHost.enable = true; package = pkgs.my-wallabag; - dataDir = "/var/lib/wallabag"; - conf = '' - # This file is a "template" of what your parameters.yml file should look like - parameters: - database_driver: pdo_pgsql - database_host: localhost - database_port: ~ - database_name: wallabag - database_user: wallabag - database_password: wallabag - # For SQLite, database_path should be "%kernel.project_dir%/data/db/wallabag.sqlite" - database_path: ~ - database_table_prefix: wallabag_ - database_socket: null - # with PostgreSQL and SQLite, you must set "utf8" - database_charset: utf8 - - domain_name: http://read.mossnet.lan - server_name: "mossnet wallabag instance" - - mailer_dsn: null:// - locale: en - - # A secret key that's used to generate certain security-related tokens - secret: SAFGOECRIlfal89oe6u0(*^dsaaih961 - - # two factor stuff - twofactor_auth: false - twofactor_sender: no-reply@wallabag.org - - # fosuser stuff - fosuser_registration: false - fosuser_confirmation: true - - # how long the access token should live in seconds for the API - fos_oauth_server_access_token_lifetime: 3600 - # how long the refresh token should life in seconds for the API - fos_oauth_server_refresh_token_lifetime: 1209600 - - from_email: ops@sealight.xyz - - rss_limit: 50 - - # RabbitMQ processing - rabbitmq_host: localhost - rabbitmq_port: 5672 - rabbitmq_user: guest - rabbitmq_password: guest - rabbitmq_prefetch_count: 10 - - # Redis processing - redis_scheme: tcp - redis_host: localhost - redis_port: 6379 - redis_path: null - redis_password: null - - # sentry logging - sentry_dsn: ~ - ''; + # Systemd now defaults to /var/lib? + # dataDir = "/var/lib/wallabag"; + parameters = { + "env(SECRET_FILE)" = config.age.secrets.wallabag-secret.path; + secret = "%env(file:resolve:SECRET_FILE)%"; + }; }; - # networking.firewall.allowedTCPPorts = [ 8080 ]; } diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index d4efdc56..38962ffa 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -9,5 +9,6 @@ wireguard = import ./wireguard.nix; backup = import ./backup.nix; ulogger-server = import ./ulogger.nix; + blogg = import ./blogging.nix; # microbin = import ./microbin.nix; # includide in 23.11 } diff --git a/modules/nixos/wallabag.nix b/modules/nixos/wallabag.nix index 14bfe26e..f2a15473 100644 --- a/modules/nixos/wallabag.nix +++ b/modules/nixos/wallabag.nix @@ -1,253 +1,245 @@ -{ config, options, lib, pkgs, ... }: - -with lib; +{ config, lib, pkgs, ... }: let + # Based on https://github.com/wallabag/wallabag/blob/2.6.6/app/config/parameters.yml.dist + settings = { + database_driver = "${cfg.database_type}"; + database_host = null; + database_port = 5432; + database_name = "wallabag"; + database_user = "wallabag"; + database_password = null; + database_path = null; + database_table_prefix = "wallabag_"; + database_socket = "/run/postgresql"; + database_charset = "utf8"; + + domain_name = "http://${cfg.domain}"; + server_name = "Wallabag"; + + # Needs an explicit command since Symfony version used by Wallabag does not yet support the `native` transport + # and the `sendmail` transport does not respect `sendmail_path` configured in `php.ini`. + mailer_dsn = "sendmail://default?command=/run/wrappers/bin/sendmail%%20-t%%20-i"; + + locale = "en"; + + # A secret key that's used to generate certain security-related tokens. + # "env(SECRET_FILE)" = "/run/secrets/wallabag"; + # secret = "%env(file:resolve:SECRET_FILE)%"; + + # two factor stuff + twofactor_auth = false; + twofactor_sender = ""; + + # fosuser stuff + fosuser_registration = false; + fosuser_confirmation = false; + + # how long the access token should live in seconds for the API + fos_oauth_server_access_token_lifetime = 3600; + # how long the refresh token should life in seconds for the API + fos_oauth_server_refresh_token_lifetime = 1209600; + + from_email = "wallabag@read.mossnet.lan"; + + # RabbitMQ processing + redis_scheme = "unix"; + redis_host = ""; # Ignored for unix scheme + redis_port = 0; # Ignored for unix scheme + redis_path = config.services.redis.servers.wallabag.unixSocket; + redis_password = null; + + # Redis processing + rabbitmq_host = ""; + rabbitmq_port = 0; + rabbitmq_user = ""; + rabbitmq_password = ""; + rabbitmq_prefetch_count = 0; + + # sentry logging + sentry_dsn = null; + } // cfg.parameters; + + php = cfg.php.package.withExtensions ({ enabled, all }: enabled ++ (with all; [ + imagick + tidy + ])); + + commonServiceConfig = { + CacheDirectory = "wallabag"; + # Stores sessions. + CacheDirectoryMode = "700"; + ConfigurationDirectory = "wallabag"; + LogsDirectory = "wallabag"; + StateDirectory = "wallabag"; + # Stores site-credentials-secret-key.txt. + StateDirectoryMode = "700"; + }; + cfg = config.services.wallabag; +in { + options.services.wallabag = with lib; { + enable = mkEnableOption (mdDoc "Wallabag read-it-later service"); - poolName = "wallabag"; + package = mkOption { + type = types.package; + default = pkgs.wallabag; + }; - configFile = pkgs.writeTextFile { - name = "wallabag-config"; - text = cfg.conf; - destination = "/app/config/parameters.yml"; + php.package = mkOption { + type = types.package; + default = pkgs.php; + }; + + parameters = mkOption { + type = types.attrsOf types.str; + default = {}; + description = mdDoc "Parameters to override from the default. See for values."; + }; + + database_type = mkOption { + type = types.enum [ + "pdo_sqlite3" + "pdo_pgsql" + ]; + default = if config.services.postgresql.enable + then "pdo_pgsql" + else "pdo_sqlite3"; + defaultText = '' + if config.services.postgresql.enable + then "pdo_pgsql" + else "pdo_sqlite3" + ''; + description = mdDoc '' + The database engine name. Can be pdo_sqlite3 or pdo_pgsql. + ''; + }; + + domain = mkOption { + type = types.str; + description = "Bare domain name for Wallabag"; + }; + + virtualHost.enable = mkEnableOption (mdDoc "Define nginx virtualhost for Wallabag"); }; - appDir = pkgs.buildEnv { - name = "wallabag-app-dir"; - ignoreCollisions = true; - checkCollisionContents = false; - paths = [ configFile "${cfg.package}" ]; - pathsToLink = [ "/app" "/src" "/translations" ]; - }; - - # See there for available commands: - # https://doc.wallabag.org/en/admin/console_commands.html - # A user can be made admin with the fos:user:promote --super command - console = pkgs.writeShellScriptBin "wallabag-console" '' - export WALLABAG_DATA="${cfg.dataDir}" - cd "${cfg.dataDir}" - ${pkgs.php}/bin/php ${cfg.package}/bin/console --env=prod $@ - ''; - -in -{ - - options = { - - services.wallabag = { - enable = mkEnableOption "wallabag"; - - user = mkOption { - type = types.str; - default = "nginx"; - description = '' - User account under which both the update daemon and the web-application run. - ''; - }; - - dataDir = mkOption { - type = types.path; - default = "/var/lib/wallabag"; - description = '' - Data directory. - ''; - }; - - package = mkOption { - type = types.package; - default = pkgs.wallabag; - description = '' - Wallabag package to use. - ''; - }; - - hostName = mkOption { - type = types.str; - description = '' - Name of the nginx virtualhost to use and setup. - ''; - }; - - poolConfig = mkOption { - type = types.lines; - default = '' - pm = dynamic - pm.max_children = 75 - pm.start_servers = 1 - pm.min_spare_servers = 1 - pm.max_spare_servers = 20 - pm.max_requests = 500 - catch_workers_output = 1 - ''; - description = '' - Options for wallabag's PHP pool. See the documentation on php-fpm.conf for details on configuration directives. - ''; - }; - - conf = mkOption { - type = types.str; - description = '' - Contents of the wallabag configuration file (parameters.yml) - ''; + config = lib.mkIf cfg.enable { + environment.etc."wallabag/parameters.yml" = { + source = pkgs.writeTextFile { + name = "wallabag-config"; + text = builtins.toJSON { + parameters = settings; + }; }; }; - }; + services.nginx = lib.mkIf cfg.virtualHost.enable { + enable = true; - config = mkIf cfg.enable { + virtualHosts = { + "${cfg.domain}" = { + root = "${pkgs.wallabag}/web"; - services.phpfpm.pools."${poolName}" = { - user = "${cfg.user}"; - group = "nginx"; - phpPackage = pkgs.php; - phpEnv = { - WALLABAG_DATA = cfg.dataDir; - PATH = lib.makeBinPath [pkgs.php]; + extraConfig = '' + add_header X-Frame-Options SAMEORIGIN; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + ''; + + locations."/" = { + extraConfig = '' + try_files $uri /app.php$is_args$args; + ''; + }; + + locations."/assets".root = "${pkgs.wallabag}/app/web"; + + locations."~ ^/app\\.php(/|$)" = { + extraConfig = '' + fastcgi_pass unix:${config.services.phpfpm.pools.wallabag.socket}; + include ${config.services.nginx.package}/conf/fastcgi.conf; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; + fastcgi_param SCRIPT_FILENAME ${pkgs.wallabag}/web/$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT ${pkgs.wallabag}/web; + fastcgi_read_timeout 120; + internal; + ''; + }; + + locations."~ /(?!app)\\.php$" = { + extraConfig = '' + return 404; + ''; + }; + }; }; + }; + + services.phpfpm.pools.wallabag = { + user = config.users.users.wallabag.name; + phpPackage = php; settings = { - "listen.owner" = "nginx"; - "listen.group" = "nginx"; - "listen.mode" = "0600"; - "user" = "${cfg.user}"; - "group" = "nginx"; + "catch_workers_output" = true; + + "listen.owner" = config.services.nginx.user; + "listen.group" = "root"; "pm" = "dynamic"; - "pm.max_children" = "75"; - "pm.min_spare_servers" = "5"; - "pm.max_spare_servers" = "20"; - "pm.max_requests" = "10"; - "catch_workers_output" = "1"; - "php_admin_value[error_log]" = "stderr"; + "pm.max_children" = 5; + "pm.start_servers" = 2; + "pm.min_spare_servers" = 1; + "pm.max_spare_servers" = 3; + "php_admin_value[error_log]" = "/var/log/wallabag/error.log"; + "php_admin_value[access_log]" = "/var/log/wallabag/access.log"; "php_admin_flag[log_errors]" = true; }; - }; - services.phpfpm.phpOptions = '' - max_execution_time = 120 + phpOptions = '' + ; Set up $_ENV superglobal. + ; http://php.net/request-order + variables_order = "EGPCS" + # Wallabag will crash on start-up. + # https://github.com/wallabag/wallabag/issues/6042 + # error_reporting = E_ALL & ~E_USER_DEPRECATED & ~E_DEPRECATED ''; - - services.nginx.enable = mkDefault true; - environment.systemPackages = [ console ]; - - # services.nginx.virtualHosts."${cfg.hostName}" = { - # forceSSL = false; - # enableACME = false; - # extraConfig = '' - # error_log /var/log/nginx/wallabag_error.log; - # access_log /var/log/nginx/wallabag_access.log; - # ''; - - # root = "${cfg.package}/web"; - # locations."/" = { - # priority = 10; - # tryFiles = "$uri /app.php$is_args$args"; - # }; - # locations."/assets".root = "${cfg.dataDir}/web"; - # locations."~ ^/app\\.php(/|$)" = { - # priority = 100; - # fastcgiParams = { - # SCRIPT_FILENAME = "$realpath_root$fastcgi_script_name"; - # DOCUMENT_ROOT = "$realpath_root"; - # }; - # extraConfig = '' - # fastcgi_pass unix:${config.services.phpfpm.pools."${poolName}".socket}; - # include ${config.services.nginx.package}/conf/fastcgi_params; - # include ${config.services.nginx.package}/conf/fastcgi.conf; - # internal; - # ''; - # }; - # locations."~ \\.php$" = { - # priority = 1000; - # return = "404"; - # }; - # }; - - - services.nginx.virtualHosts."${cfg.hostName}" = { - enableACME = false; - forceSSL = false; - root = "${cfg.package}/web"; - - # extraConfig = '' - # add_header X-Frame-Options SAMEORIGIN; - # add_header X-Content-Type-Options nosniff; - # add_header X-XSS-Protection "1; mode=block"; - # ''; - - locations."/" = { - tryFiles = "$uri /app.php$is_args$args"; - }; - - locations."/assets".root = "${cfg.dataDir}/web"; - - locations."~ ^/app\\.php(/|$)" = { - # fastcgiParams = { - # SCRIPT_FILENAME = "$realpath_root$fastcgi_script_name"; - # DOCUMENT_ROOT = "$realpath_root"; - # }; - extraConfig = '' - fastcgi_pass unix:${config.services.phpfpm.pools."${poolName}".socket}; - fastcgi_split_path_info ^(.+\.php)(/.*)$; - include ${pkgs.nginx}/conf/fastcgi_params; - fastcgi_param SCRIPT_FILENAME ${cfg.package}/web/$fastcgi_script_name; - fastcgi_param DOCUMENT_ROOT ${cfg.package}/web; - fastcgi_read_timeout 120; - internal; - ''; - }; - - locations."~ /(?!app)\\.php$" = { - extraConfig = '' - return 404; - ''; + settings = { + # Accept settings from the systemd service. + clear_env = false; }; }; + users.users.wallabag = { + isSystemUser = true; + group = "wallabag"; + }; + users.groups.wallabag = {}; + services.redis.servers.wallabag = { + enable = true; + user = "wallabag"; + }; + services.rabbitmq.enable = false; + + systemd.services.phpfpm-wallabag.serviceConfig = commonServiceConfig; + systemd.services.wallabag-install = { description = "Wallabag install service"; wantedBy = [ "multi-user.target" ]; before = [ "phpfpm-wallabag.service" ]; - after = [ "mysql.service" "postgresql.service" ]; + after = [ "postgresql.service" ]; path = with pkgs; [ coreutils php phpPackages.composer ]; serviceConfig = { - User = cfg.user; + User = "wallabag"; Type = "oneshot"; - RemainAfterExit = "yes"; - PermissionsStartOnly = true; - }; - - preStart = '' - mkdir -p "${cfg.dataDir}" - chown ${cfg.user}:nginx "${cfg.dataDir}" - ''; + } // commonServiceConfig; script = '' - echo "Setting up wallabag files in ${cfg.dataDir} ..." - cd "${cfg.dataDir}" - - rm -rf var/cache/* - rm -f app src translations - ln -sf ${appDir}/app app - ln -sf ${appDir}/src src - ln -sf ${appDir}/translations translations - ln -sf ${cfg.package}/composer.{json,lock} . - - export WALLABAG_DATA="${cfg.dataDir}" - if [ ! -f installed ]; then - echo "Install file not found, installing ..." - php ${cfg.package}/bin/console --env=prod doctrine:database:create --if-not-exists --no-interaction - php ${cfg.package}/bin/console --env=prod doctrine:migrations:migrate --no-interaction - # Until https://github.com/wallabag/wallabag/issues/3662 is fixed - # yes no | php ${cfg.package}/bin/console --env=prod wallabag:install - touch installed - else - php ${cfg.package}/bin/console --env=prod doctrine:migrations:migrate --no-interaction - fi - php ${cfg.package}/bin/console --env=prod cache:clear - ''; + if [ ! -f "$STATE_DIRECTORY/installed" ]; then + php ${pkgs.wallabag}/bin/console --env=prod wallabag:install + touch "$STATE_DIRECTORY/installed" + else + php ${pkgs.wallabag}/bin/console --env=prod doctrine:migrations:migrate --no-interaction + fi + php ${pkgs.wallabag}/bin/console --env=prod cache:clear + ''; }; }; - - meta = with stdenv.lib; { - maintainers = with maintainers; [ nadrieril ]; - }; } diff --git a/overlays/default.nix b/overlays/default.nix index 903ccd83..02df4d94 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -14,6 +14,15 @@ buildInputs = prevAttrs.propagatedBuildInputs ++ [ final.python3.pkgs.aiosqlite ]; # We're using sqlite and upstream doesn't package this dependency }); + wallabag = prev.wallabag.overrideAttrs (attrs: { + patches = builtins.filter (patch: builtins.baseNameOf patch != "wallabag-data.patch") attrs.patches ++ [ + # Out of the box, Wallabag wants to write to various subdirectories of the project directory. + # Let’s replace references to such paths with designated systemd locations + # so that the project source can remain immutable. + ../pkgs/wallabag-data.patch + ]; + }); + # Need to do server and agent too, maybe # woodpecker-cli-next = # let diff --git a/pkgs/default.nix b/pkgs/default.nix index 0d35317f..8a5ef559 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -8,6 +8,10 @@ kobopatch = pkgs.callPackage ./kobopatch.nix { }; my-mautrix-discord = pkgs.callPackage ./mautrix-discord.nix { }; # Handled by matrix-appservices input ulogger-server = pkgs.callPackage ./ulogger.nix { }; + # Wallabag is now an overlay + # TODO: we still use the patch from this folder though my-wallabag = pkgs.callPackage ./wallabag.nix { }; mautrix-slack = pkgs.callPackage ./mautrix-slack.nix { }; + gpodder2go = pkgs.callPackage ./gpodder2go.nix { }; + ghost = pkgs.callPackage ./ghost { }; } diff --git a/pkgs/wallabag-data.patch b/pkgs/wallabag-data.patch index 4276af58..fd6f4781 100644 --- a/pkgs/wallabag-data.patch +++ b/pkgs/wallabag-data.patch @@ -1,26 +1,55 @@ diff --git a/app/AppKernel.php b/app/AppKernel.php -index 61b734e06..d25d1aaa3 100644 +index 61b734e06..0902c20fc 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php -@@ -62,14 +62,19 @@ class AppKernel extends Kernel - return $bundles; - } +@@ -64,12 +64,12 @@ class AppKernel extends Kernel -+ public function getProjectDir() -+ { -+ return getenv('WALLABAG_DATA') ?: dirname(__DIR__); -+ } -+ public function getCacheDir() { - return dirname(__DIR__) . '/var/cache/' . $this->getEnvironment(); -+ return $this->getProjectDir() . '/var/cache/' . $this->getEnvironment(); ++ return getenv('CACHE_DIRECTORY') . '/' . $this->getEnvironment(); } public function getLogDir() { - return dirname(__DIR__) . '/var/logs'; -+ return $this->getProjectDir() . '/var/logs'; ++ return getenv('LOGS_DIRECTORY'); } public function registerContainerConfiguration(LoaderInterface $loader) +diff --git a/app/config/config.yml b/app/config/config.yml +index 7f0a4ca6c..77b5175c8 100644 +--- a/app/config/config.yml ++++ b/app/config/config.yml +@@ -1,5 +1,7 @@ + imports: +- - { resource: parameters.yml } ++ # Unfortunately, we cannot use %env(string:CONFIGURATION_DIRECTORY)%. Hardcoding the path for simplicity. ++ # https://symfony.com/doc/current/service_container/import.html#importing-configuration-with-imports ++ - { resource: '/etc/wallabag/parameters.yml' } + - { resource: security.yml } + - { resource: services.yml } + - { resource: wallabag.yml } +@@ -28,7 +30,7 @@ framework: + session: + # handler_id set to null will use default session handler from php.ini + handler_id: session.handler.native_file +- save_path: "%kernel.project_dir%/var/sessions/%kernel.environment%" ++ save_path: "%env(string:CACHE_DIRECTORY)%/sessions/%kernel.environment%" + cookie_secure: auto + fragments: ~ + http_method_override: true +diff --git a/app/config/wallabag.yml b/app/config/wallabag.yml +index bd57d6377..8e1cd0970 100644 +--- a/app/config/wallabag.yml ++++ b/app/config/wallabag.yml +@@ -35,7 +35,7 @@ wallabag_core: + fetching_error_message: | + wallabag can't retrieve contents for this article. Please troubleshoot this issue. + api_limit_mass_actions: 10 +- encryption_key_path: "%kernel.project_dir%/data/site-credentials-secret-key.txt" ++ encryption_key_path: "%env(string:STATE_DIRECTORY)%/site-credentials-secret-key.txt" + default_internal_settings: + - + name: share_public + diff --git a/pkgs/wallabag.nix b/pkgs/wallabag.nix index 79229206..8ba8799b 100644 --- a/pkgs/wallabag.nix +++ b/pkgs/wallabag.nix @@ -15,7 +15,7 @@ let pname = "wallabag"; - version = "2.6.8"; + version = "2.6.9"; in stdenv.mkDerivation { inherit pname version; @@ -23,7 +23,7 @@ stdenv.mkDerivation { # Release tarball includes vendored files src = fetchurl { url = "https://github.com/wallabag/wallabag/releases/download/${version}/wallabag-${version}.tar.gz"; - hash = "sha256-pmQXafqpd5rTwBIYG9NnwIIPta6Ek7iYaPaHvz1s550="; + hash = "sha256-V4s5/y9fFAmZ+WnUxU03UyRivEihD1ZUKQOOq4TLEKw="; }; patches = [