Docker - Traefik - IPWhitelist

Whitelist IP Range

docker-compose.yml

  whoami:
    image: containous/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32, x.x.x.x/y"
      - "traefik.http.routers.whoami.middlewares=test-ipwhitelist@docker"
      - "traefik.http.routers.whoami.rule=Host(`whoami.your.domain.de`)"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
      - "traefik.http.routers.whoami.tls=true"

-> only “localhost” and SRC IP x.x.x.x/y can access this URL. Rest will be blocked. -> Disadvantage. Container needs to be restartet if the Source Range gets modified!

we can do this better :)

Move to File

you may want to put your “IP Ranges” to a dedicated File and import it where needed.

Docker - Traefik - Stripprefix

Strip Prefix

Let’s assume you have a URL “https://whoami.your.domain.de/removeme" and you wanna get rid of the “removeme” before passing the Request to the Webserver. Stripprefix is your friend …

docker-compose.yml

  whoami:
    image: containous/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.test-stripprefix.stripprefix.prefixes=/wegdamit,/removeme"
      - "traefik.http.routers.whoami.middlewares=test-stripprefix@docker"
      - "traefik.http.routers.whoami.rule=Host(`whoami.your.domain.de`)"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
      - "traefik.http.routers.whoami.tls=true"

Any Comments ?

sha256: 0620c0c2d7ae033f2536f6797a048772e52a09119367f4864f8bb2a754d2ea57

Docker - Traefik - Ratelimiting

docker-compose.yml

let’s limit the Requests to 10 Req / 10 Seconds.

  whoami:
    image: containous/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.test-ratelimit.ratelimit.average=10"
      - "traefik.http.middlewares.test-ratelimit.ratelimit.burst=0"
      - "traefik.http.middlewares.test-ratelimit.ratelimit.period=10s"
      - "traefik.http.routers.whoami.middlewares=test-ratelimit@docker"
      - "traefik.http.routers.whoami.rule=Host(`whoami.your.domain.de`)"
      - "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
      - "traefik.http.routers.whoami.tls=true"

restart container

docker compose -f docker-compose.yml up -d

Test Limiting with Curl

user@docker:~$ while true; do echo $(date); curl -s https://whoami.your.domain.de |grep "Too" ; sleep 0.1; done
Wed Oct 12 18:43:57 CEST 2022
Too Many Requests
Wed Oct 12 18:43:58 CEST 2022
Too Many Requests
Wed Oct 12 18:43:58 CEST 2022
Too Many Requests

Test Limit with hey, 10 Concurrent

100 Requests, 10 Concurrent, Wait 1 Second between Poll

Docker - Dozzle - Realtime Logs

Dozzle is a real-time log viewer for docker containers

URL

Pull Image and start Container

docker pull amir20/dozzle:latest
docker run --name dozzle -d --volume=/var/run/docker.sock:/var/run/docker.sock -p 8888:8080 amir20/dozzle:latest

Docker Compose

version: "3"
services:
  dozzle:
    container_name: dozzle
    image: amir20/dozzle:latest
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - 8888:8080

You’re now exposing all your logfiles to the Internet on Port 8888. Apply some FW Rules on the Host, on the Cloud Provider or wherever it fit’s for you ….

Docker on Debian

Let’s Setup Docker on Debian

Get Debian on some Cloud Provider

Update Apt

apt-get install ca-certificates curl gnupg lsb-release

add official GPG Keys

mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg |gpg --dearmor -o /etc/apt/keyrings/docker.gpg

add Repo to Sources

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" |tee /etc/apt/sources.list.d/docker.list > /dev/null

install Docker Engine

apt-get update
apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Check Version

docker version
root@docker:~# docker version
Client: Docker Engine - Community
 Version:           20.10.18
 API version:       1.41
 Go version:        go1.18.6
 Git commit:        b40c2f6
 Built:             Thu Sep  8 23:12:08 2022
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Docker Compose Version

docker compose version
root@docker:~# docker compose version
Docker Compose version v2.10.2

Install Hello World

docker run hello-world

Prepare Folders

mkdir -p /etc/docker/container/traefik
cd /etc/docker/container/traefik

Build Docker-compose

cat << 'EOF' > docker-compose.yml
services:
  traefik:
    image: traefik:v2.6
    restart: always
    command:
      - "--providers.docker"
      - "--providers.docker.exposedByDefault=false"
      - "--providers.docker.network=traefik_web"
      - "--entrypoints.http.address=:80"
      - "--entrypoints.http.http.redirections.entrypoint.to=https"
      - "--entrypoints.http.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.https.address=:443"
      - "--entrypoints.https.http.tls.certResolver=le"
      - "--certificatesresolvers.le.acme.tlschallenge=true"
      - "--certificatesresolvers.le.acme.email=docker@stoege.net"
      - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
networks:
  web:
    name: traefik_web
EOF

docker compose up

docker compose up -d

docker compose ps

docker compose ps
NAME                COMMAND                  SERVICE             STATUS              PORTS
traefik-traefik-1   "/entrypoint.sh --pr…"   traefik             running             0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp

Demo Nginx

mkdir -p /etc/docker/container/nginx-demo
cd /etc/docker/container/nginx-demo

docker-compose.yml

cat << 'EOF' > docker-compose.yml
services:
  nginx:
    image: nginx:1.20
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nginx.rule=Host(`nginx.v4.docker.noflow.ch`)"
    networks:
      - traefik_web

networks:
  traefik_web:
    external: true
EOF

Nginx up

docker compose up -d

Tail logfile

docker compose logs -f

-> https://nginx.v4.docker.noflow.ch

Hugo - Start

GoHugo from Scratch

