The way I deploy my apps is usually:
- deploy the frontend app to managed services like Netlify or Zeit, depending on if I'm using Next.js
- deploy the backend service to a VPS provider such as DigitalOcean(get $100 free credit via my link) or Vultr ( provider with the best performance)
Most frontend deployment services like Netlify and Zeit have built in https support so enabling https for the frontend has never been an issue for me. However, because the frontend uses https, it forces the backend to be as secure, meaning you cannot make http request to fetch data.
I have tried to use nginx and letsencrypt to set up https support for my API service in the past, but I felt it was overly complicated for just a small application. Luckily I found a very simple and easy alternative to nginx, traefik.
traefik allows you to set up a reverse proxy with nothing but a docker-compose file! And it also makes enabling https support very easy. How amazing is that? So let me walk you through how to deploy you backend API with traefik in 5 minutes.
Before we start, you need:
- a domain name
- docker installed
- a docker image of your backend API (See my previous post)
I'll just provide very simple steps on how to set up your service. If you'd like to learn more about the configuration, here's the official document: https://docs.traefik.io/providers/docker/
- Create a docker-compose.yml file and copy paste the content below
jameskutw/apiwith your own docker image
- replace example.com with your own domain
- make sure the port mapping for your API container is correct
Basically traefik gets information from the labels of a container. As you can see in the file. For example
"traefik.http.routers.api.rule=Host(`example.com`)" tells traefik that traffic from example.com should be directed to the
version: "3.3" services: traefik: image: "traefik:v2.2" container_name: "traefik" command: #- "--log.level=DEBUG" - "--api.insecure=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.myresolver.acme.httpchallenge=true" - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web" # - "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory" - "--email@example.com" - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" - "8080:8080" volumes: - "./letsencrypt:/letsencrypt" - "/var/run/docker.sock:/var/run/docker.sock:ro" api: image: "jameskutw/api" container_name: "api" ports: - "5001:80" labels: - "traefik.enable=true" - "traefik.http.routers.api.rule=Host(`example.com`)" - "traefik.http.routers.api.entrypoints=websecure" - "traefik.http.routers.api.tls.certresolver=myresolver"
Because Let's encrypt(free ssl certificate provider) has a cap on how many times you can request a certificate, to do a dry run just to see if it works, uncomment this line
"--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory" and run
docker-compose up -d
If everything works fine
- remove the containers
- comment back that line you uncommented
- run the containers again
docker-compose up -d