Skip to content
Advertisement

How do I run a simple Go server as a daemon in Debian?

I recently wrote a simple server in Go:

package main
import (
    "net/http"
    "fmt"
    "os/exec"
)

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

func handler(output http.ResponseWriter, input *http.Request) {

    instruction := "Instructed to " + input.URL.Path[1:] + "."

    fmt.Printf(instruction)

    if input.URL.Path[1:] == "********" {

            *************
            *************
            *************                

            if err != nil {
                    fmt.Println("There was a problem executing the script.")
                    }
            } else {

            fmt.Println(" I'm unfamiliar with this instruction.")
            }

    }

It works perfectly well if compiled and then executed by ./go_http_server &.

The problem is that it doesn’t survive reboots. So after some reading, I attempted to daemonize it by placing a script in /etc/init.d:

#!/bin/sh

### BEGIN INIT INFO
# Provides:          myservice
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Put a short description of the service here
# Description:       Put a long description of the service here
### END INIT INFO

# Change the next 3 lines to suit where you install your script and what you want to call it
DIR=/****/****
DAEMON=$DIR/go_http_server
DAEMON_NAME=*********

# Add any command line options for your daemon here
DAEMON_OPTS=""

# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=*****

# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid

. /lib/lsb/init-functions

do_start () {
    log_daemon_msg "Starting system $DAEMON_NAME daemon"
    start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS
    log_end_msg $?
}
do_stop () {
    log_daemon_msg "Stopping system $DAEMON_NAME daemon"
    start-stop-daemon --stop --pidfile $PIDFILE --retry 10
    log_end_msg $?
}

case "$1" in

    start|stop)
        do_${1}
        ;;

    restart|reload|force-reload)
        do_stop
        do_start
        ;;

    status)
        status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?

…then running update-rc.d go_http_server defaults, and poof! It runs on boot, as verified by ps -ef | grep go_http_server.

But it doesn’t receive GET requests while running as a service. Thinking it might be running before the network interface was up, I tried service go_http_server stop, followed by service go_http_server start; still refused to receive GET requests. Stopping the service again and then executing ./go_http_server & makes the server function correctly once more.

I’ve been Googling this on and off for a couple days now. Either my search queries suck, or this isn’t an obvious problem. How do I daemonize my Go server?


EDIT: The exact same thing happens with a server I wrote in Python: it works as it should when executed using ./python_server.py, but–if started as service–HTTP requests are ignored. Both files have been made executable, and it doesn’t matter if the daemon user is root or any other user. Not sure if this helps, but I thought it might be relevant.

Advertisement

Answer

Supervisor is a good fit here, and can automatically capture and rotate logs written to stdout, restart on crash and manage ports/permissions.

Here’s what an example configuration would look like for a Go web service:

# where 'mygoapp' is the name of your application
$ sudo vim /etc/supervisor/conf.d/mygoapp.conf 

[program:yourapp]
command=/home/yourappuser/bin/yourapp # the location of your app
autostart=true
autorestart=true
startretries=10
user=yourappuser # the user your app should run as (i.e. *not* root!)
directory=/srv/www/yourapp.com/ # where your application runs from
environment=APP_SETTINGS="/srv/www/yourapp.com/prod.toml" # environmental variables
redirect_stderr=true
stdout_logfile=/var/log/supervisor/yourapp.log # the name of the log file.
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=10

I wrote an article[1] that takes you through the steps, but the Supervisor documentation is extremely comprehensive.

Similarly, Debian systems also use systemd[2], which can achieve this as well.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement