deploy/cloud-init.yaml
237 lines · 7653 bytes
1#cloud-config
2# gitbay VPS bootstrap (Ubuntu 24.04).
3#
4# What this does on first boot:
5# - moves the host's admin sshd to port 2222 (gitbay's embedded SSH
6# listener owns port 22) — CONNECT ON 2222 AFTER FIRST BOOT
7# - creates the unprivileged gitbay user and directory layout
8# - installs /etc/gitbay/config.toml, the systemd unit (with
9# CAP_NET_BIND_SERVICE so ports 22/80/443 work without root), and a
10# nightly backup timer
11# - opens ufw for 22, 80, 443, 2222
12#
13# It does NOT install the gitbayd binary (it is not hosted anywhere yet);
14# scp it to /usr/local/bin/gitbayd afterward and `systemctl start gitbayd`.
15
16package_update: true
17packages:
18 - git
19 - ufw
20 - unattended-upgrades
21 - fail2ban
22
23write_files:
24 # Admin sshd on 2222. Ubuntu 24.04 socket-activates sshd, so the port
25 # must change in BOTH sshd_config and the socket unit.
26 - path: /etc/ssh/sshd_config.d/60-gitbay-port.conf
27 content: |
28 Port 2222
29 PasswordAuthentication no
30 # Throttle unauthenticated connection floods on the admin sshd
31 # (gitbayd's own port 22 is throttled by limits.ssh_auth_rate).
32 MaxStartups 10:30:60
33 MaxAuthTries 3
34 LoginGraceTime 20
35
36 # OS security patches applied automatically; reboot at 04:30 if needed.
37 - path: /etc/apt/apt.conf.d/51gitbay-unattended
38 content: |
39 Unattended-Upgrade::Allowed-Origins { "${distro_id}:${distro_codename}-security"; };
40 Unattended-Upgrade::Automatic-Reboot "true";
41 Unattended-Upgrade::Automatic-Reboot-Time "04:30";
42 APT::Periodic::Update-Package-Lists "1";
43 APT::Periodic::Unattended-Upgrade "1";
44
45 # fail2ban watches the admin sshd for auth failures.
46 - path: /etc/fail2ban/jail.d/gitbay.conf
47 content: |
48 [sshd]
49 enabled = true
50 port = 2222
51 backend = systemd
52 maxretry = 5
53 bantime = 1h
54
55 # Heartbeat: post disk/service/cert status to a webhook if one is set in
56 # /etc/gitbay/monitor.url. Silent when the file is absent.
57 - path: /usr/local/bin/gitbay-monitor.sh
58 permissions: "0755"
59 content: |
60 #!/bin/sh
61 set -eu
62 url_file=/etc/gitbay/monitor.url
63 [ -f "$url_file" ] || exit 0
64 url=$(cat "$url_file")
65 disk=$(df -P /var/lib/gitbay | awk 'NR==2{print $5}')
66 svc=$(systemctl is-active gitbayd || true)
67 # Days until the ACME cert expires, if autocert cached one.
68 cert=/var/lib/gitbay/autocert
69 exp="n/a"
70 if [ -d "$cert" ]; then
71 f=$(ls -1 "$cert" 2>/dev/null | grep -v acme_account | head -1 || true)
72 [ -n "$f" ] && exp=$(openssl x509 -enddate -noout -in "$cert/$f" 2>/dev/null | cut -d= -f2 || echo n/a)
73 fi
74 alert=""
75 [ "$svc" != "active" ] && alert="gitbayd is $svc; "
76 pct=$(echo "$disk" | tr -d '%')
77 [ "$pct" -ge 85 ] && alert="${alert}disk ${disk}; "
78 body=$(printf '{"disk":"%s","service":"%s","cert_expires":"%s","alert":"%s"}' "$disk" "$svc" "$exp" "$alert")
79 curl -fsS -m 10 -H 'Content-Type: application/json' -d "$body" "$url" >/dev/null 2>&1 || true
80
81 - path: /etc/systemd/system/gitbay-monitor.service
82 content: |
83 [Unit]
84 Description=gitbay host heartbeat
85 [Service]
86 Type=oneshot
87 ExecStart=/usr/local/bin/gitbay-monitor.sh
88
89 - path: /etc/systemd/system/gitbay-monitor.timer
90 content: |
91 [Unit]
92 Description=gitbay host heartbeat
93 [Timer]
94 OnCalendar=*-*-* *:00:00 UTC
95 Persistent=true
96 [Install]
97 WantedBy=timers.target
98 - path: /etc/systemd/system/ssh.socket.d/override.conf
99 content: |
100 [Socket]
101 ListenStream=
102 ListenStream=2222
103
104 - path: /etc/gitbay/config.toml
105 permissions: "0640"
106 content: |
107 [server]
108 root = "/var/lib/gitbay"
109 site_url = "https://gitbay.org"
110
111 [ssh]
112 mode = "embedded"
113 port = 22
114
115 [http]
116 addr = ":443"
117 tls = "acme"
118 acme_email = "hello@gitbay.org"
119 acme_http_addr = ":80"
120
121 [web]
122 mode = "view_only"
123
124 [registration]
125 mode = "closed"
126
127 - path: /etc/systemd/system/gitbayd.service
128 content: |
129 [Unit]
130 Description=gitbay forge daemon
131 After=network-online.target
132 Wants=network-online.target
133
134 [Service]
135 User=gitbay
136 Group=gitbay
137 ExecStart=/usr/local/bin/gitbayd --config /etc/gitbay/config.toml serve
138 Restart=on-failure
139 RestartSec=3
140
141 # Bind 22/80/443 without root; no privilege escalation afterward.
142 AmbientCapabilities=CAP_NET_BIND_SERVICE
143 CapabilityBoundingSet=CAP_NET_BIND_SERVICE
144 NoNewPrivileges=yes
145 ProtectSystem=strict
146 ProtectHome=yes
147 ReadWritePaths=/var/lib/gitbay /var/backups/gitbay
148 PrivateTmp=yes
149 ProtectKernelTunables=yes
150 ProtectKernelModules=yes
151 ProtectControlGroups=yes
152 ProtectHostname=yes
153 ProtectClock=yes
154 ProtectKernelLogs=yes
155 RestrictSUIDSGID=yes
156 RestrictNamespaces=yes
157 RestrictRealtime=yes
158 LockPersonality=yes
159 MemoryDenyWriteExecute=yes
160 PrivateDevices=yes
161 # IPv4/IPv6 for listeners and outbound git/ssh; UNIX for the hook socket.
162 RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
163 # Allow only ordinary service syscalls; the daemon spawns git and ssh,
164 # so keep @process/@exec available (both are within @system-service).
165 SystemCallFilter=@system-service
166 SystemCallErrorNumber=EPERM
167 SystemCallArchitectures=native
168
169 [Install]
170 WantedBy=multi-user.target
171
172 - path: /usr/local/bin/gitbay-backup.sh
173 permissions: "0755"
174 content: |
175 #!/bin/sh
176 # Nightly consistent backup; keeps the last 7 locally.
177 # To ship offsite, add an rclone/s3 upload of $out here.
178 set -eu
179 dir=/var/backups/gitbay
180 out="$dir/gitbay-$(date -u +%Y%m%d-%H%M%S).tar.gz"
181 /usr/local/bin/gitbayd --config /etc/gitbay/config.toml admin backup --out "$out"
182 ls -1t "$dir"/gitbay-*.tar.gz | tail -n +8 | xargs -r rm --
183
184 - path: /etc/systemd/system/gitbay-backup.service
185 content: |
186 [Unit]
187 Description=gitbay nightly backup
188 [Service]
189 Type=oneshot
190 User=gitbay
191 ExecStart=/usr/local/bin/gitbay-backup.sh
192
193 - path: /etc/systemd/system/gitbay-backup.timer
194 content: |
195 [Unit]
196 Description=gitbay nightly backup
197 [Timer]
198 OnCalendar=*-*-* 09:00:00 UTC
199 RandomizedDelaySec=15m
200 Persistent=true
201 [Install]
202 WantedBy=timers.target
203
204 - path: /etc/systemd/system/gitbay-gc.service
205 content: |
206 [Unit]
207 Description=gitbay weekly repository maintenance
208 [Service]
209 Type=oneshot
210 User=gitbay
211 ExecStart=/usr/local/bin/gitbayd --config /etc/gitbay/config.toml admin gc
212
213 - path: /etc/systemd/system/gitbay-gc.timer
214 content: |
215 [Unit]
216 Description=gitbay weekly repository maintenance
217 [Timer]
218 OnCalendar=Sun *-*-* 07:00:00 UTC
219 RandomizedDelaySec=30m
220 Persistent=true
221 [Install]
222 WantedBy=timers.target
223
224runcmd:
225 - adduser --system --group --home /var/lib/gitbay --shell /usr/sbin/nologin gitbay
226 - install -d -o gitbay -g gitbay -m 750 /var/lib/gitbay /var/backups/gitbay
227 - chgrp gitbay /etc/gitbay/config.toml /etc/gitbay
228 - ufw allow 22/tcp
229 - ufw allow 80/tcp
230 - ufw allow 443/tcp
231 - ufw allow 2222/tcp
232 - ufw --force enable
233 - systemctl daemon-reload
234 - systemctl restart ssh.socket || systemctl restart ssh
235 - systemctl enable gitbayd gitbay-backup.timer gitbay-gc.timer gitbay-monitor.timer
236 - systemctl start gitbay-backup.timer gitbay-gc.timer gitbay-monitor.timer
237 - systemctl enable --now unattended-upgrades fail2ban