Running multiple apps on a single machine has never been easier! In this tutorial, I’ll show you how to run 3 apps on one server using Docker and Traefik.
Use case
Say you’re low on cash and can only rent one server, you can run your website, blog and SaaS app on the same machine (what we’ll do in this tutorial). Or you can run an API (back-end) and SPA (front-end). You can even run two different websites (example1.com and example2.com) if you want.
Docker
Docker is the most widely used containerization software today. It allows you bundle code with it’s config and dependencies, making it easy and seamless to deploy your apps on any machine (or several machines). It also helps in development by providing a consistent environment for collaborators on a project. More info here: https://docs.docker.com.
Traefik
Traefik is a HTTP reverse proxy and load balancer that integrates with Docker, Swarm, Kubernetes among other orchestration tools. You can learn more here: https://docs.traefik.io.
Docker Compose
We’ll be using Docker via Docker Compose. Docker Compose makes it easy to run multi-container Docker applications. You can configure all your containers in one file and run them at once with a single command. Read more here: https://docs.docker.com/compose.
Project setup
The 3 apps we’ll be running are a website (static site), a blog and a SaaS app (dasboard-ish). For the sake of demonstration, I just downloaded HTML templates online 👀. So I have a landing page template, blog template and dashboard template. They’ll all be served with Ngnix 😉.
website
blog
SaaS app
Here’s the project repo: https://github.com/nicholaskajoh/jack.
Each app is put in it’s own folder, with its own Dockerfile. The Dockerfiles are identical since we’re basically just serving static files in all the apps.
# Dockerfile
FROM nginx:alpine
COPY . /usr/share/nginx/html
The docker compose file brings everything together under one roof. Here’s how it looks:
# docker-compose.yml
version: "3"
services:
traefik:
image: traefik
command: --web --docker --docker.domain=docker.localhost --logLevel=DEBUG
ports:
- "80:80"
- "8080:8080"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /dev/null:/traefik.toml
app:
build: ./app
volumes:
- ./app:/usr/share/nginx/html
labels:
- "traefik.backend=app-be"
- "traefik.frontend.rule=Host:app.localhost"
blog:
build: ./blog
volumes:
- ./blog:/usr/share/nginx/html
labels:
- "traefik.backend=blog-be"
- "traefik.frontend.rule=Host:blog.localhost"
website:
build: ./website
volumes:
- ./website:/usr/share/nginx/html
labels:
- "traefik.backend=website-be"
- "traefik.frontend.rule=Host:localhost"
As can be seen, traefik itself is run in a container. The domain is set to localhost and the ports 80, 8080 and 443 are published. The web flag (--web
) under command parameter tells traefik to run its API dashboard which will be exposed on port 8080.
Traefik can be configured using a traefik.toml file. It can also pick configs from service labels. As such, we specified the traefik.backend
and traefik.frontend.rule
configs using labels. traefik.backend
specifies the service to handle requests from traefik.frontend.rule
. So if we go to app.localhost, we will be served content from the app service. Same with localhost and website, and blog.localhost and blog.
Try it out: clone Jack, run docker-compose up
and visit localhost, app.localhost and blog.localhost.
Traefik dashboard
The Traefik dashboard displays useful information including the available front-ends and back-ends, and the health of the containers. You can password protect the dashboard so only authorized persons can access it.
SSL
Traefik can handle SSL for you automatically. This guide (https://docs.traefik.io/https/acme/) explains the configuration process using Let’s Encrypt.
NB: I added SSL configs in docker-compose.prod.yml and traefik.toml for use in production.
Scaling and load balancing
Traefik load balances multiple instances of a given service automatically. You can use the scale flag/parameter in docker compose to run multiple instances of your containers.
Last modified on 2023-03-14