Skip to content

Commit 8e108b4

Browse files
explodedclaude
andcommitted
Fix deployment: stop service before binary replace, add self-update
The deploy script was failing with "Text file busy" because it tried to overwrite the running binary with cp. Three-part fix: 1. scripts/deploy-moon (new standalone copy of server-side script): - Self-update: if bundle contains a newer version of this script, install it and re-exec before doing anything else - Stop the service (systemctl stop moon) before copying the binary - Use rm -f before cp to handle "Text file busy" even as a fallback 2. scripts/server-setup.sh: embed the same improved deploy-moon so re-running the setup script updates the server-side copy; also add NOPASSWD sudoers entry for "systemctl stop moon" 3. .github/workflows/deploy.yml: - Include scripts/deploy-moon in the SCP bundle so the server copy auto-updates on every deployment - Add continue-on-error: true to the "Stop service" step so the deploy still proceeds even if sudoers hasn't been updated yet One-time manual step required: SSH into the server and run sudo bash scripts/server-setup.sh to install the fixed deploy-moon and updated sudoers. After that, all future deployments will be fully automated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ab1ff8c commit 8e108b4

File tree

3 files changed

+82
-3
lines changed

3 files changed

+82
-3
lines changed

.github/workflows/deploy.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,12 @@ jobs:
5353
username: ${{ secrets.DEPLOY_USER }}
5454
key: ${{ secrets.DEPLOY_SSH_KEY }}
5555
port: ${{ secrets.DEPLOY_PORT || '22' }}
56-
source: "moon,index.html,about.html,calendar.html,static/"
56+
source: "moon,index.html,about.html,calendar.html,static/,scripts/deploy-moon"
5757
target: "/tmp/moon-deploy"
5858
overwrite: true
5959

6060
- name: Stop service before deploy
61+
continue-on-error: true
6162
uses: appleboy/ssh-action@v1.0.3
6263
with:
6364
host: ${{ secrets.DEPLOY_HOST }}

scripts/deploy-moon

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/bin/bash
2+
# /usr/local/bin/deploy-moon
3+
# Runs as root (via sudo) during GitHub Actions deployments.
4+
#
5+
# To update this script on the server, include scripts/deploy-moon in the SCP
6+
# bundle — it will self-update and re-exec before doing anything else.
7+
8+
set -e
9+
10+
DEPLOY_SRC="${1:-/tmp/moon-deploy}"
11+
DEPLOY_DIR=/var/www/moon
12+
13+
# Self-update: if the bundle contains a newer version of this script, install
14+
# it and re-exec so the rest of the deployment runs with the updated logic.
15+
BUNDLE_SCRIPT="$DEPLOY_SRC/scripts/deploy-moon"
16+
if [ -f "$BUNDLE_SCRIPT" ] && ! diff -q /usr/local/bin/deploy-moon "$BUNDLE_SCRIPT" > /dev/null 2>&1; then
17+
echo "[deploy] Updating deploy script from bundle..."
18+
install -m 755 "$BUNDLE_SCRIPT" /usr/local/bin/deploy-moon
19+
exec /usr/local/bin/deploy-moon "$@"
20+
fi
21+
22+
# Read the service owner from the installed unit — no hardcoded username
23+
SERVICE_USER=$(systemctl show moon --property=User --value)
24+
SERVICE_GROUP=$(systemctl show moon --property=Group --value)
25+
26+
if [ -z "$SERVICE_USER" ]; then
27+
echo "[deploy] ERROR: Could not read User from moon.service"
28+
exit 1
29+
fi
30+
31+
echo "[deploy] Stopping service..."
32+
systemctl stop moon || true
33+
34+
echo "[deploy] Installing binary to $DEPLOY_DIR/moon (owner: $SERVICE_USER:$SERVICE_GROUP)..."
35+
rm -f "$DEPLOY_DIR/moon"
36+
cp "$DEPLOY_SRC/moon" "$DEPLOY_DIR/moon"
37+
chmod +x "$DEPLOY_DIR/moon"
38+
39+
echo "[deploy] Updating web assets..."
40+
cp "$DEPLOY_SRC/index.html" "$DEPLOY_DIR/"
41+
cp "$DEPLOY_SRC/about.html" "$DEPLOY_DIR/"
42+
cp "$DEPLOY_SRC/calendar.html" "$DEPLOY_DIR/"
43+
cp -r "$DEPLOY_SRC/static/" "$DEPLOY_DIR/"
44+
chown -R "$SERVICE_USER:$SERVICE_GROUP" "$DEPLOY_DIR"
45+
46+
echo "[deploy] Starting service..."
47+
systemctl start moon
48+
49+
echo "[deploy] Verifying service is active..."
50+
sleep 2
51+
if ! systemctl is-active --quiet moon; then
52+
echo "[deploy] ERROR: Service failed to start. Status:"
53+
systemctl status moon --no-pager --lines=30
54+
exit 1
55+
fi
56+
57+
echo "[deploy] Cleaning up..."
58+
rm -rf "$DEPLOY_SRC"
59+
60+
echo "[deploy] Done — moon is running."

