{ config, pkgs, lib, ... }: let cfg = config.services.lenticular-cloud; python = pkgs.python3; format = pkgs.formats.json {}; types = lib.types; config_oauth_secret = "${cfg.settings.DATA_FOLDER}/lenticular_oauth_secret.toml"; python_env = python.withPackages (ps: with ps; [ lenticular-cloud gevent setuptools ]); in { options = with lib.options; { services.lenticular-cloud = { enable = mkEnableOption "lenticluar service enable"; domain = mkOption { type = lib.types.str; example = "example.com"; }; username = mkOption { type = lib.types.str; description = mdDoc "user to run the service"; default = "lenticular_cloud"; }; service_domain = mkOption { type = lib.types.str; example = "account.example.com"; }; settings = mkOption { description = mdDoc '' Lenticular cloud settings ''; default = { }; type = types.submodule { freeformType = format.type; options = { DOMAIN = mkOption { type = types.str; description = mdDoc "Top level Domain of the service"; default = cfg.domain; }; PUBLIC_URL = mkOption { type = types.str; description = mdDoc "public service url"; default = "https://${cfg.service_domain}"; }; ADMINS = mkOption { type = types.listOf types.str; description = mdDoc "list of admin users"; example = [ "tuxcoder" ]; }; DATA_FOLDER = mkOption { type = types.str; default = "/var/lib/${cfg.username}"; }; PKI_PATH = mkOption { type = types.str; default = "${cfg.settings.DATA_FOLDER}/pki"; }; SQLALCHEMY_DATABASE_URI = mkOption { type = types.str; default = "postgresql://${cfg.username}@/${cfg.username}?host=/run/postgresql"; }; HYDRA_ADMIN_URL = mkOption { type = types.str; default = "https://${config.services.ory-hydra.admin_domain}"; }; HYDRA_PUBLIC_URL = mkOption { type = types.str; default = "https://${config.services.ory-hydra.public_domain}"; }; LENTICULAR_CLOUD_SERVICES = mkOption { type = types.attrsOf (types.submodule { options = { app_token = mkOption { type = types.bool; default = false; description = "enables the app token function for this service"; }; href = mkOption { type = types.str; example = "https://service.example.com"; description = "Link to the hosted service"; }; icon = mkOption { type = types.str; example = "https://service.example.com/favicon.png"; description = "Link to an icon of the service"; }; }; }); default = {}; }; }; }; }; }; }; config = { environment.systemPackages = [ pkgs.lenticular-cloud ]; nixpkgs.overlays = [ (import ./overlay.nix) ]; users = { groups."${cfg.username}" = { }; users."${cfg.username}" = { createHome = true; home = "/var/lib/${cfg.username}"; description = "web server"; extraGroups = [ # "ory-hydra" ]; group = cfg.username; isSystemUser = true; }; }; services.postgresql = { enable = true; ensureDatabases = [ cfg.username ]; ensureUsers = [ { name = cfg.username; ensureDBOwnership = true; } ]; }; services.ory-hydra.settings = { urls = { login = "${cfg.settings.PUBLIC_URL}/auth/login"; logout = "${cfg.settings.PUBLIC_URL}/auth/logout"; consent = "${cfg.settings.PUBLIC_URL}/auth/consent"; error = "${cfg.settings.PUBLIC_URL}/auth/error"; }; }; services.nginx.enable = true; services.nginx.virtualHosts."${cfg.service_domain}" = { addSSL = true; enableACME = true; serverName = cfg.service_domain; locations."/" = { recommendedProxySettings = true; proxyPass = "http://unix:/run/${cfg.username}/web.sock"; }; }; users.users.nginx.extraGroups = [ cfg.username ]; systemd.services.lenticular-cloud = { description = "lenticular account"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; requires = [ "ory-hydra.service" "postgresql.service" ]; enable = cfg.enable; environment = let config_file = format.generate "lenticular-cloud.json" cfg.settings; in { # CONFIG_FILE = "/etc/lenticular_cloud/production.conf"; CONFIG_FILE = "${config_file}:${config_oauth_secret}"; }; preStart = '' if [[ ! -e "${config_oauth_secret}" ]]; then SECRET_KEY=`${pkgs.openssl}/bin/openssl rand --hex 16` echo 'OAUTH_SECRET="$${SECRET_KEY}"' > ${config_oauth_secret} echo "oauth secreted generated" fi ${pkgs.lenticular-cloud}/bin/lenticular_cloud-cli db_upgrade ''; serviceConfig = { Type = "simple"; WorkingDirectory = cfg.settings.DATA_FOLDER; User = cfg.username; ExecStart = ''${python_env}/bin/gunicorn lenticular_cloud.wsgi --name lenticular_cloud \ --workers 2 --log-level=info \ --bind=unix:/run/${cfg.username}/web.sock \ -k gevent''; Restart = "on-failure"; RuntimeDirectory = cfg.username; }; }; }; }