1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
{ config, pkgs, lib, ... }:
# cgit - fast web interface for git repositories.
#
# Repositories live in /srv/git/<repo>.git (bare repos).
# Access model:
# - Web browsing: public, no auth (https://git.karanj.com)
# - git clone/pull over HTTPS: public, read-only via git-http-backend
# - git push: SSH only, using the "git" user + your authorized keys
#
# The NixOS cgit module serves both cgit browsing and git-http-backend
# (clone/pull, via gitHttpBackend.enable which defaults to true) on the
# *same* nginx vhost/location - nginx tells them apart by matching the
# request path against a regex (.../info/refs|git-upload-pack for the
# smart-HTTP protocol), not by a separate port. That combined vhost is
# bound to localhost:8086 below, and Caddy reverse-proxies everything
# for git.karanj.com straight to it. Only git-upload-pack is wired up, so
# push over HTTP is impossible regardless - push stays SSH-only.
{
# Dedicated git user for SSH push access
users.users.git = {
isSystemUser = true;
group = "git";
home = "/srv/git";
shell = pkgs.git;
# Allow pushing from both your devices
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAwAgL0o4NVonSG07Xu4Eai84ns4AjoZj2V7dGC9nXit karanjayachandra@Einstein.local"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH+qnLTnorv+I2rSSfGjNiCuX/W5AxoNgAdu+cTOyKzW Galileo"
];
};
users.groups.git = {};
# Repository root
#
# The git-shell-commands lines below add Git LFS support. git-shell's own
# hardcoded allowlist is exactly three commands - git-receive-pack,
# git-upload-pack, git-upload-archive (confirmed from git's own shell.c) -
# so a plain LFS-tracked push fails with "unrecognized command
# 'git-lfs-authenticate ...'" otherwise. The documented extension point is
# an executable file matching the command name in ~/git-shell-commands
# (~ being /srv/git, the git user's home above). Symlinking git-lfs-transfer
# there - nixpkgs' server-side implementation of Git LFS's pure-SSH
# protocol - is enough: git-lfs clients (v3.0+) already try this command
# automatically for SSH remotes before falling back to the HTTP-based
# git-lfs-authenticate flow, so nothing needs configuring client-side. This
# keeps LFS on the same SSH-only path as normal pushes, with no HTTP LFS
# server or tokens involved.
systemd.tmpfiles.rules = [
"d /srv/git 0755 git git -"
"d /srv/git/git-shell-commands 0750 git git -"
"L+ /srv/git/git-shell-commands/git-lfs-transfer - - - - ${pkgs.git-lfs-transfer}/bin/git-lfs-transfer"
];
# cgit web interface served via nginx + fcgiwrap
services.cgit."git.karanj.com" = {
enable = true;
scanPath = "/srv/git";
gitHttpBackend.checkExportOkFiles = false;
settings = {
# Site branding
root-title = "karan's git";
root-desc = "personal git repositories";
# Enable common features
enable-index-links = 1;
enable-commit-graph = 1;
enable-log-filecount = 1;
enable-log-linecount = 1;
enable-blame = 1;
enable-http-clone = 1; # show clone URL in UI
# Public clone URL prefix shown in the cgit UI
clone-url = "https://git.karanj.com/$CGIT_REPO_URL";
# Syntax highlighting
source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py";
about-filter = "${pkgs.cgit}/lib/cgit/filters/about-formatting.sh";
};
};
services.nginx.virtualHosts."git.karanj.com" = {
forceSSL = false;
enableACME = false;
listen = [ { addr = "127.0.0.1"; port = 8086; } ];
# Overrides the module's own `= /cgit.css` location (set with mkDefault,
# so any concrete value here wins) to serve cgit.css below instead of
# cgit's stock stylesheet - same variable-driven light/dark technique as
# ~/workspace/homepage's stylesheet, switching automatically via
# prefers-color-scheme with no JS or toggle.
locations."= /cgit.css".alias = "${./cgit.css}";
};
}
|