diff --git a/flake.nix b/flake.nix index bbf0a9f..1c19d0f 100644 --- a/flake.nix +++ b/flake.nix @@ -34,6 +34,8 @@ install -Dm755 ${./fragify.py} $out/bin/fragify mkdir -p $out/share/fragify cp -r ${./templates} $out/share/fragify/ + # Provide a WSGI entry file for uWSGI to load + install -Dm644 ${./fragify.py} $out/share/fragify/fragify_wsgi.py ''; meta.mainProgram = "fragify"; diff --git a/fragify.py b/fragify.py index f78ef49..0bd47aa 100644 --- a/fragify.py +++ b/fragify.py @@ -16,6 +16,11 @@ class BaseTemplateResource: def _get_template_dir(self): """Get the template directory path, handling both development and installed environments""" + # Allow overriding via environment variable (for packaged deployments) + env_dir = os.environ.get('FRAGIFY_TEMPLATES_DIR') + if env_dir and os.path.exists(env_dir): + return env_dir + # Get the directory where this script is located script_dir = os.path.dirname(os.path.abspath(__file__)) diff --git a/module.nix b/module.nix index 24635e2..0cebce5 100644 --- a/module.nix +++ b/module.nix @@ -6,93 +6,67 @@ }: let - cfg = config.services.mail-quota-warning; + cfg = config.services.fragify; in { - options = { - services.fragify = { + options = { + services.fragify = { - enable = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable fragify web application. - ''; - }; + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable fragify web application. + ''; + }; - }; - }; + }; + }; - config = lib.mkIf cfg.enable { + config = lib.mkIf cfg.enable { - systemd.services."fragify" = { - description = "fragify web application"; - after = [ "network.target" ]; - wants = [ "network-online.target" ]; - environment = { - PYTHONUNBUFFERED = "1"; - }; - serviceConfig = { - Type = "simple"; - ExecStart = "${lib.getExe pkgs.fragify}"; - WorkingDirectory = "%S/fragify"; - StateDirectory = "fragify"; - User = "fragify"; - Group = "fragify"; + # uWSGI application definition for Fragify + services.uwsgi.enable = true; + services.uwsgi.user = "fragify"; + services.uwsgi.group = "fragify"; + services.uwsgi.plugins = [ "python3" ]; + services.uwsgi.instance."fragify" = { + type = "normal"; + chdir = "/"; + # Load WSGI by file path from the packaged share dir + wsgi-file = "${pkgs.fragify}/share/fragify/fragify_wsgi.py"; + module = "fragify:app"; + pythonPackages = p: with p; [ falcon requests jinja2 ]; + env = { + FRAGIFY_TEMPLATES_DIR = "${pkgs.fragify}/share/fragify/templates"; + }; + socket = "unix:${config.services.uwsgi.runDir}/fragify.sock"; + chmod-socket = "660"; + umask = "0077"; + vacuum = true; + master = true; + processes = 2; + threads = 2; + harakiri = 60; + buffer-size = 65535; + # Security hardening + need-app = true; + no-orphans = true; + }; - # hardening - AmbientCapabilities = ""; - CapabilityBoundingSet = ""; - DevicePolicy = "closed"; - DynamicUser = false; - LockPersonality = true; - MemoryDenyWriteExecute = true; - NoNewPrivileges = true; - PrivateDevices = true; - PrivateTmp = true; - PrivateUsers = false; - ProcSubset = "pid"; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectProc = "invisible"; - ProtectSystem = "strict"; - RemoveIPC = true; - RestrictAddressFamilies = [ - "AF_INET" - "AF_INET6" - ]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - SystemCallArchitectures = "native"; - SystemCallFilter = [ - "@system-service" - "~@privileged" - ]; - UMask = "0077"; - }; - }; + # Ensure fragify user and group exist + users.users.fragify = { + isSystemUser = true; + group = "fragify"; + description = "fragify web application user"; + }; - # Create fragify user and group - users.users.fragify = { - isSystemUser = true; - group = "fragify"; - description = "fragify web application user"; - }; - - users.groups.fragify = {}; - - }; - - meta = { - maintainers = with lib.maintainers; [ onny ]; - }; + users.groups.fragify = {}; + }; + meta = { + maintainers = with lib.maintainers; [ onny ]; + }; }