diff --git a/flake.lock b/flake.lock index 238f2ac..f172523 100644 --- a/flake.lock +++ b/flake.lock @@ -532,11 +532,11 @@ "unstable": "unstable_2" }, "locked": { - "lastModified": 1702398531, - "narHash": "sha256-RZeMnFPju5pHZ80FtNPmchbIOLspy93NLFVMRmW9fCs=", + "lastModified": 1703787975, + "narHash": "sha256-KCIiOu/LU3juaw+MipIsJOWkwU1QlIMlQZ+JuKEoRhY=", "ref": "main", - "rev": "0183623a2f68f0716673fd46a69b501cc3fbaf1b", - "revCount": 120, + "rev": "0934337798b36835864df2fe8298aeb86a7bbc6c", + "revCount": 121, "type": "git", "url": "ssh://xin-secrets-ro/qbit/xin-secrets.git" }, diff --git a/hosts/h/alias b/hosts/h/alias index 2a9853c..321228a 100644 --- a/hosts/h/alias +++ b/hosts/h/alias @@ -1 +1 @@ -h.suah.dev +h.otter-alligator.ts.net diff --git a/hosts/h/default.nix b/hosts/h/default.nix index bf8da2d..c7d73f4 100644 --- a/hosts/h/default.nix +++ b/hosts/h/default.nix @@ -154,6 +154,11 @@ in owner = "root"; sopsFile = config.xin-secrets.h.services; }; + wallabag_secret = { + mode = "400"; + owner = "wallabag"; + sopsFile = config.xin-secrets.h.services; + }; }; networking = { @@ -213,7 +218,7 @@ in }; environment = { - memoryAllocator.provider = "mimalloc"; + memoryAllocator.provider = "libc"; systemPackages = with pkgs; [ inetutils @@ -299,6 +304,11 @@ in }; services = { + wallabag = { + enable = true; + secretPath = config.sops.secrets.wallabag_secret.path; + domain = "bookmarks.tapenet.org"; + }; navidrome = { enable = true; settings = { @@ -830,7 +840,7 @@ in LC_COLLATE = "C" LC_CTYPE = "C"; ''; - ensureDatabases = [ "synapse" "gotosocial" "syncv3" ]; + ensureDatabases = [ "synapse" "gotosocial" "syncv3" "wallabag" ]; ensureUsers = [ { name = "synapse_user"; @@ -843,6 +853,10 @@ in name = "syncv3"; ensureDBOwnership = true; } + { + name = "wallabag"; + ensureDBOwnership = true; + } ]; }; diff --git a/modules/default.nix b/modules/default.nix index 0b28640..1a88caa 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -8,6 +8,7 @@ ./ts-rev-prox.nix ./tsvnstat.nix ./veilid-server.nix + ./wallabag.nix ./yarr.nix ]; } diff --git a/modules/wallabag-data-location.patch b/modules/wallabag-data-location.patch new file mode 100644 index 0000000..d574fc8 --- /dev/null +++ b/modules/wallabag-data-location.patch @@ -0,0 +1,54 @@ +diff --git a/app/AppKernel.php b/app/AppKernel.php +index 61b734e06..0902c20fc 100644 +--- a/app/AppKernel.php ++++ b/app/AppKernel.php +@@ -64,12 +64,12 @@ class AppKernel extends Kernel + + public function getCacheDir() + { +- return dirname(__DIR__) . '/var/cache/' . $this->getEnvironment(); ++ return getenv('CACHE_DIRECTORY') . '/' . $this->getEnvironment(); + } + + public function getLogDir() + { +- return dirname(__DIR__) . '/var/logs'; ++ return getenv('LOGS_DIRECTORY'); + } + + public function registerContainerConfiguration(LoaderInterface $loader) +diff --git a/app/config/config.yml b/app/config/config.yml +index 2155a2017..0fa61f84c 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 eddd56654..50eed72cf 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/modules/wallabag.nix b/modules/wallabag.nix new file mode 100644 index 0000000..54672eb --- /dev/null +++ b/modules/wallabag.nix @@ -0,0 +1,233 @@ +{ lib +, config +, pkgs +, ... +}: + +let + cfg = config.services.wallabag; + inherit (builtins) toJSON; + inherit (lib) mkOption mkEnableOption types mkIf; + wallabag = pkgs.wallabag.overrideAttrs (old: { + patches = builtins.filter (patch: builtins.baseNameOf patch != "wallabag-data.patch") old.patches ++ [ + # https://github.com/jtojnar/nixfiles/commit/662ac88e3358e9b50468c4bbf124aa821e22cae4 + ./wallabag-data-location.patch + ]; + }); + wallabagConfig = toJSON { + parameters = { + database_driver = "pdo_sqlite"; + database_driver_class = "~"; + database_host = "127.0.0.1"; + database_port = "~"; + database_name = "wallabag"; + database_user = "root"; + database_password = "~"; + database_table_prefix = "wallabag_"; + database_socket = "~"; + database_path = "${cfg.dataDir}/data/db/wallabag.sqlite"; + database_charset = "utf8"; + + domain_name = "https://${cfg.domain}"; + server_name = "Wallabag"; + + mailer_dsn = "smtp://127.0.0.1"; + + locale = "en"; + + "env(SECRET_FILE)" = "${cfg.secretPath}"; + secret = "%env(file:resolve:SECRET_FILE)%"; + + twofactor_auth = true; + twofactor_sender = "no-reply@${cfg.domain}"; + + 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 = "no-reply@${cfg.domain}"; + + # rss_limit = 50; + + # TODO: RabbitMQ processing + rabbitmq_host = null; + rabbitmq_port = null; + rabbitmq_user = null; + rabbitmq_password = null; + rabbitmq_prefetch_count = null; + + redis_scheme = "tcp"; + redis_host = "127.0.0.1"; + redis_port = 6380; + redis_path = null; + redis_password = null; + + # sentry logging + sentry_dsn = null; + }; + }; + php = pkgs.php.withExtensions ({ enabled, all }: enabled ++ (with all; [ + imagick + tidy + ])); + wallabagServiceConfig = { + CacheDirectory = "wallabag"; + CacheDirectoryMode = "700"; + + ConfigurationDirectory = "wallabag"; + ConfigurationDirectoryMode = "700"; + + LogsDirectory = "wallabag"; + + StateDirectory = "wallabag"; + StateDirectoryMode = "700"; + #DynamicUser = false; + }; +in +{ + options.services.wallabag = { + enable = mkEnableOption "Enable Wallabag"; + domain = mkOption { + type = types.str; + default = ""; + description = "Domain wallabag will run on"; + }; + secretPath = mkOption { + type = types.path; + default = ""; + description = "Path to file containing the wallabag secret"; + }; + dataDir = mkOption { + type = types.path; + default = "/var/lib/wallabag"; + description = "wallabag data directory"; + }; + + socket = mkOption { + type = types.path; + default = config.services.phpfpm.pools.wallabag.socket; + description = "wallabag data directory"; + }; + user = mkOption { + type = with types; oneOf [ str int ]; + default = "wallabag"; + description = "The user wallabag will run as."; + }; + + group = mkOption { + type = with types; oneOf [ str int ]; + default = "wallabag"; + description = "The group wallabag will run with."; + }; + + }; + + config = mkIf cfg.enable { + + environment.etc."wallabag/parameters.yml" = { + source = pkgs.writeTextFile { + name = "wallabag-config"; + text = wallabagConfig; + }; + }; + + users.groups.${cfg.group} = { }; + users.users.${cfg.user} = { + isSystemUser = true; + inherit (cfg) group; + description = "Wallabag daemon user"; + home = cfg.dataDir; + createHome = true; + }; + + services.nginx.virtualHosts.${cfg.domain} = { + forceSSL = true; + enableACME = true; + root = "${wallabag}/web"; + 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;"; + "/assets".root = "${wallabag}/app/web"; + "~ ^/app\\.php(/|$)".extraConfig = '' + fastcgi_pass unix:${cfg.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 ${wallabag}/web/$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT ${wallabag}/web; + fastcgi_param REMOTE_USER $remote_user; + fastcgi_read_timeout 120; + internal; + ''; + "~ /(?!app)\\.php$".extraConfig = "return 404;"; + }; + }; + + services.phpfpm = { + pools.wallabag = { + inherit (cfg) user; + phpPackage = php; + settings = { + "listen.owner" = "nginx"; + "listen.group" = "nginx"; + pm = "dynamic"; + "pm.max_children" = 5; + "pm.start_servers" = 2; + "pm.min_spare_servers" = 1; + "pm.max_spare_servers" = 3; + clear_env = false; + catch_workers_output = true; + }; + 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 + ''; + }; + }; + + systemd.services.phpfpm-wallabag.serviceConfig = wallabagServiceConfig; + + systemd.services.wallabag-install = { + description = "Wallabag install service"; + wantedBy = [ "multi-user.target" ]; + before = [ "phpfpm-wallabag.service" ]; + after = [ "postgresql.service" ]; + path = with pkgs; [ coreutils php phpPackages.composer ]; + serviceConfig = { + User = cfg.user; + Type = "oneshot"; + } // wallabagServiceConfig; + preStart = '' + mkdir -p "${cfg.dataDir}/data/db" + ''; + script = '' + if [ ! -f "$STATE_DIRECTORY/installed" ]; then + if php ${wallabag}/bin/console --env=prod wallabag:install; then + echo "Wallabag initial config complete" + touch "$STATE_DIRECTORY/installed" + else + echo "failed to install!" + exit 1 + fi + else + echo "Running wallabag migrations" + php ${wallabag}/bin/console --env=prod doctrine:migrations:migrate --no-interaction + fi + echo "Starting Wallabag" + php ${wallabag}/bin/console --env=prod cache:clear + ''; + }; + }; +}