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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
#!/usr/bin/env bash
#
# deploy.sh — build custard for linux/amd64 and deploy it behind Caddy + systemd.
# Reads deploy/deploy.env (copy from deploy.env.example). Idempotent; re-run to
# update. Generates the Caddyfile + systemd unit from your settings — nothing to
# hand-edit on the server.
#
set -euo pipefail
cd "$(dirname "$0")/.."
ENV_FILE="deploy/deploy.env"
if [ ! -f "$ENV_FILE" ]; then
echo "missing $ENV_FILE — copy deploy/deploy.env.example to it and fill in your values" >&2
exit 1
fi
set -a; . "$ENV_FILE"; set +a
: "${REMOTE:?set REMOTE in deploy.env}"
: "${DOMAIN:?set DOMAIN in deploy.env}"
: "${RUN_USER:?set RUN_USER in deploy.env}"
: "${REPOS_PATH:?set REPOS_PATH in deploy.env}"
SOFT_SERVE_DB="${SOFT_SERVE_DB:-}"
SOFT_SERVE_BACKEND="${SOFT_SERVE_BACKEND:-}"
WEBHOOK_SECRET="${WEBHOOK_SECRET:-}"
TAP_REPO="${TAP_REPO:-homebrew-tap}"
DL_PATH="/var/lib/custard/dl"
echo "==> building static linux/amd64 binary"
command -v templ >/dev/null 2>&1 && templ generate
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /tmp/custard-linux ./cmd/custard
echo "==> rendering Caddyfile + unit for $DOMAIN"
gitblock=""
if [ -n "$SOFT_SERVE_BACKEND" ]; then
gitblock=" handle_path /git/* {
reverse_proxy $SOFT_SERVE_BACKEND
}
"
fi
cat > /tmp/custard.Caddyfile <<EOF
# Generated by custard deploy.sh — do not edit by hand.
${DOMAIN} {
encode gzip zstd
${gitblock} handle_path /dl/* {
root * /var/lib/custard/dl
file_server browse
}
reverse_proxy 127.0.0.1:8080
}
EOF
dbflag=""
[ -n "$SOFT_SERVE_DB" ] && dbflag=" --soft-serve-db ${SOFT_SERVE_DB}"
cat > /tmp/custard.service <<EOF
[Unit]
Description=custard — web code forge
After=network-online.target
Wants=network-online.target
[Service]
User=${RUN_USER}
Group=${RUN_USER}
EnvironmentFile=-/etc/custard.env
ExecStart=/usr/local/bin/custard --repos ${REPOS_PATH} --addr 127.0.0.1:8080 --base-url https://${DOMAIN} --soft-serve-http https://${DOMAIN}/git --tap-repo ${TAP_REPO} --dl-path ${DL_PATH}${dbflag}
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
ReadOnlyPaths=${REPOS_PATH}
# custard writes only the tap repo (formula commits) and the download dir.
ReadWritePaths=${REPOS_PATH}/${TAP_REPO}.git ${DL_PATH}
[Install]
WantedBy=multi-user.target
EOF
echo "==> uploading to $REMOTE"
scp -q /tmp/custard-linux "$REMOTE:/usr/local/bin/custard.new"
scp -q /tmp/custard.service "$REMOTE:/etc/systemd/system/custard.service"
scp -q /tmp/custard.Caddyfile "$REMOTE:/tmp/custard.Caddyfile"
# Webhook secret → root-only env file (not process args). Empty file if unset.
if [ -n "$WEBHOOK_SECRET" ]; then
printf 'WEBHOOK_SECRET=%s\n' "$WEBHOOK_SECRET" > /tmp/custard.env
else
: > /tmp/custard.env
fi
scp -q /tmp/custard.env "$REMOTE:/tmp/custard.env"
# Download dir owned by the run user (custard writes), world-readable (Caddy serves).
ssh "$REMOTE" "install -d -o ${RUN_USER} -g ${RUN_USER} -m 755 ${DL_PATH} && install -m 600 /tmp/custard.env /etc/custard.env && rm -f /tmp/custard.env"
echo "==> installing on remote"
ssh "$REMOTE" 'bash -seu' <<'REMOTE_EOF'
if ! command -v caddy >/dev/null 2>&1; then
echo "installing caddy..."
apt-get install -y -q debian-keyring debian-archive-keyring apt-transport-https curl >/dev/null 2>&1
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' > /etc/apt/sources.list.d/caddy-stable.list
apt-get update -q >/dev/null 2>&1 && apt-get install -y -q caddy >/dev/null 2>&1
fi
install -d -o caddy -g caddy /etc/caddy
mv /tmp/custard.Caddyfile /etc/caddy/Caddyfile
mv /usr/local/bin/custard.new /usr/local/bin/custard
chmod +x /usr/local/bin/custard
systemctl daemon-reload
systemctl enable --now custard >/dev/null 2>&1 || true
systemctl restart custard
caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile >/dev/null && { systemctl reload caddy || systemctl restart caddy; }
sleep 1
echo " custard: $(systemctl is-active custard) caddy: $(systemctl is-active caddy)"
curl -s -o /dev/null -w ' local probe -> %{http_code}\n' http://127.0.0.1:8080/ || true
REMOTE_EOF
echo "==> done → https://${DOMAIN}"
|