Mastering the Setup: My Journey with Go, Docker, and HTTPS

September 15, 2024 | Tyler Laudenslager, B.S Computer Science

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:

Copied!
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:

  1. Install Certbot:
    Copied!
    sudo apt-get update
    sudo apt-get install certbot
    sudo apt-get install python3-certbot-nginx
    
  2. Generate Certificates:
    Copied!
    sudo certbot certonly --standalone -d letsmake.dev --email your-email@example.com --agree-tos --non-interactive
    
  3. Renewal Setup: Certificates from Let's Encrypt expire every 90 days, so set up automatic renewal:
    Copied!
    sudo crontab -e
    
    Add the following line:
    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.

  1. 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"]
    
  2. Building the Docker Image:
    Copied!
    sudo docker build -t letsmake .
    
  3. 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

Copied!
#!/usr/bin/bash
sudo docker build -t letsmake .

clean-server.sh

Copied!
#!/usr/bin/bash
# Stop the container
sudo docker stop letsmake
# Remove the container
sudo docker rm letsmake

run-server.sh

Copied!
#!/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

Copied!
#!/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.

← Back to Articles