Serving HTTP requests using a Go binary file and Supervisor in Ubuntu
Go builds everything into a single binary file, making deployment easier. However, it’s not feasible to keep the terminal open to run the Go file forever. Supervisor comes to the rescue by managing the process for us!
Prepare in the local machine
Firstly, we create a basic Go hello file that serves HTTP requests. We will run it on port 8000 or any other port given by the environment variable.
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8000"
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(fmt.Sprintf("Hello from port %s", port)))
})
fmt.Printf("Listening on :%s\n", port)
http.ListenAndServe(fmt.Sprintf(":%s", port), nil)
}
Build the binary file, please make sure to add the two environment variables to build for Linux. Otherwise, it will build the wrong binary. By default Go will build the binary file for the current operating system (in my case is MacOS).
GOOS=linux GOARCH=amd64 go build -o hello_bin hello.go
Copy the built binary file hello_bin
to the server’s /home/ubuntu/hello
folder. I recommend using rsync
instead of scp
because it offers better performance and can handle file and folder copying, updating old files, and creating new folders if they don’t exist, all in a single command 🚀.
rsync -avz ./hello_bin ubuntu@159.223.47.97:/home/ubuntu/hello
Go to remote Ubuntu server
Go to our Ubuntu remote server:
ssh ubuntu@159.223.47.97 #change to your user and server IP
Please install Supervisor if it is not already installed.
sudo apt update && sudo apt install supervisor
Let’s create a Supervisor configuration file called hello1.conf
.
You can use either vim
or nano
to create or edit the file.
sudo vim /etc/supervisor/conf.d/hello1.conf
Please be noted to use the full path for the command
key, rather than a relative path from the current directory.
[program:hello1]
command=/home/ubuntu/hello/hello_bin
directory=/home/ubuntu/hello
user=ubuntu
autostart=true
autorestart=true
stderr_logfile=/var/log/hello1.err.log
stdout_logfile=/var/log/hello1.out.log
Similarly, let’s create a program configuration file called hello2.conf
. This file should include the environment variable PORT=8001
so that later we can run our two programs simultaneously on different ports.
sudo vim /etc/supervisor/conf.d/hello2.conf
[program:hello2]
command=/home/ubuntu/hello/hello_bin
directory=/home/ubuntu/hello
user=ubuntu
autostart=true
autorestart=true
stderr_logfile=/var/log/hello2.err.log
stdout_logfile=/var/log/hello2.out.log
environment=PORT=8001
Now, let’s update the Supervisor with the new configuration. Let’s use the supervisorctl reread
command for two purposes:
- to help Supervisor review new information (without changing the configuration)
- and to check if our newly added configurations are valid before performing the actual update.
sudo supervisorctl reread
# hello1: available
# hello2: available
Next, we perform the actual update in configuration state of Supervisor. After update the programs are ready to run.
sudo supervisorctl update
Now, we can run our programs using either the start
or restart
command. It is okay to simply use restart
as if the program already run we will get a small error but it still work properly.
sudo supervisorctl restart hello1
# hello1: ERROR (not running) # you see it when the program has never run and it is FINE
# hello1: started
Do the same for hello2:
sudo supervisorctl restart hello2
# hello2: stopped # you see it when the program is currently running
# hello2: started
Moment of Truth
Go back to our Local machine to test our two programs hello1 and hello2:
curl http://159.223.47.97:8000/
# Hello from port 8000
curl http://159.223.47.97:8001/
# Hello from port 8001
Great! We can see that hello2
is receiving the PORT
environment variable and running properly.
We’ve done now!
Bonus
To group hello1
and hello2
together for easier management, you can modify the /etc/supervisor/conf.d/hello2.conf
file by adding two additional lines at the end.
[program:hello2]
command=/home/ubuntu/hello/hello_bin
directory=/home/ubuntu/hello
user=ubuntu
autostart=true
autorestart=true
stderr_logfile=/var/log/hello2.err.log
stdout_logfile=/var/log/hello2.out.log
environment=PORT=8001
[group:hello]
programs=hello1,hello2
Now, we can run the group hello:
(note the colon :
) to manage both hello1
and hello2
together.
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart hello:
Please note that you can no longer directly interact with the individual processes hello1
and hello2
. Instead, you will need to use the hello
group to manage them. Running individual program is error now:
sudo supervisorctl restart hello1
# hello1: ERROR (no such process)
We must do this instead:
sudo supervisorctl restart hello:
# hello:hello1: stopped
# hello:hello2: stopped
# hello:hello1: started
# hello:hello2: started
Source code: https://gist.github.com/anvodev/19c1402b93258bb4272ecf4dd64ba6bc
Thanks for reading! Good luck with the server-related tasks!