-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeploy.sh
More file actions
executable file
·157 lines (136 loc) · 6.11 KB
/
deploy.sh
File metadata and controls
executable file
·157 lines (136 loc) · 6.11 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env bash
set -Eeuo pipefail
umask 022
# ── config ──────────────────────────────────────────────────────────────
SITE="cob.musicsian.com"
WEB_ROOT="/var/www/$SITE"
RELEASES="$WEB_ROOT/releases"
CURRENT="$WEB_ROOT/current"
STAMP="${1:-$(date +%Y-%m-%d-%H%M%S)}" # you can pass a stamp manually if you want
KEEP="${KEEP:-10}" # how many releases to keep
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
STAGE="${STAGE_DIR:-$HOME/builds/$SITE/$STAMP}"
# ── ensure dirs exist ───────────────────────────────────────────────────
echo "▶ Ensure web root"
sudo install -d -m 0755 "$WEB_ROOT"
sudo install -d -m 0755 "$RELEASES"
# ── stage ───────────────────────────────────────────────────────────────
echo "▶ Stage files → $STAGE"
mkdir -p "$STAGE"
# Only ship the static site files we care about
rsync -az --delete \
--include '/index.html' \
--include '/favicon.ico' \
--include '/css/***' \
--include '/js/***' \
--exclude '*' \
"$PROJECT_DIR"/ "$STAGE"/
echo "▶ Verify staged content"
ls -l "$STAGE"
test -f "$STAGE/index.html" || { echo "✗ index.html missing in stage"; exit 1; }
test -d "$STAGE/css" || { echo "✗ css/ missing in stage"; exit 1; }
test -d "$STAGE/js" || { echo "✗ js/ missing in stage"; exit 1; }
# ── publish ─────────────────────────────────────────────────────────────
echo "▶ Publish → $RELEASES/$STAMP"
sudo rsync -az --delete "$STAGE"/ "$RELEASES/$STAMP"/
echo "▶ Verify release contents"
sudo test -f "$RELEASES/$STAMP/index.html" || { echo "✗ index.html missing in release"; exit 1; }
sudo test -d "$RELEASES/$STAMP/css" || { echo "✗ css/ missing in release"; exit 1; }
sudo test -d "$RELEASES/$STAMP/js" || { echo "✗ js/ missing in release"; exit 1; }
# show release contents for debugging
echo "▶ Release contents:"
sudo ls -la "$RELEASES/$STAMP"
# ── harden perms & preflight readability (as nginx user) ────────────────
echo "▶ Fix ownership/permissions and preflight readability"
sudo chown -R root:root "$RELEASES/$STAMP"
sudo find "$RELEASES/$STAMP" -type d -exec chmod 0755 {} +
sudo find "$RELEASES/$STAMP" -type f -exec chmod 0644 {} +
NGINX_USER="nginx"
if id "$NGINX_USER" >/dev/null 2>&1; then
sudo -u "$NGINX_USER" test -r "$RELEASES/$STAMP/index.html" || { echo "✗ nginx user cannot read index.html"; exit 1; }
else
echo "! Warn: nginx user '$NGINX_USER' not found; skipping readability check"
fi
# ── flip symlink (with rollback trap) ───────────────────────────────────
echo "▶ Flip symlink"
# Save previous target for potential rollback
prev="$(readlink -f "$CURRENT" 2>/dev/null || true)"
if [[ -n "$prev" ]]; then
echo " Previous release: $prev"
fi
# FIXED: Remove old symlink first, then create new one atomically
if [[ -L "$CURRENT" ]]; then
sudo rm -f "$CURRENT"
fi
sudo ln -sfn "$RELEASES/$STAMP" "$CURRENT"
# Verify the symlink is correct
echo "▶ Verify symlink"
if [[ ! -L "$CURRENT" ]]; then
echo "✗ $CURRENT is not a symlink"
exit 1
fi
LINK_TARGET="$(readlink -f "$CURRENT")"
echo " Current → $LINK_TARGET"
# Ensure the symlink points to the right place
if [[ "$LINK_TARGET" != "$RELEASES/$STAMP" ]]; then
echo "✗ Symlink points to wrong location"
echo " Expected: $RELEASES/$STAMP"
echo " Got: $LINK_TARGET"
exit 1
fi
# Ensure the flipped target is actually valid
if ! sudo test -f "$CURRENT/index.html"; then
echo "✗ current release missing index.html; rolling back"
if [[ -n "${prev:-}" ]] && [[ -d "$prev" ]]; then
sudo ln -sfn "$prev" "$CURRENT"
fi
exit 1
fi
# Setup rollback function
rollback() {
echo "⚠️ Rolling back symlink to previous release"
if [[ -n "${prev:-}" ]] && [[ -d "$prev" ]]; then
sudo ln -sfn "$prev" "$CURRENT"
echo " Rolled back to: $prev"
else
echo " No previous release to rollback to"
fi
}
trap 'rollback' ERR
# ── selinux restore (safe if SELinux is permissive/disabled) ────────────
echo "▶ Restore SELinux context"
sudo restorecon -Rv "$RELEASES/$STAMP" >/dev/null 2>&1 || true
sudo restorecon -v "$CURRENT" >/dev/null 2>&1 || true
# ── quick health check (non-fatal) ─────────────────────────────────────
if command -v curl >/dev/null 2>&1; then
echo "▶ Health check: GET https://$SITE/"
if curl -fsS -o /dev/null -w " Status: %{http_code}\n" "https://$SITE/" --max-time 5; then
echo " ✓ Site responding"
else
echo " ⚠ Site health check failed (non-fatal)"
fi
fi
# ── nginx reload (only if config passes) ────────────────────────────────
echo "▶ Test & reload Nginx"
if sudo nginx -t 2>/dev/null; then
sudo systemctl reload nginx
echo " ✓ Nginx reloaded"
else
echo "✗ nginx -t failed"
exit 1
fi
# ── prune old releases ──────────────────────────────────────────────────
echo "▶ Prune old releases (keep $KEEP)"
# FIXED: Exclude the current release from pruning
CURRENT_RELEASE="$(basename "$(readlink -f "$CURRENT")")"
OLD_RELEASES=$(sudo bash -c "ls -1dt $RELEASES/* 2>/dev/null | grep -v '$CURRENT_RELEASE' | tail -n +$((KEEP+1))" || true)
if [[ -n "$OLD_RELEASES" ]]; then
echo "$OLD_RELEASES" | while read -r old_release; do
echo " Removing: $(basename "$old_release")"
done
echo "$OLD_RELEASES" | sudo xargs -r rm -rf
else
echo " No old releases to prune"
fi
echo "✓ Deployed $STAMP → $SITE"
echo " Live at: https://$SITE/"