| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- { config
- , lib
- , pkgs
- , ... }:
- with lib;
- let
- cfg = config.services.gogs;
- iniFormat = pkgs.formats.ini {};
- defaultConfig = lib.recursiveUpdate {
- server.RUN_USER = cfg.user;
- security.INSTALL_LOCK = true;
- database.TYPE = "sqlite3";
- database.PATH = "${cfg.stateDir}/data/gogs.db";
- } cfg.settings;
- configFile = iniFormat.generate "gogs.ini" defaultConfig;
- themeVariants = {
- dark = "kristuff.gogs.dark.min.css";
- dark-blue = "kristuff.gogs.dark-accent-blue.min.css";
- dark-green = "kristuff.gogs.dark-accent-green.min.css";
- dark-magenta = "kristuff.gogs.dark-accent-magenta.min.css";
- dark-orange = "kristuff.gogs.dark-accent-orange.min.css";
- dark-red = "kristuff.gogs.dark-accent-red.min.css";
- dark-yellow = "kristuff.gogs.dark-accent-yellow.min.css";
- };
- themeFile = if cfg.theme == null then null
- else if builtins.hasAttr cfg.theme themeVariants
- then "${pkgs.gogs-themes}/dist/${themeVariants.${cfg.theme}}"
- else cfg.theme;
- themeSetupScript = pkgs.writeShellScript "gogs-theme-setup" ''
- mkdir -p ${cfg.stateDir}/custom/public/css ${cfg.stateDir}/custom/templates/inject
- cp -f ${themeFile} ${cfg.stateDir}/custom/public/css/theme.css
- cat > ${cfg.stateDir}/custom/templates/inject/head.tmpl << 'EOF'
- <link rel="stylesheet" href="{{AppSubURL}}/css/theme.css">
- EOF
- '';
- in {
- options.services.gogs = {
- enable = lib.mkEnableOption "Gogs Git service";
- package = lib.mkPackageOption pkgs "gogs" { };
- user = lib.mkOption {
- type = lib.types.str;
- default = "git";
- description = "User account under which Gogs runs.";
- };
- group = lib.mkOption {
- type = lib.types.str;
- default = "git";
- description = "Group under which Gogs runs.";
- };
- stateDir = lib.mkOption {
- type = lib.types.str;
- default = "/var/lib/gogs";
- description = "Persistent data directory.";
- };
- environmentFile = lib.mkOption {
- type = lib.types.nullOr lib.types.path;
- default = null;
- description = ''
- File containing environment variables to pass to the Gogs service,
- formatted as VARIABLE=VALUE per line. Values set here are merged into
- the service's environment and can be used to pass secrets (e.g.
- database passwords) without putting them in the Nix store.
- '';
- };
- theme = lib.mkOption {
- type = lib.types.nullOr (
- lib.types.either (lib.types.enum [
- "dark"
- "dark-blue"
- "dark-green"
- "dark-magenta"
- "dark-orange"
- "dark-red"
- "dark-yellow"
- ]) lib.types.path
- );
- default = null;
- example = "dark-blue";
- description = ''
- Dark theme for Gogs. Can be:
- - A string selecting a built-in variant from pkgs.gogs-themes:
- dark, dark-blue, dark-green, dark-magenta, dark-orange, dark-red, dark-yellow.
- - A path or package pointing to a custom CSS file.
- Set to null to disable theming.
- '';
- };
- adminUser = lib.mkOption {
- type = lib.types.nullOr (lib.types.submodule {
- options = {
- name = lib.mkOption {
- type = lib.types.str;
- description = "Admin username.";
- };
- email = lib.mkOption {
- type = lib.types.str;
- description = "Admin email address.";
- };
- passwordFile = lib.mkOption {
- type = lib.types.path;
- description = ''
- File containing the admin password. Must be readable by root.
- Recommended to use an age secret managed by agenix.
- '';
- };
- };
- });
- default = null;
- example = {
- email = "[email protected]";
- passwordFile = "/run/secrets/gogs-admin-password";
- };
- description = ''
- Admin user to create on first startup. Uses gogs admin create-user
- via ExecStartPost. Idempotent — silently skips if the user already
- exists. Set to null to skip.
- '';
- };
- settings = lib.mkOption {
- type = iniFormat.type;
- default = { };
- example = lib.literalExpression ''
- {
- server = {
- DOMAIN = "git.example.com";
- ROOT_URL = "https://git.example.com/";
- HTTP_PORT = 3000;
- };
- database = {
- TYPE = "sqlite3";
- PATH = "/var/lib/gogs/data/gogs.db";
- };
- }
- '';
- description = ''
- Settings written to app.ini.
- See:
- https://gogs.io/docs/advanced/configuration_cheat_sheet
- '';
- };
- };
- config = mkIf cfg.enable {
- users.users.${cfg.user} = {
- isSystemUser = true;
- group = cfg.group;
- home = cfg.stateDir;
- createHome = true;
- };
- users.groups.${cfg.group} = { };
- systemd.tmpfiles.rules = [
- "d ${cfg.stateDir} 0750 ${cfg.user} ${cfg.group} -"
- "d ${cfg.stateDir}/repositories 0750 ${cfg.user} ${cfg.group} -"
- "d ${cfg.stateDir}/data 0750 ${cfg.user} ${cfg.group} -"
- "d ${cfg.stateDir}/log 0750 ${cfg.user} ${cfg.group} -"
- "d ${cfg.stateDir}/custom/public/css 0755 ${cfg.user} ${cfg.group} -"
- "d ${cfg.stateDir}/custom/templates/inject 0755 ${cfg.user} ${cfg.group} -"
- ];
- systemd.services.gogs = {
- description = "Gogs Git Service";
- after = [ "network.target" ];
- wantedBy = [ "multi-user.target" ];
- environment = {
- GOGS_WORK_DIR = cfg.stateDir;
- GOGS_CUSTOM = "${cfg.stateDir}/custom";
- };
- serviceConfig = {
- Type = "simple";
- User = cfg.user;
- Group = cfg.group;
- EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
- StateDirectory = "gogs";
- StateDirectoryMode = "0750";
- WorkingDirectory = cfg.stateDir;
- ExecStart =
- "${getExe cfg.package} web --config ${configFile}";
- ExecStartPre = lib.mkIf (themeFile != null) [
- "+${themeSetupScript}"
- ];
- Restart = "on-failure";
- NoNewPrivileges = true;
- PrivateTmp = true;
- ProtectSystem = "strict";
- ProtectHome = true;
- };
- postStart = lib.mkIf (cfg.adminUser != null) ''
- ${lib.getExe cfg.package} admin create-user \
- --name ${lib.escapeShellArg cfg.adminUser.name} \
- --password "$(cat ${cfg.adminUser.passwordFile})" \
- --email ${lib.escapeShellArg cfg.adminUser.email} \
- --admin \
- --config ${configFile} \
- >/dev/null 2>&1 || true
- '';
- };
- };
- }
|