I recently had to figure this out and could not find a good resource, I hope this is the first one then.
How to set up HTTPS for a Go (Gin) REST API using Docker and Letsencrypt
What is used (what you need to install):
Source code for the demo Go REST API:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func setupRouter() *gin.Engine {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, "pong")
})
return r
}
func main() {
r := setupRouter()
r.Run(":80")
}
How to encrypt it using letsencrypt
- Add
"github.com/gin-gonic/autotls"
to your imports. - Open a goroutine for the run on port 80 to prevent blocking the thread while still enabling access via http: Change:
r.Run(":80")
To:
go r.Run(":80")
- Add the option to access the service via ssl:
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("domain.com"),
Cache: autocert.DirCache("/var/www/.cache"),
}
autotls.RunWithManager(r, &m)
You have to enter your domain instead of "domain.com"
Dockerize it
Dockerfile:
FROM golang:latest
WORKDIR /
COPY . .
EXPOSE 80
EXPOSE 443
ENV GIN_MODE=release
VOLUME ["/var/www/.cache"]
CMD [ "go","run", "main.go" ]
You should also add a volume to docker-compose because you will be rate limited by letsencrypt if you request to many certificates
go-backend:
build:
context: ./go-backend
dockerfile: Dockerfile
ports:
- 80:80
- 443:443
container_name: go-backend
volumes:
- certcache:/var/www/.cache
Here the gin project is located in ./go-backend
which might be different for your project. The important part is that the volume is created at /var/www/.cache
to prevent to many requests to letsencrypt.
Final notes:
If you want to encrypt your api and make it accessible using https, it might be a good idea to prevent using http. This would be especially important if you send passwords or other sensitive data to or from the server via your api. In this case you should remove this from your go code:
go r.Run(":80")
You also should close (not open) port 80 in your Dockerfile and in docker-compose because they are not needed.
Full go code:
package main
import (
"github.com/gin-gonic/autotls"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/acme/autocert"
"net/http"
)
func setupRouter() *gin.Engine {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, "pong")
})
return r
}
func main() {
r := setupRouter()
go r.Run(":80")
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("domain.com"),
Cache: autocert.DirCache("/var/www/.cache"),
}
autotls.RunWithManager(r, &m)
}
Top comments (0)