scripts/server-setup.sh

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,24 @@ cat > /usr/local/bin/deploy-moon << 'DEPLOY_SCRIPT'
6262
#!/bin/bash
6363
# /usr/local/bin/deploy-moon
6464
# Runs as root (via sudo) during GitHub Actions deployments.
65+
#
66+
# To update this script on the server, include scripts/deploy-moon in the SCP
67+
# bundle — it will self-update and re-exec before doing anything else.
6568
6669
set -e
6770
6871
DEPLOY_SRC="${1:-/tmp/moon-deploy}"
6972
DEPLOY_DIR=/var/www/moon
7073
74+
# Self-update: if the bundle contains a newer version of this script, install
75+
# it and re-exec so the rest of the deployment runs with the updated logic.
76+
BUNDLE_SCRIPT="$DEPLOY_SRC/scripts/deploy-moon"
77+
if [ -f "$BUNDLE_SCRIPT" ] && ! diff -q /usr/local/bin/deploy-moon "$BUNDLE_SCRIPT" > /dev/null 2>&1; then
78+
echo "[deploy] Updating deploy script from bundle..."
79+
install -m 755 "$BUNDLE_SCRIPT" /usr/local/bin/deploy-moon
80+
exec /usr/local/bin/deploy-moon "$@"
81+
fi
82+
7183
# Read the service owner from the installed unit — no hardcoded username
7284
SERVICE_USER=$(systemctl show moon --property=User --value)
7385
SERVICE_GROUP=$(systemctl show moon --property=Group --value)
@@ -77,7 +89,11 @@ if [ -z "$SERVICE_USER" ]; then
7789
exit 1
7890
fi
7991
92+
echo "[deploy] Stopping service..."
93+
systemctl stop moon || true
94+
8095
echo "[deploy] Installing binary to $DEPLOY_DIR/moon (owner: $SERVICE_USER:$SERVICE_GROUP)..."
96+
rm -f "$DEPLOY_DIR/moon"
8197
cp "$DEPLOY_SRC/moon" "$DEPLOY_DIR/moon"
8298
chmod +x "$DEPLOY_DIR/moon"
8399
@@ -88,8 +104,8 @@ cp "$DEPLOY_SRC/calendar.html" "$DEPLOY_DIR/"
88104
cp -r "$DEPLOY_SRC/static/" "$DEPLOY_DIR/"
89105
chown -R "$SERVICE_USER:$SERVICE_GROUP" "$DEPLOY_DIR"
90106
91-
echo "[deploy] Restarting service..."
92-
systemctl restart moon
107+
echo "[deploy] Starting service..."
108+
systemctl start moon
93109
94110
echo "[deploy] Verifying service is active..."
95111
sleep 2
@@ -116,6 +132,8 @@ SUDOERS_FILE="/etc/sudoers.d/moon-deploy"
116132
cat > "$SUDOERS_FILE" << 'EOF'
117133
# Allow the deploy user to run the moon deployment script as root
118134
deploy ALL=(ALL) NOPASSWD: /usr/local/bin/deploy-moon
135+
# Allow stopping the moon service directly (used by the GitHub Actions workflow)
136+
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop moon
119137
EOF
120138

121139
chmod 440 "$SUDOERS_FILE"

0 commit comments

Comments
 (0)