Setting up a Go web application with Docker and HTTPS support using Let’s Encrypt was an eye-opening experience that taught me a lot about real-world application deployment. Though frustrating at times, I eventually succeeded by troubleshooting several issues and automating the process with helpful scripts. In this article, I’ll walk you through my journey and share everything I learned about setting up Go, Docker, and HTTPS together.
The Problem
The initial goal was simple: deploy a Go application using Docker and serve it securely over HTTPS. However, I ran into multiple issues, from setting up SSL certificates with Let's Encrypt to configuring Docker correctly to work with Go’s built-in HTTPS server.
At first, my application couldn't find the SSL certificates, resulting in an insecure setup. After debugging this issue, I realized that Docker wasn't properly mounting the certificate files inside the container. My solution was to mount the fullchain.pem
and privkey.pem
files directly, which finally got the setup working.
Here’s how I eventually solved the problem.
Getting Started: Basic Go HTTPS Server
First, let’s start with a basic Go server that serves a static HTML file over HTTPS. This Go code serves an HTML page using the certificates obtained via Let’s Encrypt:
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>Welcome to Let's Make</h1>")
})
err := http.ListenAndServeTLS(":443", "/etc/letsencrypt/live/letsmake.dev-0001/fullchain.pem", "/etc/letsencrypt/live/letsmake.dev-0001/privkey.pem", nil)
if err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}
Getting Certificates from Let's Encrypt
To secure the Go application with HTTPS, I used Certbot to generate SSL certificates from Let’s Encrypt. Follow these steps to set it up:
- Install Certbot:
Copied!
sudo apt-get update sudo apt-get install certbot sudo apt-get install python3-certbot-nginx
- Generate Certificates:
Copied!
sudo certbot certonly --standalone -d letsmake.dev --email your-email@example.com --agree-tos --non-interactive
- Renewal Setup: Certificates from Let's Encrypt expire every 90 days, so set up automatic renewal:
Copied!Add the following line:
sudo crontab -e
Copied!0 0 * * * /usr/bin/certbot renew --quiet
Setting Up Docker
With the SSL certificates in place, I moved on to setting up Docker to containerize the Go application. Docker simplifies deployment and ensures the environment is consistent across machines.
- Create a Dockerfile:
Copied!
FROM golang:1.20-alpine WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN go build -o server . EXPOSE 443 CMD ["./server"]
- Building the Docker Image:
Copied!
sudo docker build -t letsmake .
- Running the Docker Container:
Copied!
sudo docker run -d -p 443:443 \ -v /etc/letsencrypt/live/letsmake.dev-0001/fullchain.pem:/etc/letsencrypt/live/letsmake.dev-0001/fullchain.pem:ro \ -v /etc/letsencrypt/live/letsmake.dev-0001/privkey.pem:/etc/letsencrypt/live/letsmake.dev-0001/privkey.pem:ro \ --name letsmake letsmake
Automating with Bash Scripts
After manually building and running the Docker container several times, I decided to automate the process with a set of Bash scripts.
build-server.sh
#!/usr/bin/bash
sudo docker build -t letsmake .
clean-server.sh
#!/usr/bin/bash
# Stop the container
sudo docker stop letsmake
# Remove the container
sudo docker rm letsmake
run-server.sh
#!/usr/bin/bash
sudo docker run -d -p 443:443 \
-v /etc/letsencrypt/live/letsmake.dev-0001/fullchain.pem:/etc/letsencrypt/live/letsmake.dev-0001/fullchain.pem:ro \
-v /etc/letsencrypt/live/letsmake.dev-0001/privkey.pem:/etc/letsencrypt/live/letsmake.dev-0001/privkey.pem:ro \
--name letsmake letsmake
publish.sh
#!/usr/bin/bash
sudo ./clean-server.sh
sudo ./build-server.sh
sudo ./run-server.sh
Conclusion
Deploying a Go application with Docker and securing it with HTTPS was an educational experience, full of minor setbacks and challenges. The key takeaway was learning how Docker’s volume mounting works and ensuring SSL certificates were correctly mapped inside the container. Automating the deployment with Bash scripts saved me a lot of time and effort, especially when debugging and redeploying new versions.
If you’re facing similar challenges, I hope this article helps you set up your own Go, Docker, and HTTPS workflow without as much hassle.