Take a fresh VM with OpenBSD ;) otherwise, you have to adapt appropriate …

install pkg

Login as User which is part of the “wheel group”. Doas should allow all Users of the Wheel Group to get root.

doas pkg_add hugo-- nginx--

adduser webmaster

create a user “webmaster” and prepare virtual directories

doas adduser webmaster
doas mkdir /var/www/virtual
doas chown webmaster /var/www/virtual/

Update Nginx

we need to modify nginx, prepare a site folder and a basic config for the webserver. do some stuff as root

Headscale - Real World Example

Tailscale on Public Intrnet

Setup

Let’s build a few machines around the world and get our hands dirty with headscale / tailscale.

headscale

  • amsterdam

tailscale

  • stockholm
  • miami
  • singapore
  • sydney

goal is to build a fullmesh network with all 4 tailscale clients

Headscale Server

Generate Install Key

let’s generate a reusable install key for all 4 clients. It’s valid for 1 hour.

Headscale - OpenBSD

Running Headscale Server on OpenBSD

i like and widely use wireguard for my infrastructure. i’m also aware of it’s limitation and i know the tailscale project but never gave try. recently, i stumbled upon the headscale project, an opensource alternative to for the (closed) tailscale server. perfect, let’s give a try!

and, of course, i’m gooing to implement this with OpenBSD, what else ;)

Doku

on the Server

compile and install server

this is working on OpenBSD 7.1, and also on the upcomming Version 7.2

OpenBSD & OTP

i don’t like ssh & password authentication. but sometime, specially during setup or recovery, it’s need and make sense. thought i’ll protect some boxes with otp. here a few notes and instrucations

Build login_otp

git clone https://github.com/reyk/login_otp
cd login_otp
make obj
make all
doas make install

Initialize OTP DB

doas otp -i

Generate Key for User

otp -g
Name: stoege
Key:  xxxx xxxx xxxx xxxx xxxx xxxx xx
URL:  otpauth://totp/stoege?secret=xxxxxxxxxxxxxxxxxxxxxxxxxx&issuer=&algorithm=SHA1&digits=6&period=30

Build QR Code

echo "otpauth://totp/stoege?secret=xxxxxxxxxxxxxxxxxxxxxxxxxx&issuer=&algorithm=SHA1&digits=6&period=30" |qrencode -t ansiutf8

and scan the code with the google authenticator (or similar app)

Url Shortener for CLI

CLI Url Shortener

wrote a little URL Shortener in Python with FastAPI and a wrapper script for cli usage. needs httpie & jq packages. python backend is under development, cli wrapper for different os right here …

Usage

somehost$ ./myurlshort

usage: /usr/local/bin/myurlshort http://veeeeeeeeeeeeeeeeeeeeeeeeeery.long.url.to

anyhost$ ./myurlshort http://my-url-to-short.egal.world.planet.universe
https://url.stoege.net/xXxXx

CLI Wrappers

OpenBSD

cat << 'EOF' > myurlshort
#!/usr/bin/env bash

# url shortener for openbsd, v1.0, 2022-09-12, by @stoege

which jq >/dev/null || ( echo -e "*** jq not installed ***\ndoas pkg_add jq\n"; )
which https >/dev/null || ( echo -e "*** httpie not installed ***\ndoas pkg_add httpie\n"; )

if [[ $# -ne 1 ]]; then
  echo -e "\nusage: $0 http://veeeeeeeeeeeeeeeeeeeeeeeeeery.long.url.to\n"
  exit 1
fi

url="$1"

# check if http/https set
if ! ( [[ $1 == http* ]] || [[ $1 == https* ]] ); then
  url="https://$1"
  echo "adding https:// ... -> $url"
fi

https post url.stoege.net/url target_url="$url" |jq -r '.url'

exit 0
EOF

chmod 755 myurlshort

macOS

cat << 'EOF' > myurlshort
#!/usr/bin/env bash

# url shortener for macos, v1.0, 2022-09-12, by @stoege

which jq >/dev/null || ( echo -e "*** jq not installed ***\nbrew install jq\n"; )
which https >/dev/null || ( echo -e "*** httpie not installed ***\nbrew install httpie\n"; )

if [[ $# -ne 1 ]]; then
  echo -e "\nusage: $0 http://veeeeeeeeeeeeeeeeeeeeeeeeeery.long.url.to\n"
  exit 1
fi

url="$1"

# check if http/https set
if ! ( [[ $1 == http* ]] || [[ $1 == https* ]] ); then
  url="https://$1"
  echo "adding https:// ... -> $url"
fi

https post url.stoege.net/url target_url="$url" |jq -r '.url'

exit 0
EOF

chmod 755 myurlshort

Alpine

cat << 'EOF' > myurlshort
#!/usr/bin/env bash

# url shortener for alpine, v1.0, 2022-09-12, by @stoege

which jq >/dev/null || ( echo -e "*** jq not installed ***\napk add jq\n"; )
which https >/dev/null || ( echo -e "*** httpie not installed ***\napk add httpie\n"; )

if [[ $# -ne 1 ]]; then
  echo -e "\nusage: $0 http://veeeeeeeeeeeeeeeeeeeeeeeeeery.long.url.to\n"
  exit 1
fi

url="$1"

# check if http/https set
if ! ( [[ $1 == http* ]] || [[ $1 == https* ]] ); then
  url="https://$1"
  echo "adding https:// ... -> $url"
fi

https post url.stoege.net/url target_url="$url" |jq -r '.url'

exit 0
EOF

chmod 755 myurlshort

Any Comments ?

sha256: 75b0a781fd4569791f3d43932694e155a9443a739f0bf43b0e0904ce299eec3e