deploy/cloud-init.yaml

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

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