Created
September 6, 2024 07:06
-
-
Save lambrospetrou/aaaa13344f0026d810700f1bd2601cfd to your computer and use it in GitHub Desktop.
Simple deployment on a VPS, Hetzner, EC2 with zero downtime. Uses Caddy and systemd.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Inspired from: | |
# - https://blog.wesleyac.com/posts/simple-deploy-script | |
# - https://gist.github.com/WesleyAC/b3aaa0292579158ad566c140415c875d | |
# - https://caddyserver.com/docs/running#using-the-service | |
set -e | |
# cd $(dirname $0) | |
if [ "$#" -ne 1 ]; then | |
echo "usage: $0 user@server-address" | |
exit 1 | |
fi | |
SERVER_SSH=$1 | |
SERVER_PATH=/opt/apps_workspace/monosource-server | |
BINARY_NAME="monosource-server" | |
SERVER_RESTART_COMMAND="systemctl restart $BINARY_NAME" | |
SYSTEMD_FILE="monosource-server.service" | |
SYSTEMD_DAEMONRELOAD_COMMAND="systemctl daemon-reload" | |
# https://caddyserver.com/docs/running#unit-files | |
CADDY_RESTART_COMMAND="systemctl reload caddy" | |
CADDYFILE="monosource-server-Caddyfile" | |
# Assume the script will be run inside the `server-src/` directory. | |
OUTFILE="./build/$BINARY_NAME" | |
ENVFILENAME=".env.prod.local" | |
ENVFILE="./build/$ENVFILENAME" | |
# COMMIT_HASH=$(git rev-parse HEAD) | |
COMMIT_HASH="commit_unknown" | |
BUILD_TIMESTAMP=$(TZ=UTC date -u +"%Y%m%d_%H%M%S") | |
FILE_HASH=$(b2sum $OUTFILE | cut -f1 -d' ') | |
REMOTE_FILENAME="$BINARY_NAME-$BUILD_TIMESTAMP-$COMMIT_HASH-$FILE_HASH" | |
echo "Deploying: $REMOTE_FILENAME" | |
# Copy necessary files from current version. | |
scp "$OUTFILE" "$SERVER_SSH:/tmp/$REMOTE_FILENAME" | |
scp "$ENVFILE" "$SERVER_SSH:/tmp/$REMOTE_FILENAME-$ENVFILENAME" | |
scp "_tools/files/etc/caddy/sites-enabled/$CADDYFILE" "$SERVER_SSH:/tmp/$REMOTE_FILENAME-$CADDYFILE" | |
scp "_tools/files/etc/systemd/system/$SYSTEMD_FILE" "$SERVER_SSH:/tmp/$REMOTE_FILENAME-$SYSTEMD_FILE" | |
# Put the latest files in the right directories and restart everything without downtime. | |
ssh -q -Tt $SERVER_SSH <<EOL | |
sudo nohup sh -c "\ | |
mkdir -p $SERVER_PATH/versions/ $SERVER_PATH/current/ /etc/caddy/sites-enabled/ && \ | |
mv "/tmp/$REMOTE_FILENAME-$CADDYFILE" "/etc/caddy/sites-enabled/$CADDYFILE" && \ | |
$CADDY_RESTART_COMMAND && \ | |
mv "/tmp/$REMOTE_FILENAME-$SYSTEMD_FILE" "/etc/systemd/system/$SYSTEMD_FILE" && \ | |
$SYSTEMD_DAEMONRELOAD_COMMAND && \ | |
mv "/tmp/$REMOTE_FILENAME-$ENVFILENAME" "$SERVER_PATH/current/$ENVFILENAME" && \ | |
mv "/tmp/$REMOTE_FILENAME" "$SERVER_PATH/versions/$REMOTE_FILENAME" && \ | |
chmod +x "$SERVER_PATH/versions/$REMOTE_FILENAME" && \ | |
rm -f "$SERVER_PATH/current/$BINARY_NAME" && \ | |
ln -s "$SERVER_PATH/versions/$REMOTE_FILENAME" "$SERVER_PATH/current/$BINARY_NAME" && \ | |
$SERVER_RESTART_COMMAND" | |
EOL | |
echo "Deleting older versions, retaining the latest 10!" | |
# Cleanup old versions, and retain the last 10 deployed. | |
# For each version we copy the application binary in the /versions/ dir. | |
# So, in order to retain 10x versions we need to keep the top 10 lines when | |
# sorted with the latest files at the top, and start removing from line 11! | |
# Attention: If you have less than 10 deployments already this will fail, but it's fine. | |
ssh -q -Tt $SERVER_SSH <<EOL | |
sudo nohup sh -c "find "$SERVER_PATH/versions/" -type f -exec realpath {} \; | sort -r | tail -n +11 | sudo xargs rm" | |
EOL |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This Caddyfile assumes that the entry point Caddyfile is: | |
# $ cat /etc/caddy/Caddyfile | |
# | |
# import sites-enabled/* | |
# | |
# The above import line is the only thing needed in "/etc/caddy/Caddyfile". | |
:80, :443 { | |
reverse_proxy http://127.0.0.1:8080 { | |
header_up Host {host} | |
header_up X-Real-IP {remote} | |
# This gives 10s of buffering to allow zero downtime restarts of the service. | |
lb_try_duration 10s | |
} | |
request_body { | |
max_size 1M | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Unit] | |
Description=Monosource Server | |
After=network.target | |
[Service] | |
ExecStart=/opt/apps_workspace/monosource-server/current/monosource-server | |
User=appuser | |
Group=appadmins | |
WorkingDirectory=/opt/apps_workspace/monosource-server/current/ | |
Restart=always | |
RestartSec=5 | |
StandardOutput=journal | |
StandardError=journal | |
[Install] | |
WantedBy=multi-user.target |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment