A new forge is now used, it is pretty much equal to before, but now we
are using (a fork of) Gitea instead of Forgejo. Gitea was choosen
because provides more features that we need compared to Forgejo and it
has a more modern codebase to fork and customize. The fork can be found
at https://code.capytal.cc/loreddev/gitea, it mostly provides a new
default theme and custom UI changes.
This commit is contained in:
Guz
2025-10-11 09:21:21 -03:00
parent 8df6647f9e
commit 470d719f80
6 changed files with 375 additions and 87 deletions

View File

@@ -1,118 +1,350 @@
{
config,
inputs,
lib,
self,
pkgs,
...
}: let
cfg = config.services.forgejo;
gitea = config.services.gitea;
in {
services.forgejo = {
imports = [
self.nixosModules.gitea
];
services.gitea = {
enable = true;
package = pkgs.forgejo;
settings = let
initList = l: (lib.strings.concatStringsSep "," l);
in {
package = inputs.loreddev-gitea.packages.${pkgs.system}.default;
lfs.enable = true;
settings = with lib; let
initList = l: (concatStringsSep "," l);
in rec {
DEFAULT = {
APP_NAME = "Capytal Code";
};
actions = {
ENABLED = true;
DEFAULT_ACTIONS_URL = "https://data.forgejo.org";
};
admin = {
DISABLE_REGULAR_ORG_CREATION = true;
USER_DISABLED_FEATURES = "deletion manage_ssh_keys manage_gpg_keys";
EXTERNAL_USER_DISABLED_FEATURES = "deletion manage_ssh_keys manage_gpg_keys";
};
database = {
HOST = "127.0.0.1:${toString config.services.postgresql.settings.port}";
NAME = "forgejo";
USER = "forgejo";
SSL_MODE = "disable";
};
repository = {
DEFAULT_REPO_UNITS = initList [
"repo.code"
"repo.issues"
"repo.pulls"
];
DEFAULT_TEMPLATE_REPO_UNITS = repository.DEFAULT_REPO_UNITS;
};
"repository.pull-request" = {
CLOSE_KEYWORDS = initList [
# en-US
"close"
"closes"
"closed"
"fix"
"fixes"
"fixed"
"resolve"
"resolves"
"resolved"
# pt-BR
"corrige"
"completa"
"fecha"
"implementa"
"resolve"
"termina"
];
};
"repository.signing" = {
DEFAULT_TRUST_MODEL = "committer";
};
"ui.meta" = {
AUTHOR = "Capytal";
DESCRIPTION = replaceString "\n" " " ''
Software forge dedicated for hosting official projects from Capytal and it's members.
Explore and discover the source-code of our commercial user-facing products, internal
developer-focused libraries, and infraestructure setups.
'';
KEYWORDS = initList [
"capytal"
"capytal code"
"capytal-code"
"git"
"gitea"
"projects"
"development"
"open source"
"open-source"
];
};
server = {
DOMAIN = "code.capytal.cc";
ROOT_URL = "https://${server.DOMAIN}";
PUBLIC_URL_DETECTION = "auto";
HTTP_PORT = 9964;
};
database = {
DB_TYPE = "sqlite3";
NAME = "gitea";
USER = "gitea";
SQLITE_JOURNAL_MODE = "WAL";
};
security = {
REVERSE_PROXY_TRUSTED_PROXIES = "127.0.0.0/8,::1/128";
};
server = rec {
HTTP_PORT = 9960;
DOMAIN = "forge.capytal.company";
ROOT_URL = "https://${DOMAIN}";
INSTALL_LOCK = true;
COOKIE_REMEMBER_NAME = "__Host-capytal_code_forge_incredible";
PASSWORD_COMPLEXITY = initList ["lower" "upper" "digit" "spec"];
PASSWORD_CHECK_PWN = true;
};
service = {
REGISTER_MANUAL_CONFIRM = true;
REVERSE_PROXY_TRUSTED_PROXIES = "127.0.0.0/8,::1/128";
DISABLE_REGISTRATION = true;
DEFAULT_KEEP_EMAIL_PRIVATE = true;
DEFAULT_ALLOW_CREATE_ORGANIZATION = false;
DEFAULT_USER_IS_RESTRICTED = true;
SHOW_REGISTRATION_BUTTON = false;
ALLOW_ONLY_INTERNAL_REGISTRATION = true;
VALID_SITE_URL_SCHEMES = initList ["https"];
};
qos = {
# For endpoints not protected by Anubis and protect from overload in general.
ENABLED = true;
};
cache = {
ADAPTER = "twoqueue";
HOST = builtins.toJSON {
size = 1000;
recent_ratio = 0.25;
ghost_ratio = 0.5;
};
};
session = {
COOKIE_SECURE = true;
COOKIE_NAME = "__Host-i_like_capytal_code_forge";
SAME_SITE = "strict";
};
picture = {
DISABLE_GRAVATAR = true; # Deprecated
ENABLE_FEDERATED_AVATAR = false; # Deprecated
};
"cron.delete_repo_archives" = {
ENABLED = true;
};
"cron.git_gc_repos" = {
ENABLED = true;
};
oauth2 = {
ENABLED = true;
};
federation = {
ENABLED = true;
};
lfs = {};
storage = {
STORAGE_TYPE = "minio";
MINIO_USE_SSL = false;
MINIO_ENDPOINT = "127.0.0.1:3461";
MINIO_BUCKET = "forgejo";
MINIO_ENDPOINT = "localhost:3461";
MINIO_BUCKET = "gitea";
MINIO_LOCATION = config.services.garage.settings.s3_api.s3_region;
};
ui = {
# DEFAULT_THEME = "capytal-dark";
"storage.repo-archive" = {};
"repo-archive" = {};
actions = {
ENABLE = false; # Temporarily
DEFAULT_ACTIONS_URL = "self";
};
};
secrets = {
server = {
LFS_JWT_SECRET = config.sops.secrets."gitea/server/lfs_jwt_secret".path;
};
security = {
SECRET_KEY = config.sops.secrets."gitea/security/secret_key".path;
INTERNAL_TOKEN = config.sops.secrets."gitea/security/internal_token".path;
};
oauth2 = {
JWT_SECRET = config.sops.secrets."gitea/oauth2/jwt_secret".path;
};
storage = {
MINIO_ACCESS_KEY_ID = "${config.sops.secrets."forgejo/s3/key".path}";
MINIO_SECRET_ACCESS_KEY = "${config.sops.secrets."forgejo/s3/secret".path}";
MINIO_ACCESS_KEY_ID = config.sops.secrets."gitea/storage/access_key_id".path;
MINIO_SECRET_ACCESS_KEY = config.sops.secrets."gitea/storage/secret_access_key".path;
};
};
};
services.gitea-actions-runner = {
package = pkgs.forgejo-actions-runner;
instances = {
"forgejo-runner-1" = {
"gitea-runner-1" = {
enable = true;
name = "Forgejo Runner (${config.networking.hostName}) 1";
url = config.services.forgejo.settings.server.ROOT_URL;
tokenFile = config.sops.secrets."forgejo/actions/token".path;
name = "Gitea Runner (${config.networking.hostName}) 1";
url = gitea.settings.server.ROOT_URL;
tokenFile = config.sops.secrets."gitea/actions/token".path;
labels = [
"alpine-3.22:docker://data.forgejo.org/oci/alpine:3.22"
"golang-1.24:docker://data.forgejo.org/oci/golang:1.24-alpine3.22"
"node-24:docker://node:24-bullseye"
"ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
];
};
};
};
users.users."${cfg.user}".packages = [
(pkgs.symlinkJoin {
paths = [pkgs.forgejo];
buildInputs = [pkgs.makeWrapper];
postFixup = ''
wrapProgram $out/bin/gitea \
--add-flags --config '${cfg.customDir}/conf/app.ini'
'';
inherit (pkgs.forgejo) name pname meta;
})
];
# systemd.services.gitea-custom = let
# gitea = config.services.gitea;
# rsync = lib.getExe pkgs.rsync;
# in {
# before = [
# "gitea-secrets.service"
# "gitea.service"
# ];
# script = ''
# ${rsync} -av "${./assets}" "${gitea.customDir}/public/assets"
# '';
# serviceConfig = {
# Type = "oneshot";
# RemainAfterExit = true;
# User = gitea.user;
# Group = gitea.group;
# ReadWritePaths = [gitea.customDir];
# UMask = "0077";
# };
# };
services.anubis.instances."forgejo" = {
services.anubis.instances."gitea" = {
settings = {
BIND = ":${toString (cfg.settings.server.HTTP_PORT + 2)}";
BIND = ":${toString (gitea.settings.server.HTTP_PORT + 2)}";
BIND_NETWORK = "tcp";
METRICS_BIND = ":${toString (cfg.settings.server.HTTP_PORT + 3)}";
METRICS_BIND = ":${toString (gitea.settings.server.HTTP_PORT + 3)}";
METRICS_BIND_NETWORK = "tcp";
SERVE_ROBOTS_TXT = true;
TARGET = "http://localhost:${toString cfg.settings.server.HTTP_PORT}";
ED25519_PRIVATE_KEY_HEX_FILE = config.sops.secrets."anubis/forgejo/hex_file".path;
TARGET = "http://localhost:${toString gitea.settings.server.HTTP_PORT}";
ED25519_PRIVATE_KEY_HEX_FILE = config.sops.secrets."anubis/gitea/hex_file".path;
};
};
services.caddy.virtualHosts.":${toString (cfg.settings.server.HTTP_PORT + 1)}" = {
extraConfig = ''
reverse_proxy http://localhost${config.services.anubis.instances."forgejo".settings.BIND} {
header_up X-Real-Ip {remote_host}
}
'';
services.caddy.virtualHosts = let
redir = {
extraConfig = ''
redir https://code.capytal.cc{uri} permanent
'';
};
in {
":${toString (gitea.settings.server.HTTP_PORT + 1)}" = {
extraConfig = ''
reverse_proxy http://localhost${config.services.anubis.instances."gitea".settings.BIND} {
header_up X-Http-Version {http.request.proto}
header_up X-Real-Ip {remote_host}
}
'';
};
# Old ports used by legacy https://forge.capytal.company
":9961" = redir;
":9962" = redir;
};
# services.forgejo = {
# enable = true;
# package = pkgs.forgejo;
# settings = let
# initList = l: (lib.strings.concatStringsSep "," l);
# in {
# DEFAULT = {
# APP_NAME = "Capytal Code";
# };
# actions = {
# ENABLED = true;
# DEFAULT_ACTIONS_URL = "https://data.forgejo.org";
# };
# admin = {
# DISABLE_REGULAR_ORG_CREATION = true;
# USER_DISABLED_FEATURES = "deletion manage_ssh_keys manage_gpg_keys";
# EXTERNAL_USER_DISABLED_FEATURES = "deletion manage_ssh_keys manage_gpg_keys";
# };
# database = {
# HOST = "127.0.0.1:${toString config.services.postgresql.settings.port}";
# NAME = "forgejo";
# USER = "forgejo";
# SSL_MODE = "disable";
# };
# repository = {
# DEFAULT_REPO_UNITS = initList [
# "repo.code"
# "repo.issues"
# "repo.pulls"
# ];
# };
# security = {
# REVERSE_PROXY_TRUSTED_PROXIES = "127.0.0.0/8,::1/128";
# };
# server = rec {
# HTTP_PORT = 9960;
# DOMAIN = "forge.capytal.company";
# ROOT_URL = "https://${DOMAIN}";
# };
# service = {
# DISABLE_REGISTRATION = true;
# };
# storage = {
# STORAGE_TYPE = "minio";
# MINIO_USE_SSL = false;
# MINIO_ENDPOINT = "127.0.0.1:3461";
# MINIO_BUCKET = "forgejo";
# MINIO_LOCATION = config.services.garage.settings.s3_api.s3_region;
# };
# ui = {
# # DEFAULT_THEME = "capytal-dark";
# };
# };
# secrets = {
# storage = {
# MINIO_ACCESS_KEY_ID = "${config.sops.secrets."forgejo/s3/key".path}";
# MINIO_SECRET_ACCESS_KEY = "${config.sops.secrets."forgejo/s3/secret".path}";
# };
# };
# };
# services.gitea-actions-runner = {
# package = pkgs.forgejo-actions-runner;
# instances = {
# "forgejo-runner-1" = {
# enable = true;
# name = "Forgejo Runner (${config.networking.hostName}) 1";
# url = config.services.forgejo.settings.server.ROOT_URL;
# tokenFile = config.sops.secrets."forgejo/actions/token".path;
# labels = [
# "alpine-3.22:docker://data.forgejo.org/oci/alpine:3.22"
# "golang-1.24:docker://data.forgejo.org/oci/golang:1.24-alpine3.22"
# "node-24:docker://node:24-bullseye"
# ];
# };
# };
# };
#
# users.users."${cfg.user}".packages = [
# (pkgs.symlinkJoin {
# paths = [pkgs.forgejo];
# buildInputs = [pkgs.makeWrapper];
# postFixup = ''
# wrapProgram $out/bin/gitea \
# --add-flags --config '${cfg.customDir}/conf/app.ini'
# '';
# inherit (pkgs.forgejo) name pname meta;
# })
# ];
#
# services.anubis.instances."forgejo" = {
# settings = {
# BIND = ":${toString (cfg.settings.server.HTTP_PORT + 2)}";
# BIND_NETWORK = "tcp";
# METRICS_BIND = ":${toString (cfg.settings.server.HTTP_PORT + 3)}";
# METRICS_BIND_NETWORK = "tcp";
# SERVE_ROBOTS_TXT = true;
# TARGET = "http://localhost:${toString cfg.settings.server.HTTP_PORT}";
# ED25519_PRIVATE_KEY_HEX_FILE = config.sops.secrets."anubis/forgejo/hex_file".path;
# };
# };
# services.caddy.virtualHosts.":${toString (cfg.settings.server.HTTP_PORT + 1)}" = {
# extraConfig = ''
# reverse_proxy http://localhost${config.services.anubis.instances."forgejo".settings.BIND} {
# header_up X-Real-Ip {remote_host}
# }
# '';
# };
}