deploy/cloud-init.yaml

v0.5.0
gitbay/deploy/cloud-init.yaml history · blame · raw

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