Seddik Omar

Seddik Omar

Chief Technical Officer / DevOps

Use Traefik as a reverse proxy

Sometimes you need to use a reverse proxy to protect expose your app directly on web, to do it several tools comes up (Nginx,Apache,AWS ELB …).

In this article we will be interested to Traefik

First step :

Traefik need a config file traefik.toml :

defaultEntryPoints = ["http"]

[entryPoints]
  [entryPoints.http]
  address = ":80"
#config of host traefik with http auth basic 
[web]
address = ":8080"
[web.auth.basic]
  users = ["admin:$apr1$o1HmXW0i$wWgVewL1kLu9gaqmMDh6d/"]

[docker]
endpoint = "unix:///var/run/docker.sock"
#choose local domain you want
domain = "dev.local" 
watch = true
exposedbydefault = true

What we’re going to do is configure a docker network – let’s call it traefik – that every service will be placed into that’s actually connected to the internet. Since this network will be service agnostic we’ll create it as an external network directly with the docker cli.

docker network create traefik

Now lets create a new docker-compose file for traefik that looks like.

version: '3.2'

services:
  proxy:
    image: traefik
    networks:
      - traefik
    ports:
      - "80:80"
      - "8080:8080"
      - "443:443"
    volumes:
      - "$PWD/traefik.toml:/etc/traefik/traefik.toml"
      - /var/run/docker.sock:/var/run/docker.sock
    restart: unless-stopped
    labels:
      - "traefik.frontend.rule=Host:traefik.dev.local"
      - "traefik.port=8080"
      - "traefik.backend=traefik"
      - "traefik.frontend.entryPoints=http"

This create a new container based on the official traefik image, which is restarted automatically if it stops, exposes ports 80 (HTTP), 443 (HTTPS) and 8080 (dashboard) directly, has a few mounted volumes and is part of the web network. For the network to be picked up by docker-compose we need to explicitly list it in a networks section below.

Running Other Services

we’re going to configure Ruby on Rails and Postgres.

Postgres

db:
   image: postgres
   volumes:
     - ./postgres/data:/var/lib/postgresql/data
   networks:
     - traefik

RubyOnRails:

Create a ruby_app in the root directory and clone the rails app inside, before docker-compose you should create a dockerfile and entrypoint.sh file for your app like this one.

Entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /app/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "[email protected]"
Dockerfile:
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
Docker-compose ROR:
web:
    build: ./ruby_app
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - ./ruby_app:/app
    ports:
      - "3000:3000"
    networks:
      - traefik
    depends_on:
      - db
    labels:
      - "traefik.frontend.rule=Host:rails.dev.local"
      - "traefik.port=3000"
      - "traefik.backend=rails"
      - "traefik.frontend.entryPoints=http"

Global docker-compose:

version: '3.2'

services:
  db:
    image: postgres
    volumes:
      - ./postgres/data:/var/lib/postgresql/data
    networks:
      - traefik
  web:
    build: ./ruby_app
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - ./ruby_app:/app
    ports:
      - "3000:3000"
    networks:
      - traefik
    depends_on:
      - db
    labels:
      - "traefik.frontend.rule=Host:rails.dev.local"
      - "traefik.port=3000"
      - "traefik.backend=rails"
      - "traefik.frontend.entryPoints=http"
  proxy:
    image: traefik
    networks:
      - traefik
    ports:
      - "80:80"
      - "8080:8080"
      - "443:443"
    volumes:
      - "$PWD/traefik.toml:/etc/traefik/traefik.toml"
      - /var/run/docker.sock:/var/run/docker.sock
    restart: unless-stopped
    labels:
      - "traefik.frontend.rule=Host:traefik.dev.local"
      - "traefik.port=8080"
      - "traefik.backend=traefik"
      - "traefik.frontend.entryPoints=http"
  networks:
  traefik:
    external:
      name: traefik

NB: You should add hosts : (Linux : /etc/hosts)

  • 127.0.0.1 traefik.dev.local
  • 127.0.0.1 rails.dev.local

It’s time to run your docker-compose:

docker-compose up -d

If all container run correctly test host on your browser:

Traefik dashboard
RubyOnRails application