#!/bin/bash
# Filename: traefik-docker.sh
# Install traefik.io on a newly installed Ubuntu server
# Run this script only once!
#
# To run to run use one of the below commands:
# wget -O - -q https://go.poorna.net/go/traefik-docker.sh | bash
# curl -s      https://go.poorna.net/go/traefik-docker.sh | bash

# Check that we are running this as root
if [ "$(id -u)" -ne 0 ]; then
  echo 'ERROR: This script must be run as root.'
  exit 1
fi

# Ensure that we are running on an ubuntu host
. /etc/os-release
if [ "$ID" != "ubuntu" ]; then
  echo 'ERROR: This script is intended to run only on an Ubuntu host.'
  exit 1
fi

# Ensure docker-compose is available
if ! command -v docker-compose &> /dev/null; then
  echo 'ERROR: docker-compose is not installed. Please install it first.'
  exit 1
fi

set -eoux pipefail

# Creating docker-socket-proxy docker container
echo 'Creating docker-socket-proxy docker container'
mkdir -p /opt/docker-socket-proxy
cat > /opt/docker-socket-proxy/docker-compose.yml <<EOT
# docker-compose file to start up tecnativa/docker-socket-proxy
# to start the container run:
#    docker-compose up -d
#
# Note2: docker container name is sourced from the .env file in this directory.
#
# Note3: containrrr/watchtower service will auto update this container

name: docker-socket-proxy

services:
  docker-socket-proxy:
    image: tecnativa/docker-socket-proxy
    container_name: docker-socket-proxy
    restart: always

    ports:
      - 127.0.0.1:2375:2375

    mem_limit: 64M

    environment:
      CONTAINERS: 1

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

    labels:
      - com.centurylinklabs.watchtower.enable=true
EOT

echo 'Starting docker-socket-proxy docker container'
docker-compose -f /opt/docker-socket-proxy/docker-compose.yml up -d


# Creating traefik docker container
echo 'Creating traefik docker container'
mkdir -p /opt/traefik/{acme,conf.d}
cat > /opt/traefik/docker-compose.yml <<EOT
name: traefik

services:
  traefik:
    image: traefik:v3
    container_name: traefik
    restart: always

    mem_limit: 512M

    volumes:
      - ./:/opt/traefik
      - ./:/etc/traefik

    network_mode: host

    labels:
      - com.centurylinklabs.watchtower.enable=true
EOT


cat > /opt/traefik/traefik.yaml <<EOT
# Traefik v3.x main configuration file
# Filename: /opt/traefik/traefik.yaml

# Listen on http, https ports. Forward all http to https using middleware.
entryPoints:
  https:
    address: ':443'

  http:
    address: ':80'
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https

  name:
    http3: {}

# Use lets-encrypt CA to auto create SSL certificates on demand
certificatesResolvers:
  lets-encrypt:
    acme:
      email: noreply@example.com
      storage: /opt/traefik/acme/acme.json

# Use HTTP Challege for the publicly accessable domains
      httpChallenge:
        entryPoint: http

# As internal DNS domains are being used, use DNS Challenge to verify LE certs
# See environment vars: CLOUDFLARE_DNS_API_TOKEN, CLOUDFLARE_ZONE_API_TOKEN
#     dnsChallenge:
#       provider: cloudflare
#       delayBeforeCheck: 0

# Web access log location. See /etc/logrotate.d/traefik.
accessLog:
  filePath: /dev/stdout

# Serve applications configured file and docker
# Docker provider uses labels in docker-compose for auto discovery
providers:
  file:
    directory: /opt/traefik/conf.d
    watch: true

  docker:
    exposedByDefault: false
    endpoint: "tcp://localhost:2375"
    watch: true
EOT


cat > /opt/traefik/conf.d/00-common.yaml <<EOT
# Common dynamic config options for traefik
# Filename: /opt/traefik/conf.d/00-common.yaml

# Set minimum TLS 1.2 with secure ciphers
tls:
  options:
    default:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
        - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
EOT

cat > /opt/traefik/conf.d/10-ip-private-networks.yaml <<EOT
# Traefik v3.x dynamic config fragment to secure access only from local networks
# Filename: /opt/traefik/conf.d/10-ip-private-networks.yaml
#
# Add this line to Docker labels to use the middleware:
# traefik.http.routers.example.middlewares:privatenetworks@file
#
# If there are multiple rules, longer rule has the high priority
# Use this label to adjust priority if needed:
# traefik.http.routers.example.priority: 100

http:
  middlewares:
    privatenetworks:
      ipAllowList:
        sourceRange:
          - '127.0.0.0/8'
          - '10.0.0.0/8'
          - '172.16.0.0/12'
          - '192.168.0.0/16'
          - '100.64.0.0/10' # Tailscale Subnet
EOT

echo 'Starting traefik docker container'
docker-compose -f /opt/traefik/docker-compose.yml up -d

echo 'SUCCESS: traefik and other packages installed successfully'
