Essential Bash Scripts for Deploying Golang Backend Services
This guide walks through a complete set of Bash scripts for building, starting, stopping, upgrading, and rolling back a Go backend application, explains the required directory layout, and highlights signal handling to ensure reliable deployments.
Why Deployment Scripts Matter
Even seasoned developers need reliable deployment tools; a good set of scripts can automate building, launching, stopping, rolling back, and logging for Go backend services.
Directory Layout
All scripts reside in a single folder alongside a bin directory for compiled binaries and an app.log file for runtime logs.
bin # directory for compiled binaries
app.log # runtime log file
log.sh # tail logs
build.sh # compile the project
run.sh # launch a binary in background
start.sh # start latest version, backup previous
shutdown.sh# stop the running service
rollback.sh# revert to previous versionlog.sh
tail -f -n 200 app.log # show the last 200 lines in real timebuild.sh
The script sets project paths, selects a Git branch, pulls the latest code, builds the Go binary, and copies the result to a version‑specific file.
#!/bin/bash
baseProjectDir="/go/src/monitor"
targetDir="bin"
branch="master"
pwd=$(pwd)
targetFile=$(basename $pwd)
buildPkg="monitor"
gitPull() {
pushd .
cd "$baseProjectDir"
git checkout "$branch"
git pull
popd
}
goBuild() {
buildResult=$(go build -o "$targetDir/$targetFile" "$buildPkg" 2>&1)
if [ -z "$buildResult" ]; then
buildResult="success"
fi
}
gitPull
goBuild
if [ "$buildResult" = "success" ]; then
cp $targetDir/$targetFile $targetFile-new
chmod +x $targetFile-new
else
echo "build error $buildResult"
exit 1
fi
echo "All Complete"run.sh
#!/bin/bash
# launch the binary in background and redirect output to app.log
nohup ./$1 >> app.log &start.sh
Stops any existing version, optionally forces termination, backs up the old binary, replaces it with the newly built one, and starts the service.
#!/bin/bash
pwd=$(pwd)
target=$(basename $pwd)
pid=$(ps -C $target -o pid=)
if [ -n "$pid" ]; then
echo "Stopping old version, PID: $pid"
if [ "$1" = "-f" ]; then
echo "Force shutdown..."
kill -9 $(ps -C $target -o pid=)
else
kill -s 2 $(ps -C $target -o pid=)
fi
while [ -n "$(ps -C $target -o pid=)" ]; do sleep 1; done
fi
if [ -f "${target}-new" ]; then
echo "Upgrading..."
if [ -f "${target}-backup" ]; then
backupdt=$(date +%Y%m%d-%H)
mv "${target}-backup" "${target}-backup-$backupdt"
fi
mv $target ${target}-backup
mv ${target}-new $target
echo "Upgrade Complete"
fi
echo "Starting..."
./run.sh $target
echo "Done"shutdown.sh
Identical to the stop portion of start.sh but does not perform an upgrade.
#!/bin/bash
pwd=$(pwd)
target=$(basename $pwd)
pid=$(ps -C $target -o pid=)
if [ -n "$pid" ]; then
echo "Stopping old version, PID: $pid"
if [ "$1" = "-f" ]; then
echo "Force shutdown..."
kill -9 $(ps -C $target -o pid=)
else
kill -s 2 $(ps -C $target -o pid=)
fi
while [ -n "$(ps -C $target -o pid=)" ]; do sleep 1; done
fi
echo "Done"rollback.sh
Stops the current binary, restores the previously backed‑up version, and restarts it.
#!/bin/bash
pwd=$(pwd)
target=$(basename $pwd)
pid=$(ps -C $target -o pid=)
if [ -n "$pid" ]; then
echo "Stopping old version, PID: $pid"
if [ "$1" = "-f" ]; then
echo "Force shutdown..."
kill $(ps -C $target -o pid=)
else
kill -s 2 $(ps -C $target -o pid=)
fi
while [ -n "$(ps -C $target -o pid=)" ]; do sleep 1; done
fi
if [ -f "${target}-backup" ]; then
echo "Rolling back..."
rm -f "$target"
mv ${target}-backup $target
echo "Rollback Complete"
fi
echo "Starting..."
./run.sh $target
echo "Done"Signal Handling in Go
When kill -s 2 is used, the Go program must listen for os.Interrupt (SIGINT) to exit cleanly. A minimal example:
package main
import (
"log"
"os"
"os/signal"
"github.com/robfig/cron"
)
func main() {
c := cron.New()
c.AddFunc("*/3 * * * * ?", func(){ log.Println("cron running") })
c.Start()
go signalListen()
select {}
}
func signalListen() {
ch := make(chan os.Signal)
signal.Notify(ch, os.Interrupt, os.Kill)
for {
<-ch
os.Exit(0)
}
}These scripts together provide a lightweight, reproducible deployment workflow for Go backend services without requiring external tools like Make or CI pipelines.
Go Development Architecture Practice
Daily sharing of Golang-related technical articles, practical resources, language news, tutorials, real-world projects, and more. Looking forward to growing together. Let's go!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
