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.