So, in a previous post I explained how one can backup all databases on a server, each in its own dump file. Let’s take it to the next level and make a Golang program that will let us run the dump process with a HTTP request.

Assuming you already have Go installed on the backup server, create first a project directory in your home folder for example. Copy the mysql dump script from here and save it as dump.sh in your project folder. Modify ROOTDIR="/backup/mysql/" inside dump.sh to reflect current project directory.

We will create a Golang script with two functions. One will launch the backup script when a specific HTTP request is done. The other one will put the HTTP call behind a authentication, so only people with credentials will be able to make the backup request.

package main

import (
	"encoding/base64"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"
)

var username = os.Getenv("DB_BACKUP_USER")
var password = os.Getenv("DB_BACKUP_PASSWORD")

func BasicAuth(w http.ResponseWriter, r *http.Request, user, pass string) bool {
	s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
	if len(s) != 2 {
		return false
	}
	b, err := base64.StdEncoding.DecodeString(s[1])
	if err != nil {
		return false
	}
	pair := strings.SplitN(string(b), ":", 2)
	if len(pair) != 2 {
		return false
	}
	return pair[0] == string(user) && pair[1] == string(pass)
}
func handler(w http.ResponseWriter, r *http.Request) {
	if BasicAuth(w, r, username, password) {
		cmd := exec.Command("bash", "dump.sh")
		stdout, err := cmd.Output()
		if err != nil {
			log.Fatal(err)
		}
		fmt.Fprintf(w, string(stdout))
		return
	}
	w.Header().Set("WWW-Authenticate", `Basic realm="Protected Page!!! "`)
	w.WriteHeader(401)
	w.Write([]byte("401 Unauthorized\n"))
}

func main() {
	http.HandleFunc("/backup", handler)
	http.ListenAndServe(":8080", nil)
}

This uses DB_BACKUP_USER and DB_BACKUP_PASSWORD that you will have to set as environment variables. Just append this to your ~/.bashrc file

export DB_BACKUP_USER="hello"
export DB_BACKUP_PASSWORD="password"

Now run source ~/.bashrc to load them.

Build the executable with go build http-db-backup.go where http-db-backup.go is the name of your Go file. Now you need to run the executable with sudo, but while preserving the environment: sudo -E ./http-db-backup

Now if you open your browser and open http://111.222.333.444:8080/backup (where 111.222.333.444 is your backup machine IP) the backup process will start, and you will get the output of the dump.sh in your browser when backup finishes.

We can furthermore add another function to list the directory in browser, so you can download the needed backup or backups.

func lister(w http.ResponseWriter, r *http.Request) {
	if BasicAuth(w, r, username, password) {
		http.FileServer(http.Dir(".")).ServeHTTP(w, r)
		return
	}
	w.Header().Set("WWW-Authenticate", `Basic realm="Protected Page!!! "`)
	w.WriteHeader(401)
	w.Write([]byte("401 Unauthorized\n"))
}

All you need to do is to add http.HandleFunc("/", lister) to your main() and navigate to http://111.222.333.444:8080/ . You will be able to navigate the backup directory to download the dump files.