wallabag is a self hostable application for saving web pages: Save and classify articles. Read them later. Freely.
Deploying Wallabag to The Wobserver
I tried to make the module configurable so that others could use it, but your mileage may vary. I have no intention of upstreaming this to nixpkgs because I don't really understand PHPFPM well enough to feel comfy being responsible for it, but it's good enough for the CCE .
nix source: :tangle ~/arroyo-nix/nixos/wallabag.nix{ pkgs, ... }: { imports = [ ./wallabag-mod.nix ]; services.wallabag = { enable = true; domain = "bag.fontkeming.fail"; virtualHost.enable = true; parameters = { domain_name = "https://bag.fontkeming.fail"; server_name = "rrix's Back-log Black-hole"; locale = "en_US"; twofactor_sender = "wallabag@fontkeming.fail"; from_email = "wallabag@fontkeming.fail"; }; }; services.nginx.virtualHosts."bag.fontkeming.fail" = { useACMEHost = "fontkeming.fail"; addSSL = true; extraConfig = '' error_log /var/log/nginx/wallabag_error.log; access_log /var/log/nginx/wallabag_access.log; ''; }; }
Make sure to write your cookie secret to /var/lib/wallabag/secret.txt!
Another Attempt for a Wallabag NixOS module
The Wallabag module I was using was kind of fiddly and didn't work after I upgraded to 24.05, I stumbled across this one that has some improvements:
it runs a small patch on Wallabag's source to be able to keep the source directory immutable and storing ephemeral data in the
systemdmanaged/var/lib,/var/cache, etc paths.it loads some secrets from a config file on the file system rather than embedding the secret in to the nix store
i've gone and added options to the module so that parameters can be overwritten, some basic settings can be provided, etc. See below for usage example.
i stripped out some DRY utilities that the upstream author had created to manage all their PHPFPM applications. In theory i could port e.g. tt-rss and my other phpfpm applications to use these helpers, but i'd rather not 😊
nix source: :tangle ~/arroyo-nix/nixos/wallabag-mod.nix{ config, lib, pkgs, ... }: let wallabag = pkgs.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. ../files/wallabag-data.patch ]; }); # 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/.s.PGSQL.${toString config.services.postgresql.port}"; database_charset = "utf8"; domain_name = ""; 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)" = "%env(string:STATE_DIRECTORY)%/secret.txt"; 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 = ""; # 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"); package = mkOption { type = types.package; default = pkgs.wallabag; }; 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 <https://doc.wallabag.org/en/admin/parameters.html> 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"); }; 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; virtualHosts = { "bag.fontkeming.fail" = { 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; ''; }; locations."/assets".root = "${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 ${wallabag}/web/$fastcgi_script_name; fastcgi_param DOCUMENT_ROOT ${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 = { "catch_workers_output" = true; "listen.owner" = config.services.nginx.user; "listen.group" = "root"; "pm" = "dynamic"; "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; }; 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 memory_limit = 256M ''; 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 = [ "postgresql.service" ]; path = with pkgs; [ coreutils php phpPackages.composer ]; serviceConfig = { User = "wallabag"; Type = "oneshot"; } // commonServiceConfig; script = '' if [ ! -f "$STATE_DIRECTORY/installed" ]; then php ${wallabag}/bin/console --env=prod wallabag:install touch "$STATE_DIRECTORY/installed" else php ${wallabag}/bin/console --env=prod doctrine:migrations:migrate --no-interaction fi php ${wallabag}/bin/console --env=prod cache:clear ''; }; }; }
diff source: :tangle ~/arroyo-nix/files/wallabag-data.patch :comments nonediff --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 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 <a href="https://doc.wallabag.org/en/user/errors_during_fetching.html#how-can-i-help-to-fix-that">troubleshoot this issue</a>. 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