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.

Go Development Architecture Practice
Go Development Architecture Practice
Go Development Architecture Practice
Essential Bash Scripts for Deploying Golang Backend Services

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 version

log.sh

tail -f -n 200 app.log  # show the last 200 lines in real time

build.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.

backendGolangbashscripts
Go Development Architecture Practice
Written by

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!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.