Files
literate-dotfiles/homelab.org
2023-10-13 12:30:13 +02:00

132 KiB

Home Server

Hardware

Part Model
Case Fractal Design Node 804
Motherboard ASUS PRIME B450M-A
CPU AMD Ryzen 3 3200G
RAM Corsair Vengeance LPX 16Go (2x8Go) DDR4 3200MHz
Cooler ARCTIC Freezer 34 eSports DUO
PSU Corsair SF450
SSD M.2 Samsung 970 EVO Plus 250Gb
Disk Drives Various drives ranging from 3Tb to 8Tb
Home Server Hardware

Installation

Ubuntu

  • Download Ubuntu Server 20.04 LTS (link).
  • Activate OpenSSH and add SSH Keys
  • Account: thomas, hostname: homelab

Install Important software

sudo apt install neovim tmux fd-find ripgrep fzf apache2-utils unrar ranger

Terminal Problem

On the local host, using Termite:

infocmp > termite.terminfo  # export Termite's Terminfo
scp termite.terminfo user@remote-host:~/  # or any other method to copy to the remote host

On the remote host, in the directory where you copied termite.terminfo:

tic -x termite.terminfo  # import Terminfo for current user
rm termite.terminfo  # optional: remove Terminfo file

Minor Modifications of ~/.inputrc

Modify ~/.inputrc, like so:

"\e[A": history-search-backward            # arrow up
"\e[B": history-search-forward             # arrow down

Partition and Format Disk Drives

A nice tutorial is available here.

lsblk
sudo parted /dev/sda mklabel gpt
sudo parted -a opt /dev/sda mkpart "partitionname" ext4 0% 100%
sudo mkfs.ext4 -L partitionname /dev/sda1

MergerFS and FStab

MergerFS is a transparent layer that sits on top of the data drives providing a single mount point for reads / writes (link).

sudo apt install mergerfs

Create mount points

sudo mkdir /mnt/disk0
sudo mkdir /mnt/disk1
sudo mkdir /mnt/parity

Create folder where disks will be merged.

sudo mkdir /srv/storage

Edit /etc/fstab.

/dev/disk/by-uuid/7fb7873c-83bd-4805-98ab-506e6c7b56fa /mnt/disk0  ext4 defaults 0 0
/dev/disk/by-uuid/6574b7ae-321c-4078-9793-bc41a4fa5588 /mnt/disk1  ext4 defaults 0 0
/dev/disk/by-uuid/6fcd38b9-0886-46bd-900d-cb1f170dbcee /mnt/parity ext4 defaults 0 0

/mnt/disk* /srv/storage fuse.mergerfs direct_io,defaults,allow_other,minfreespace=50G,fsname=mergerfs 0 0

SnapRAID (link) and SnapRAID Runner (link)

SnapRAID is a snapshot parity calculation tool which acts at the block level independent of filesystem (link).

It is manually installed with docker (link).

The configuration file is located in /etc/snapraid.conf:

# Defines the file to use as parity storage
# It must NOT be in a data disk
# Format: "parity FILE_PATH"
parity /mnt/parity/snapraid.parity

# Defines the files to use as content list
# You can use multiple specification to store more copies
# You must have least one copy for each parity file plus one. Some more don't
# hurt
# They can be in the disks used for data, parity or boot,
# but each file must be in a different disk
# Format: "content FILE_PATH"
content /var/snapraid.content
content /mnt/disk0/.snapraid.content
content /mnt/disk1/.snapraid.content

# Defines the data disks to use
# The order is relevant for parity, do not change it
# Format: "disk DISK_NAME DISK_MOUNT_POINT"
disk disk0 /mnt/disk0
disk disk1 /mnt/disk1

# Excludes hidden files and directories (uncomment to enable).
#nohidden

# Defines files and directories to exclude
# Remember that all the paths are relative at the mount points
# Format: "exclude FILE"
# Format: "exclude DIR/"
# Format: "exclude /PATH/FILE"
# Format: "exclude /PATH/DIR/"
exclude /tmp/
exclude /lost+found/
exclude *.!sync
exclude .DS_Store
exclude ._.DS_Store
exclude .Thumbs.db
exclude .fseventsd
exclude .Spotlight-V100
exclude .TemporaryItems
exclude .Trashes

Go in the /home/thomas/.local/soft/ directory and clone the snapraid-runner repository.

Then, create the snapraid-runner.conf file:

[snapraid]
; path to the snapraid executable (e.g. /bin/snapraid)
executable = /usr/local/bin/snapraid
; path to the snapraid config to be used
config = /etc/snapraid.conf
; abort operation if there are more deletes than this, set to -1 to disable
deletethreshold = -1
; if you want touch to be ran each time
touch = true

[logging]
; logfile to write to, leave empty to disable
file = snapraid.log
; maximum logfile size in KiB, leave empty for infinite
maxsize = 5000

[gotify]
sendon = error
url = https://gotify.tdehaeze.xyz
token = <<get-password(passname="nas/gotify_snapraid_token")>>

[scrub]
; set to true to run scrub after sync
enabled = true
; scrub plan - either a percentage or one of [bad, new, full]
plan = 12
; minimum block age (in days) for scrubbing. Only used with percentage plans
older-than = 10

And finally, create a cronjob with sudo crontab -e and add the following line:

0 3 * * * python3 /home/thomas/.local/soft/snapraid-runner/snapraid-runner.py -c /home/thomas/.local/soft/snapraid-runner/snapraid-runner.conf >> /home/thomas/cron/snapraid_runner.log 2>&1

Install Docker

The procedure is well explained here.

If docker is already installed, remove it:

sudo apt remove docker

Executing the Docker Command Without Sudo

sudo usermod -aG docker ${USER}

To apply the new group membership, log out of the server and back in, or type the following:

su - ${USER}

Install Docker-Compose

sudo apt install docker-compose

Setup Docker Networks

docker network create --gateway 192.168.90.1 --subnet 192.168.90.0/24 t2_proxy
docker network create docker_default

Change Timezone

sudo timedatectl set-timezone Europe/Paris

Secure the Web Server

Most of it comes from here.

  • Set PasswordAuthentication no in /etc/ssh/sshd_config

Automatic Security Updates

The procedure is well explained here.

sudo apt install unattended-upgrades update-notifier-common

Edit /etc/apt/apt.conf.d/50unattended-upgrades, and change the following lines:

Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

Edit /etc/apt/apt.conf.d/20auto-upgrades:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

Setup cronjobs

Create a folder ~/cron with all the scripts and logs related to cron.

To edit the cron jobs, type crontab -e and add a line like:

*/5 * * * * /home/thomas/cron/caddy_update.sh >> /home/thomas/cron/caddy_update.log 2>&1

That will run every 5 minutes. To check how the first part of the crontab works, check this website.

Setup Traefik proxy

Follow this guide.

Run docker-compose

cd ~/docker && docker-compose up -d

Docker config ~/.docker/config.json

{
  "psFormat": "table {{ .ID }}\\t{{ .Names }}\t{{ .Status }}"
}

Maintenance - How To

Update System/Packages

sudo -- sh -c 'apt-get update; apt-get upgrade -y; apt-get dist-upgrade -y; apt-get autoremove -y; apt-get autoclean -y'

Snapraid errors

If there are errors, you can check what is going on with:

sudo snapraid status

To fix the errors:

sudo snapraid -e fix

You can check again if everything is fixed using the scrub command:

sudo snapraid scrub

Docker Commands

  • Starting a container: $ docker start homeassistant
  • Stopping a container: $ docker stop homeassistant
  • Restarting a container: $ docker restart homeassistant
  • Listing the running containers: $ docker ps or $ cd ~/docker/ && docker-compose ps
  • View the logs of a container: $ docker logs -f homeassistant
  • Drop a shell into a container: $ docker exec -it homeassistant /bin/bash
  • Update specific container: docker-compose pull --ignore-pull-failures homeassistant

Update All Containers

cd ~/docker/ && docker-compose pull --ignore-pull-failures && docker-compose up -d

Clean up Docker environment This will delete all unused images, volumes and networks.

docker system prune -f && docker image prune -f && docker volume prune -f

Add wireguard client

With an Android client

Show the QRcode corresponding the a specific peer with:

docker exec -it wireguard /app/show-peer 1

Then, simply scan the QRcode with the Wireguard application.

With a Linux client

Copy the file $CONFIGDIR/wireguard/peeri/peeri.conf, e.g.:

[Interface]
Address = 10.13.13.4/24
DNS = 10.13.1.1
PrivateKey = ****
ListenPort = 51820

[Peer]
PublicKey = ****
Endpoint = wireguard.tdehaeze.xyz:51820
AllowedIPs = 0.0.0.0/0, ::0/0

Then, paste the file to /etc/wireguard/interfacename.conf. And then:

  • sudo chmod 600 /etc/wireguard/interfacename.conf
  • sudo chown root:root /etc/wireguard/interfacename.conf

Then, start the tunnel with:

wg-quick up interfacename

Add new user to authelia

Modify the user database file:

nvim ~/docker/config/authelia/users_database.yml

Add an entry for the new user. Restart the container with docker-compose restart authelia. Ask the new user to go to https://login.tdehaeze.xyz/ to reset his password.

Docker-Compose

Basic Config

version: "3.8"
networks:
  t2_proxy:
    external:
      name: t2_proxy
  immich:
    external: false
  backend:
    external: false
  default:
    driver: bridge
x-logging:
  &default-logging
  driver: "json-file"
  options:
    max-size: "200k"
    max-file: "10"
services:

Docker Config and Tools

traefik - Application proxy (link)

  traefik:
    container_name: traefik
    image: traefik:2.9
    restart: unless-stopped
    depends_on:
      - authelia
    networks:
      t2_proxy:
        ipv4_address: 192.168.90.254 # You can specify a static IP
    security_opt:
      - no-new-privileges:true
    ports:
      - 80:80 # http
      - 443:443 # https
      - 8448:8448 # Matrix
    volumes:
      - $CONFIGDIR/traefik2/acme.json:/acme.json
      - $CONFIGDIR/traefik2/traefik.yaml:/etc/traefik/traefik.yaml
      - $CONFIGDIR/traefik2/services.yaml:/etc/traefik/services.yaml
      - /var/log/traefik:/var/log
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - CF_API_EMAIL=$CLOUDFLARE_EMAIL
      - CF_API_KEY=$CLOUDFLARE_API_KEY
    labels:
      - "traefik.enable=true"
      # HTTP-to-HTTPS Redirect
      - "traefik.http.routers.http-catchall.entryPoints=web"
      - "traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`)"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
      # HTTP Routers
      - "traefik.http.routers.traefik-rtr.entrypoints=web-secure"
      - "traefik.http.routers.traefik-rtr.rule=Host(`traefik.$DOMAINNAME`)"
      - "traefik.http.routers.traefik-rtr.tls=true"
      - "traefik.http.routers.traefik-rtr.middlewares=authelia@docker"
      - "traefik.http.routers.traefik-rtr.service=traefik-svc"
      # - "traefik.http.routers.traefik-rtr.tls.certresolver=dns-cloudflare" # Comment out this line after first run of traefik to force the use of wildcard certs
      - "traefik.http.routers.traefik-rtr.tls.domains[0].main=$DOMAINNAME"
      - "traefik.http.routers.traefik-rtr.tls.domains[0].sans=*.$DOMAINNAME"
      - "traefik.http.routers.traefik-rtr.tls.domains[1].main=wingaudio.fr"
      - "traefik.http.routers.traefik-rtr.tls.domains[1].sans=*.wingaudio.fr"
      - "traefik.http.services.traefik-svc.loadbalancer.server.port=8080"
      # Services - API
      - "traefik.http.routers.traefik-rtr.service=api@internal"
      # Router
      - "traefik.http.routers.openwrt.entrypoints=web-secure"
      - "traefik.http.routers.openwrt.rule=Host(`openwrt.$DOMAINNAME`)"
      - "traefik.http.routers.openwrt.tls=true"
      - "traefik.http.routers.openwrt.service=openwrt@file"
      # Valetudo
      - "traefik.http.routers.valetudo.entrypoints=web-secure"
      - "traefik.http.routers.valetudo.rule=Host(`valetudo.$DOMAINNAME`)"
      - "traefik.http.routers.valetudo.tls=true"
      - "traefik.http.routers.valetudo.middlewares=authelia@docker"
      - "traefik.http.routers.valetudo.service=valetudo@file"
    logging: *default-logging

traefik.yaml

global:
  checkNewVersion: true
  sendAnonymousUsage: false

entryPoints:
  web:
    address: :80
  web-secure:
    address: :443
    forwardedHeaders:
      trustedIPs: 173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/12,172.64.0.0/13,131.0.72.0/22
  matrix-federation:
    address: :8448

api:
  dashboard: true

log:
  level: ERROR

metrics:
  influxDB2:
    address: https://influxdb.$DOMAINNAME
    token: dhkvChi1tXrMY18plDTWifz8MZNUm2M4QGpEAd2FftmMlfsN7KLq96uQXADbiQxDb1Vo2pYTSblCGqrfVygqJw==
    org: homelab
    bucket: traefik

accessLog:
  filePath: /var/log/access.log
  filters:
    statusCodes: 400-499

providers:
  docker:
    endpoint: unix:///var/run/docker.sock
    defaultrule: Host(`{{ index .Labels "com.docker.compose.service" }}.$DOMAINNAME`)
    exposedByDefault: false
    network: t2_proxy
    swarmMode: false
  file:
    filename: /etc/traefik/services.yaml

serversTransport:
  insecureSkipVerify: true # Necessary for Unifi (but not recommended)

certificatesResolvers:
  dns-cloudflare:
    acme:
      # caServer: https://acme-staging-v02.api.letsencrypt.org/directory # LetsEncrypt Staging Server - uncomment when testing
      email: dehaeze.thomas@gmail.com
      storage: /acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers: 1.1.1.1:53,1.0.0.1:53
        # delayBeforeCheck: 90 # To delay DNS check and reduce LE hitrate
http:
  services:
    openwrt:
      loadBalancer:
        servers:
        - url: "http://192.168.1.1/"
    valetudo:
      loadBalancer:
        servers:
        - url: "http://192.168.1.110/"
        - url: "http://192.168.2.157/"
        - url: "http://192.168.5.157/"
        healthCheck:
          path: /
  middlewares:
    unifiHeaders:
      headers:
        customRequestHeaders:
          Authorization: "" # Removes

authelia - Single Sign-On Multi-Factor portal (link)

  authelia:
    image: authelia/authelia:4.35
    container_name: authelia
    restart: unless-stopped
    networks:
      - t2_proxy
      - backend
    volumes:
      - $CONFIGDIR/authelia:/config
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - AUTHELIA_NOTIFIER_SMTP_PASSWORD=$GOOGLE_AUTHELIA_PASS
      - AUTHELIA_JWT_SECRET=$AUTHELIA_JWT_SECRET
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.authelia-rtr.entrypoints=web-secure"
      - "traefik.http.routers.authelia-rtr.tls=true"
      - "traefik.http.routers.authelia-rtr.service=authelia-svc"
      - "traefik.http.routers.authelia-rtr.rule=Host(`login.$DOMAINNAME`)"
      - "traefik.http.services.authelia-svc.loadbalancer.server.port=9091"
      - "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://login.$DOMAINNAME/"
      - "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true"
      - "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email"
      - "treafik.http.middlewares.chain-authelia.chain.middlewares=middlewares-rate-limit, middlewares-secure-headers, middlewares-authelia"
      - "traefik.docker.network=t2_proxy"

configuration.yml

---
###############################################################
#                   Authelia configuration                    #
###############################################################

default_redirection_url: https://authelia.tdehaeze.xyz

server:
  host: 0.0.0.0
  port: 9091

log:
  level: debug

totp:
  issuer: authelia.com
  period: 30
  skew: 1

authentication_backend:
  file:
    path: /config/users_database.yml
    password:
      algorithm: argon2id
      iterations: 1
      salt_length: 16
      parallelism: 8
      memory: 1024

access_control:
  default_policy: deny
  rules:
    - domain: valetudo.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
      - ["group:family"]
    - domain: openwrt.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: traefik.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: scrutiny.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: sync-ju.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: sync-jm.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: sync-anne.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: syncthing.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: uptime.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: wireguard.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: joal.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: change.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: esphome.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: influxdb.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: node-red.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
      - ["group:family"]
    - domain: zigbee2mqtt.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: qobuz.tdehaeze.xyz
      policy: bypass
      resources:
      - "^/download.*$"
    - domain: qobuz.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
      - ["group:friends"]
      - ["group:family"]
    - domain: sonarr.tdehaeze.xyz
      policy: bypass
      resources:
      - "^/api.*$"
    - domain: sonarr.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: radarr.tdehaeze.xyz
      policy: bypass
      resources:
      - "^/api.*$"
    - domain: radarr.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: unifi.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]

session:
  name: authelia_session
  expiration: 3600
  inactivity: 300
  domain: tdehaeze.xyz

regulation:
  max_retries: 3
  find_time: 120
  ban_time: 300

storage:
  encryption_key: bUEO5bYNJYziXUxEWFYubUmUdUZPhy
  local:
    path: /config/db.sqlite3

notifier:
  smtp:
    host: smtp.gmail.com
    port: 587
    username: tdehaeze.xyz@gmail.com
    sender: tdehaeze.xyz@gmail.com

uptime-kuma - Monitoring Tool (link)

  uptime-kuma:
    container_name: uptime-kuma
    image: louislam/uptime-kuma
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - TZ=$TZ
      - PUID=$PUID
      - PGID=$PGID
    volumes:
      - $CONFIGDIR/uptime-kuma:/app/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.uptime-rtr.entrypoints=web-secure"
      - "traefik.http.routers.uptime-rtr.rule=Host(`uptime.$DOMAINNAME`)"
      - "traefik.http.routers.uptime-rtr.tls=true"
      - "traefik.http.routers.uptime-rtr.service=uptime-svc"
      - "traefik.http.routers.uptime-rtr.middlewares=authelia@docker"
      - "traefik.http.services.uptime-svc.loadbalancer.server.port=3001"
    logging: *default-logging

gotify - Notification service (link)

In order to have notifications on Linux desktop use gotify-dunst.

  gotify:
    container_name: gotify
    image: gotify/server
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - GOTIFY_DEFAULTUSER_NAME=$GOTIFY_DEFAULTUSER_NAME
      - GOTIFY_DEFAULTUSER_PASS=$GOTIFY_DEFAULTUSER_PASS
    volumes:
      - $CONFIGDIR/gotify:/app/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.gotify-rtr.entrypoints=web-secure"
      - "traefik.http.routers.gotify-rtr.rule=Host(`gotify.$DOMAINNAME`)"
      - "traefik.http.routers.gotify-rtr.tls=true"
      - "traefik.http.routers.gotify-rtr.service=gotify-svc"
      - "traefik.http.services.gotify-svc.loadbalancer.server.port=80"

scrutiny - Hard drive monitoring (link)

  scrutiny-web:
    container_name: scrutiny-web
    image: ghcr.io/analogj/scrutiny:master-web
    restart: unless-stopped
    networks:
      - t2_proxy
      - backend
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - SCRUTINY_WEB_INFLUXDB_HOST=influxdb
    volumes:
      - $CONFIGDIR/scrutiny:/opt/scrutiny/config
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.scrutiny-rtr.entrypoints=web-secure"
      - "traefik.http.routers.scrutiny-rtr.rule=Host(`scrutiny.$DOMAINNAME`)"
      - "traefik.http.routers.scrutiny-rtr.tls=true"
      - "traefik.http.routers.scrutiny-rtr.service=scrutiny-svc"
      - "traefik.http.routers.scrutiny-rtr.middlewares=authelia@docker"
      - "traefik.http.services.scrutiny-svc.loadbalancer.server.port=8080"
    logging: *default-logging
  scrutiny-collector:
    container_name: scrutiny-collector
    image: ghcr.io/analogj/scrutiny:master-collector
    restart: unless-stopped
    cap_add:
      - SYS_RAWIO
      - SYS_ADMIN
    networks:
      - backend
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - COLLECTOR_API_ENDPOINT=http://scrutiny-web:8080
    volumes:
      - /run/udev:/run/udev:ro
    devices:
      - /dev/sda:/dev/sda
      - /dev/sdb:/dev/sdb
      - /dev/sdc:/dev/sdc
      - /dev/nvme0:/dev/nvme0
    logging: *default-logging

wireguard - VPN (link)

  wireguard:
    container_name: wireguard
    image: weejewel/wg-easy
    restart: unless-stopped
    networks:
      - t2_proxy
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - WG_HOST=82.66.44.13
      - PASSWORD=$WIREGUARD_PASS
    volumes:
      - $CONFIGDIR/wg-easy:/etc/wireguard
    ports:
      - 51820:51820/udp
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wireguard-rtr.entrypoints=web-secure"
      - "traefik.http.routers.wireguard-rtr.rule=Host(`wireguard.$DOMAINNAME`)"
      - "traefik.http.routers.wireguard-rtr.tls=true"
      - "traefik.http.routers.wireguard-rtr.service=wireguard-svc"
      - "traefik.http.routers.wireguard-rtr.middlewares=authelia@docker"
      - "traefik.http.services.wireguard-svc.loadbalancer.server.port=51821"
    logging: *default-logging

nginx - Root (used for Matrix)

  root:
    container_name: root
    image: nginx
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/root/nginx.conf:/etc/nginx/nginx.conf
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.root-rtr.entrypoints=web-secure"
      - "traefik.http.routers.root-rtr.rule=Host(`$DOMAINNAME`)"
      - "traefik.http.routers.root-rtr.tls=true"
      - "traefik.http.routers.root-rtr.service=root-svc"
      - "traefik.http.services.root-svc.loadbalancer.server.port=8080"
    logging: *default-logging

nginx.conf

events {

}

http {
    server {
        server_name tdehaeze.xyz;
        listen 8080;

        location /.well-known/matrix/client {
            proxy_pass https://matrix.tdehaeze.xyz/.well-known/matrix/client;
            proxy_set_header X-Forwarded-For $remote_addr;
        }

        location /.well-known/matrix/server {
            proxy_pass https://matrix.tdehaeze.xyz/.well-known/matrix/server;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
    }
}

commento - Commenting system (link)

  commento:
    container_name: commento
    image: registry.gitlab.com/commento/commento
    restart: unless-stopped
    networks:
      - t2_proxy
      - backend
    # ports:
    #   - 8080:8080
    environment:
      - TZ=$TZ
      - UID=$PUID
      - GID=$PGID
      - COMMENTO_ORIGIN=https://commento.tdehaeze.xyz/
      - COMMENTO_PORT=8080
      - COMMENTO_POSTGRES=postgres://postgres:$COMMENTO_DB_PASSWORD@commento_db:5432/commento?sslmode=disable
      - COMMENTO_SMTP_HOST=smtp.gmail.com
      - COMMENTO_SMTP_PORT=587
      - COMMENTO_SMTP_USERNAME=tdehaeze.xyz@gmail.com
      - COMMENTO_SMTP_PASSWORD=$GOOGLE_AUTHELIA_PASS
      - COMMENTO_SMTP_FROM_ADDRESS=tdehaeze.xyz@gmail.com
    depends_on:
      - commento_db
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.commento-rtr.entrypoints=web-secure"
      - "traefik.http.routers.commento-rtr.rule=Host(`commento.$DOMAINNAME`)"
      - "traefik.http.routers.commento-rtr.tls=true"
      - "traefik.http.routers.commento-rtr.service=commento-svc"
      - "traefik.http.services.commento-svc.loadbalancer.server.port=8080"
    logging: *default-logging
  commento_db:
    container_name: commento_db
    image: postgres:13
    restart: unless-stopped
    networks:
      - backend
    user: "${PUID}:${PGID}"
    environment:
      - POSTGRES_DB=commento
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=$COMMENTO_DB_PASSWORD
    volumes:
      - $CONFIGDIR/commento_db:/var/lib/postgresql/data
    logging: *default-logging

unifi-controller - Software for Unifi devices (link)

  unifi-mongodb:
    container_name: unifi-mongodb
    image: mongo:4
    networks:
      - backend
    restart: unless-stopped
    environment:
      - UID=$PUID
      - GID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/unifi-mongodb/db:/data/db
    logging: *default-logging
  unifi-controller:
    container_name: unifi-controller
    image: linuxserver/unifi-network-application
    networks:
      - t2_proxy
      - backend
    restart: unless-stopped
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - MONGO_USER=unifi
      - MONGO_PASS=bMhre3Nza6mZzz1m
      - MONGO_HOST=unifi-mongodb
      - MONGO_PORT=27017
      - MONGO_DBNAME=unifi
    volumes:
      - $CONFIGDIR/unifi/data:/config
    ports:
      # - 8443:8443
      - 3478:3478/udp
      - 10001:10001/udp
      - 8080:8080
      # - 1900:1900/udp #optional
      # - 8843:8843 #optional
      # - 8880:8880 #optional
      # - 6789:6789 #optional
      # - 5514:5514/udp #optional
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.unifi-rtr.entrypoints=web-secure"
      - "traefik.http.routers.unifi-rtr.rule=Host(`unifi.$DOMAINNAME`)"
      - "traefik.http.routers.unifi-rtr.tls=true"
      - "traefik.http.routers.unifi-rtr.service=unifi-svc"
      - "traefik.http.routers.unifi-rtr.middlewares=unifiHeaders@file"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      # - "traefik.http.routers.unifi-rtr.middlewares=authelia@docker"
      - "traefik.http.services.unifi-svc.loadbalancer.server.port=8443"
      - "traefik.http.services.unifi-svc.loadbalancer.server.scheme=https"
    logging: *default-logging
  unifi-controller:
    container_name: unifi-controller
    image: jacobalberty/unifi
    networks:
      - t2_proxy
    restart: unless-stopped
    environment:
      - RUNAS_UID0=false
      - UNIFI_UID=$PUID
      - UNIFI_GID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/unifi-controller/data:/unifi/data
      - $CONFIGDIR/unifi-controller/log:/unifi/log
      - $CONFIGDIR/unifi-controller/cert:/unifi/cert
      - $CONFIGDIR/unifi-controller/init.d:/unifi/init.d
    ports:
      - 3478:3478/udp # STUN
      - 10001:10001/udp # AP discovery
      - 6789:6789/tcp # Speed test
      - 8080:8080/tcp # Device/ controller comm.
      - 8443:8443/tcp # Controller GUI/API as seen in a web browser
      - 8880:8880/tcp # HTTP portal redirection
      - 8843:8843/tcp # HTTPS portal redirection
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.unifi-rtr.entrypoints=web-secure"
      - "traefik.http.routers.unifi-rtr.rule=Host(`unifi.$DOMAINNAME`)"
      - "traefik.http.routers.unifi-rtr.tls=true"
      - "traefik.http.routers.unifi-rtr.service=unifi-svc"
      - "traefik.http.services.unifi-svc.loadbalancer.serverstransport=ignorecert"
      - "traefik.http.services.unifi-svc.loadbalancer.server.scheme=https"
      - "traefik.http.services.unifi-svc.loadbalancer.server.port=8443"
    logging: *default-logging

Metrics

influxdb

  influxdb:
    container_name: influxdb
    image: influxdb
    restart: unless-stopped
    networks:
      - t2_proxy
      - backend
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/influxdb:/var/lib/influxdb2:rw
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.influxdb-rtr.entrypoints=web-secure"
      - "traefik.http.routers.influxdb-rtr.rule=Host(`influxdb.$DOMAINNAME`)"
      - "traefik.http.routers.influxdb-rtr.tls=true"
      - "traefik.http.routers.influxdb-rtr.service=influxdb-svc"
      - "traefik.http.services.influxdb-svc.loadbalancer.server.port=8086"
    healthcheck:
      test: "curl -f http://localhost:8086/ping"
      interval: 5s
      timeout: 10s
      retries: 5
    logging: *default-logging

Websites

homer - Home page for myself (link)

  homer:
    container_name: homer
    image: b4bz/homer
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - UID=$PUID
      - GID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/homer/assets/:/www/assets
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.homer-rtr.entrypoints=web-secure"
      - "traefik.http.routers.homer-rtr.rule=Host(`homer.$DOMAINNAME`)"
      - "traefik.http.routers.homer-rtr.tls=true"
      - "traefik.http.routers.homer-rtr.service=homer-svc"
      - "traefik.http.services.homer-svc.loadbalancer.server.port=8080"
    logging: *default-logging

config.yml

---
title: "Homepage"
subtitle: ""
logo: "assets/homer.png"
header: false
footer: false

columns: "auto"
connectivityCheck: false

theme: default

links: []

services:
  - name: "Websites"
    icon: "fas fa-desktop"
    items:
    - name: "Brain"
      logo: "/assets/tools/brain.png"
      subtitle: "Digital Brain"
      url: "https://brain.tdehaeze.xyz"
    - name: "Research"
      logo: "/assets/tools/orgmode.png"
      subtitle: "Research Pages"
      url: "https://research.tdehaeze.xyz"
    - name: "Help"
      logo: "/assets/tools/help.png"
      subtitle: "Help Page"
      url: "https://help.tdehaeze.xyz"
    - name: "Dotfiles"
      logo: "/assets/tools/dotfiles.png"
      subtitle: "My Literate Dotfiles"
      url: "https://dotfiles.tdehaeze.xyz"
    - name: "Miam"
      logo: "/assets/tools/miam.png"
      subtitle: "Personnal Recipes"
      url: "https://miam.tdehaeze.xyz"
    - name: "Miniflux"
      logo: "/assets/tools/miniflux.png"
      subtitle: "RSS Feeds"
      url: "https://rss.tdehaeze.xyz"
    - name: "LinkDing"
      logo: "/assets/tools/linkding.png"
      subtitle: "Bookmark Manager"
      url: "https://bm.tdehaeze.xyz"
  - name: "Multimedia"
    icon: "fas fa-photo-video"
    items:
    - name: "Jellyfin"
      logo: "/assets/tools/jellyfin.png"
      subtitle: "Media Library"
      url: "https://jellyfin.tdehaeze.xyz"
    - name: "JFA-Go"
      logo: "/assets/tools/jellyfin.png"
      subtitle: "Manage Jellyfin Users"
      url: "http://jfa.tdehaeze.xyz/"
    # - name: "Audioserve"
    #   logo: "/assets/tools/audiobook.png"
    #   subtitle: "Audiobook Server"
    #   url: "https://audiobook.tdehaeze.xyz"
    # - name: "Kavita"
    #   logo: "/assets/tools/kavita.png"
    #   subtitle: "Book Library"
    #   url: "https://kavita.tdehaeze.xyz"
  - name: "Cloud"
    icon: "fas fa-cloud"
    items:
    - name: "Cinny"
      logo: "/assets/tools/cinny.png"
      subtitle: "Matrix web client"
      url: "https://cinny.tdehaeze.xyz"
    - name: "File Browser"
      logo: "/assets/tools/cloud.png"
      subtitle: "Simple Personnal Could"
      url: "https://cloud.tdehaeze.xyz"
    - name: "Syncthing"
      logo: "/assets/tools/syncthing.png"
      subtitle: "Anne"
      url: "https://sync-anne.tdehaeze.xyz"
    - name: "Syncthing"
      logo: "/assets/tools/syncthing.png"
      subtitle: "Juliette"
      url: "https://sync-ju.tdehaeze.xyz"
    - name: "Syncthing"
      logo: "/assets/tools/syncthing.png"
      subtitle: "Jean-Marie"
      url: "https://sync-jm.tdehaeze.xyz"
    - name: "Syncthing"
      logo: "/assets/tools/syncthing.png"
      subtitle: "P2P Sync"
      url: "https://syncthing.tdehaeze.xyz"
    - name: "Radicale"
      logo: "/assets/tools/radicale.png"
      subtitle: "CalDAV/CardDAV Server"
      url: "https://radicale.tdehaeze.xyz"
    - name: "Gitea"
      logo: "/assets/tools/gitea.png"
      subtitle: "Git Server"
      url: "https://git.tdehaeze.xyz"
  - name: "Download"
    icon: "fas fa-download"
    items:
    - name: "JellySrerr"
      logo: "/assets/tools/jellyseerr.png"
      subtitle: "Torrent Client"
      url: "http://jellyseerr.tdehaeze.xyz/"
    # - name: "Down"
    #   logo: "/assets/tools/down.png"
    #   subtitle: "Torrent Download"
    #   url: "https://down.tdehaeze.xyz/"
    - name: "Qobuz"
      subtitle: "Music Download"
      logo: "/assets/tools/qobuz.png"
      url: "https://qobuz.tdehaeze.xyz"
    - name: "Sonarr"
      logo: "/assets/tools/sonarr.png"
      subtitle: "TVShows Download"
      url: "http://sonarr.tdehaeze.xyz/"
    - name: "Radarr"
      logo: "/assets/tools/radarr.png"
      subtitle: "Movies Download"
      url: "http://radarr.tdehaeze.xyz/"
    - name: "Prowlarr"
      logo: "/assets/tools/prowlarr.png"
      subtitle: "Torrent Indexer"
      url: "http://prowlarr.tdehaeze.xyz/"
    # - name: "Jackett"
    #   logo: "/assets/tools/jackett.png"
    #   subtitle: "Torrent Client"
    #   url: "http://jackett.tdehaeze.xyz/"
    - name: "Transmission"
      logo: "/assets/tools/transmission.png"
      subtitle: "Torrent Client"
      url: "http://torrent.tdehaeze.xyz/transmission/web/"
  - name: "Config"
    icon: "fas fa-cog"
    items:
    # - name: "Portainer"
    #   logo: "/assets/tools/portainer.png"
    #   subtitle: "Manger Docker"
    #   url: "https://portainer.tdehaeze.xyz/#/containers"
    - name: "Traefik"
      logo: "/assets/tools/traefik.png"
      subtitle: "Reverse Proxy"
      url: "https://traefik.tdehaeze.xyz"
    - name: "Wireguard"
      logo: "/assets/tools/wireguard.png"
      subtitle: "Manger Docker"
      url: "https://wireguard.tdehaeze.xyz/"
    - name: "Uptime"
      logo: "/assets/tools/uptime.png"
      subtitle: "Monitoring"
      url: "https://uptime.tdehaeze.xyz"
    - name: "Commento"
      logo: "/assets/tools/commento.png"
      subtitle: "Commenting System"
      url: "https://commento.tdehaeze.xyz"
    - name: "Gotify"
      logo: "/assets/tools/gotify.png"
      subtitle: "Messaging System"
      url: "https://gotify.tdehaeze.xyz"
    - name: "Scrutiny"
      logo: "/assets/tools/scrutiny.png"
      subtitle: "S.M.A.R.T"
      url: "http://scrutiny.tdehaeze.xyz/web/dashboard"
  - name: "Home"
    icon: "fas fa-home"
    items:
    - name: "OpenWRT"
      logo: "/assets/tools/openwrt.png"
      subtitle: "Router"
      url: "https://openwrt.tdehaeze.xyz/"
    - name: "Unifi"
      logo: "/assets/tools/unifi.png"
      subtitle: "Wifi Expander"
      url: "https://unifi.tdehaeze.xyz/"
    - name: "Changedetection.io"
      logo: "/assets/tools/changedetection.png"
      subtitle: "Detect change in websites"
      url: "https://change.tdehaeze.xyz"
    - name: "Zigbee2MQTT"
      logo: "/assets/tools/zigbee2mqtt.png"
      subtitle: "Zigbee2MQTT"
      url: "https://zigbee2mqtt.tdehaeze.xyz/"
    - name: "Node Red"
      logo: "/assets/tools/node-red.png"
      subtitle: "Event-driven applications"
      url: "https://node-red.tdehaeze.xyz/"
    - name: "InfluxDB"
      logo: "/assets/tools/influxdb.png"
      subtitle: "Time series database"
      url: "https://influxdb.tdehaeze.xyz/"
    - name: "ESPHome"
      logo: "/assets/tools/esphome.png"
      subtitle: "System to control ESP8266/ESP32"
      url: "https://esphome.tdehaeze.xyz/"
    - name: "OctoPrint"
      logo: "/assets/tools/octoprint.png"
      subtitle: "Tina2"
      url: "https://3d-printer.tdehaeze.xyz/"

family - Home page for family (link)

  famille:
    container_name: famille
    image: b4bz/homer
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - UID=$PUID
      - GID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/famille/assets/:/www/assets
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.famille-rtr.entrypoints=web-secure"
      - "traefik.http.routers.famille-rtr.rule=Host(`famille.$DOMAINNAME`)"
      - "traefik.http.routers.famille-rtr.tls=true"
      - "traefik.http.routers.famille-rtr.service=famille-svc"
      - "traefik.http.services.famille-svc.loadbalancer.server.port=8080"
    logging: *default-logging

config.yml

---
title: "Homepage"
subtitle: ""
logo: "assets/homer.png"
header: false
footer: false

columns: "auto"
connectivityCheck: false

theme: default

message:
  style: "" # See https://bulma.io/documentation/components/message/#colors for styling options.
  title: "Coucou !"
  content: "Ci dessous tu peux trouver différents sites accéssibles sur mon serveur. Si tu as besoin d'aide avec l'utilisation de Jellyfin, tout est expliqué <a href='https://help.tdehaeze.xyz/'>ici</a>."


links: []

services:
  - name: "Websites"
    icon: "fas fa-desktop"
    items:
    - name: "Jellyfin"
      logo: "/assets/tools/jellyfin.png"
      subtitle: "Librairie multimédia"
      url: "https://jellyfin.tdehaeze.xyz"
    - name: "File Browser"
      logo: "/assets/tools/cloud.png"
      subtitle: "Cloud personnel"
      url: "https://cloud.tdehaeze.xyz"
    - name: "Miam"
      logo: "/assets/tools/miam.png"
      subtitle: "Site de recettes partagées"
      url: "https://miam.tdehaeze.xyz"
  - name: "Multimedia"
    icon: "fas fa-photo-video"
    items:
    - name: "Jellyseerr"
      subtitle: "Ajout de Films/Séries sur Jellyfin"
      logo: "/assets/tools/jellyseerr.png"
      url: "https://jellyseerr.tdehaeze.xyz"
    - name: "Qobuz"
      subtitle: "Ajout de Musique sur Jellyfin"
      logo: "/assets/tools/qobuz.png"
      url: "https://qobuz.tdehaeze.xyz"

hugo - Wiki + Blog (link)

  hugo:
    container_name: hugo
    image: tdehaeze/hugo-caddy
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
        - REPO=git.tdehaeze.xyz/tdehaeze/digital-brain
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.hugo-rtr.entrypoints=web-secure"
      - "traefik.http.routers.hugo-rtr.rule=Host(`brain.$DOMAINNAME`)"
      - "traefik.http.routers.hugo-rtr.tls=true"
      - "traefik.http.routers.hugo-rtr.service=hugo-svc"
      - "traefik.http.services.hugo-svc.loadbalancer.server.port=2015"
    logging: *default-logging

research - Research Pages (link)

  research:
    container_name: research
    image: abiosoft/caddy:1.0.3-no-stats
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - PLUGINS=git
    volumes:
      - $CONFIGDIR/research/Caddyfile:/etc/Caddyfile
      - $CONFIGDIR/research/web:/srv
        # - ~/.ssh:/root/.ssh
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.caddy-rtr.entrypoints=web-secure"
      - "traefik.http.routers.caddy-rtr.rule=Host(`research.$DOMAINNAME`)"
      - "traefik.http.routers.caddy-rtr.tls=true"
      - "traefik.http.routers.caddy-rtr.service=caddy-svc"
      - "traefik.http.services.caddy-svc.loadbalancer.server.port=2015"
    logging: *default-logging

Caddyfile

0.0.0.0:2015 {
    root /srv/www/

    git {
        repo     https://git.tdehaeze.xyz/tdehaeze/research-home-page
        path     /srv/www/
        interval -1
        hook     /research-home-page/webhook QHZgAKjD8q2v54Ru
        then     git submodule update --init --recursive --merge --remote
    }
}

dotfiles - Dotfiles (link)

  dotfiles:
    container_name: dotfiles
    image: abiosoft/caddy:1.0.3-no-stats
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - PLUGINS=git
    volumes:
      - $CONFIGDIR/dotfiles/Caddyfile:/etc/Caddyfile
      - $CONFIGDIR/dotfiles/www:/srv/www
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dotfiles-rtr.entrypoints=web-secure"
      - "traefik.http.routers.dotfiles-rtr.rule=Host(`dotfiles.$DOMAINNAME`)"
      - "traefik.http.routers.dotfiles-rtr.tls=true"
      - "traefik.http.routers.dotfiles-rtr.service=dotfiles-svc"
      - "traefik.http.services.dotfiles-svc.loadbalancer.server.port=2015"
    logging: *default-logging

Caddyfile

0.0.0.0:2015 {
    root /srv/www/docs/

    git {
        repo     https://git.tdehaeze.xyz/tdehaeze/literate-dotfiles
        path     /srv/www/
        interval -1
        hook     /literate-dotfiles/webhook QHZgAKjD8q2v54Ru
    }
}

help - Help page for Jellyfin (link)

  help:
    container_name: help
    image: abiosoft/caddy:1.0.3-no-stats
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - PLUGINS=git
    volumes:
      - $CONFIGDIR/help/Caddyfile:/etc/Caddyfile
      - $CONFIGDIR/help/www:/srv/www
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.help-rtr.entrypoints=web-secure"
      - "traefik.http.routers.help-rtr.rule=Host(`help.$DOMAINNAME`)"
      - "traefik.http.routers.help-rtr.tls=true"
      - "traefik.http.routers.help-rtr.service=help-svc"
      - "traefik.http.services.help-svc.loadbalancer.server.port=2015"
    logging: *default-logging

Caddyfile

0.0.0.0:2015 {
    root /srv/www/

    git {
        repo     https://git.tdehaeze.xyz/tdehaeze/family-page
        path     /srv/www/
        interval -1
        hook     /help/webhook 0fdVzNShbcmw
    }
}

mealie - Recipe Manager (link)

  miam:
    container_name: miam
    image: hkotel/mealie
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - db_type=sqlite
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/mealie:/app/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.miam-rtr.entrypoints=web-secure"
      - "traefik.http.routers.miam-rtr.rule=Host(`miam.$DOMAINNAME`)"
      - "traefik.http.routers.miam-rtr.tls=true"
      - "traefik.http.routers.miam-rtr.service=miam-svc"
      - "traefik.http.services.miam-svc.loadbalancer.server.port=80"
    logging: *default-logging

gitea - Git server (link)

  gitea:
    container_name: git
    image: gitea/gitea
    depends_on:
      - gitea_db
    restart: unless-stopped
    networks:
      - t2_proxy
      - backend
    volumes:
      - $CONFIGDIR/gitea:/data
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - SSH_PORT=$GITEA_SSH_PORT
    ports:
      - "2222:22"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.git-rtr.entrypoints=web-secure"
      - "traefik.http.routers.git-rtr.rule=Host(`git.$DOMAINNAME`)"
      - "traefik.http.routers.git-rtr.tls=true"
      - "traefik.http.routers.git-rtr.service=git-svc"
      - "traefik.http.services.git-svc.loadbalancer.server.port=3000"
    logging: *default-logging
  gitea_db:
    container_name: gitea_db
    image: mariadb:10
    restart: unless-stopped
    networks:
      - backend
    ports:
      - 3306:3306
    user: "${PUID}:${PGID}"
    environment:
      - MYSQL_ROOT_PASSWORD=$GITEA_DB_MYSQL_ROOT_PASSWORD
      - MYSQL_DATABASE=gitea
      - MYSQL_USER=gitea
      - MYSQL_PASSWORD=$GITEA_DB_MYSQL_PASSWORD
    volumes:
      - $CONFIGDIR/gitea_db:/var/lib/mysql

changedetection - Detect change in websites (link)

  changedetection:
    container_name: changedetection
    image: ghcr.io/dgtlmoon/changedetection.io
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - BASE_URL=https://change.tdehaeze.xyz
    volumes:
      - $CONFIGDIR/changedetection:/datastore
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.changedetection-rtr.entrypoints=web-secure"
      - "traefik.http.routers.changedetection-rtr.rule=Host(`change.$DOMAINNAME`)"
      - "traefik.http.routers.changedetection-rtr.tls=true"
      - "traefik.http.routers.changedetection-rtr.service=changedetection-svc"
      - "traefik.http.routers.changedetection-rtr.middlewares=authelia@docker"
      - "traefik.http.services.changedetection-svc.loadbalancer.server.port=5000"
    logging: *default-logging

WingAudio

wordpress

  wingaudio:
    container_name: wingaudio
    image: wordpress
    depends_on:
      - wingaudio_db
    restart: unless-stopped
    networks:
      - t2_proxy
      - backend
    volumes:
      - $CONFIGDIR/wingaudio:/var/www/html
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - WORDPRESS_DB_HOST=wingaudio_db
      - WORDPRESS_DB_USER=wingaudio
      - WORDPRESS_DB_PASSWORD=$WINGAUDIO_DB_MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wingaudio
    user: "${PUID}:${PGID}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wingaudio-rtr.entrypoints=web-secure"
      - "traefik.http.routers.wingaudio-rtr.rule=Host(`wingaudio.fr`)"
      - "traefik.http.routers.wingaudio-rtr.tls=true"
      - "traefik.http.routers.wingaudio-rtr.service=wingaudio-svc"
      - "traefik.http.services.wingaudio-svc.loadbalancer.server.port=80"
    logging: *default-logging
  wingaudio_db:
    container_name: wingaudio_db
    image: mysql:5.7
    restart: unless-stopped
    networks:
      - backend
    user: "${PUID}:${PGID}"
    environment:
      - MYSQL_DATABASE=wingaudio
      - MYSQL_USER=wingaudio
      - MYSQL_PASSWORD=$WINGAUDIO_DB_MYSQL_PASSWORD
      - MYSQL_RANDOM_ROOT_PASSWORD=$WINGAUDIO_DB_MYSQL_ROOT_PASSWORD
    volumes:
      - $CONFIGDIR/wingaudio_db:/var/lib/mysql
    logging: *default-logging

Multimedia

jellyfin - Media server (link)

  jellyfin:
    container_name: jellyfin
    image: linuxserver/jellyfin
    restart: unless-stopped
    networks:
      - t2_proxy
    volumes:
      - $CONFIGDIR/jellyfin:/config
      - /srv/storage/TVShows:/data/tvshows
      - /srv/storage/Documentaries:/data/documentaries
      - /srv/storage/LiveMusic:/data/livemusic
      - /srv/storage/Animes:/data/animes
      - /srv/storage/Movies:/data/movies
      - /srv/storage/Music:/data/music
      - /srv/storage/StandUp:/data/standup
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    group_add:
      - 109
    devices:
      # VAAPI Devices
      - /dev/dri/renderD128:/dev/dri/renderD128
      - /dev/dri/card0:/dev/dri/card0
    ports:
      - 8096:8096
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.jellyfin-rtr.entrypoints=web-secure"
      - "traefik.http.routers.jellyfin-rtr.rule=Host(`jellyfin.$DOMAINNAME`)"
      - "traefik.http.routers.jellyfin-rtr.tls=true"
      - "traefik.http.routers.jellyfin-rtr.service=jellyfin-svc"
      - "traefik.http.services.jellyfin-svc.loadbalancer.server.port=8096"
    logging: *default-logging

jfa-go - Manage Jellyfin Users (link)

  jfa:
    container_name: jfa
    image: hrfee/jfa-go
    restart: unless-stopped
    depends_on:
      - jellyfin
    networks:
      - t2_proxy
    volumes:
      - $CONFIGDIR/jfa:/data
      - $CONFIGDIR/jellyfin:/jf
      - /etc/localtime:/etc/localtime:ro
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.jfa-rtr.entrypoints=web-secure"
      - "traefik.http.routers.jfa-rtr.rule=Host(`jfa.$DOMAINNAME`)"
      - "traefik.http.routers.jfa-rtr.tls=true"
      - "traefik.http.routers.jfa-rtr.service=jfa-svc"
      - "traefik.http.services.jfa-svc.loadbalancer.server.port=8056"
    logging: *default-logging

Cloud

syncthing - File Synchronization (link)

  syncthing:
    container_name: syncthing
    image: linuxserver/syncthing
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - UMASK_SET=022
    volumes:
      - $CONFIGDIR/syncthing:/config
      - /srv/storage/Cloud:/Cloud
      - /srv/storage/Cloud/pictures/phone:/Pictures
      - /srv/storage/Cloud/pdfs:/Onyx/Download
      - /srv/storage/Cloud/pdfs-notes:/Onyx/note
      - /srv/storage/Cloud/.stfolder:/Onyx/.stfolder
      - /srv/storage/.password-store:/.password-store
    ports:
      - 22000:22000
      - 21027:21027/udp
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.syncthing-rtr.entrypoints=web-secure"
      - "traefik.http.routers.syncthing-rtr.rule=Host(`syncthing.$DOMAINNAME`)"
      - "traefik.http.routers.syncthing-rtr.tls=true"
      - "traefik.http.routers.syncthing-rtr.service=syncthing-svc"
      - "traefik.http.routers.syncthing-rtr.middlewares=authelia@docker"
      - "traefik.http.services.syncthing-svc.loadbalancer.server.port=8384"
    logging: *default-logging

sync-anne - File Synchronization (link)

  sync-anne:
    container_name: sync-anne
    image: linuxserver/syncthing
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - UMASK_SET=022
    volumes:
      - $CONFIGDIR/sync-anne:/config
      - /srv/storage/Users/anne:/Cloud
      - /srv/storage/Users/anne/Photos/telephone:/telephone
    ports:
      - 22001:22001
      - 21028:21028/udp
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.sync-anne-rtr.entrypoints=web-secure"
      - "traefik.http.routers.sync-anne-rtr.rule=Host(`sync-anne.$DOMAINNAME`)"
      - "traefik.http.routers.sync-anne-rtr.tls=true"
      - "traefik.http.routers.sync-anne-rtr.service=sync-anne-svc"
      - "traefik.http.routers.sync-anne-rtr.middlewares=authelia@docker"
      - "traefik.http.services.sync-anne-svc.loadbalancer.server.port=8384"
    logging: *default-logging

sync-jm - File Synchronization (link)

  sync-jm:
    container_name: sync-jm
    image: linuxserver/syncthing
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - UMASK_SET=022
    volumes:
      - $CONFIGDIR/sync-jm:/config
      - /srv/storage/Users/jean-marie:/Cloud
      # - /srv/storage/Users/jean-marie/Photos/telephone:/telephone
    ports:
      - 22002:22002
      - 21029:21029/udp
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.sync-jm-rtr.entrypoints=web-secure"
      - "traefik.http.routers.sync-jm-rtr.rule=Host(`sync-jm.$DOMAINNAME`)"
      - "traefik.http.routers.sync-jm-rtr.tls=true"
      - "traefik.http.routers.sync-jm-rtr.service=sync-jm-svc"
      - "traefik.http.routers.sync-jm-rtr.middlewares=authelia@docker"
      - "traefik.http.services.sync-jm-svc.loadbalancer.server.port=8384"
    logging: *default-logging

sync-ju - File Synchronization (link)

  sync-ju:
    container_name: sync-ju
    image: linuxserver/syncthing
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - UMASK_SET=022
    volumes:
      - $CONFIGDIR/sync-ju:/config
      - /srv/storage/Users/juliette:/Cloud
      - /srv/storage/Cloud/personnal:/Cloud/Thomas
    ports:
      - 22003:22003
      - 21030:21030/udp
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.sync-ju-rtr.entrypoints=web-secure"
      - "traefik.http.routers.sync-ju-rtr.rule=Host(`sync-ju.$DOMAINNAME`)"
      - "traefik.http.routers.sync-ju-rtr.tls=true"
      - "traefik.http.routers.sync-ju-rtr.service=sync-ju-svc"
      - "traefik.http.routers.sync-ju-rtr.middlewares=authelia@docker"
      - "traefik.http.services.sync-ju-svc.loadbalancer.server.port=8384"
    logging: *default-logging

filebrowser - Web file browser (link)

  filebrowser:
    container_name: filebrowser
    image: filebrowser/filebrowser
    restart: unless-stopped
    networks:
      - t2_proxy
    volumes:
      - $CONFIGDIR/filebrowser/database.db:/database.db
      - $CONFIGDIR/filebrowser/.filebrowser.json:/.filebrowser.json
      - /srv/storage:/srv/storage
    user: "${PUID}:${PGID}"
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.filebrowser-rtr.entrypoints=web-secure"
      - "traefik.http.routers.filebrowser-rtr.rule=Host(`cloud.$DOMAINNAME`)"
      - "traefik.http.routers.filebrowser-rtr.tls=true"
      - "traefik.http.routers.filebrowser-rtr.service=filebrowser-svc"
      - "traefik.http.services.filebrowser-svc.loadbalancer.server.port=80"
    logging: *default-logging

.filebrowser.json

{
  "port": 80,
  "baseURL": "",
  "address": "",
  "log": "stdout",
  "database": "/database.db",
  "root": "/srv/storage"
}

radicale - CalDAV/CardDAV server (link)

  radicale:
    container_name: radicale
    image: tomsquest/docker-radicale
    restart: unless-stopped
    networks:
      - t2_proxy
    volumes:
      - $CONFIGDIR/radicale/config:/config:ro
      - $CONFIGDIR/radicale/data:/data
    environment:
      - TZ=$TZ
      - UID=$PUID
      - GID=$PGID
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - SETUID
      - SETGID
      - CHOWN
      - KILL
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.radicale-rtr.entrypoints=web-secure"
      - "traefik.http.routers.radicale-rtr.rule=Host(`radicale.$DOMAINNAME`)"
      - "traefik.http.routers.radicale-rtr.tls=true"
      - "traefik.http.routers.radicale-rtr.service=radicale-svc"
      - "traefik.http.services.radicale-svc.loadbalancer.server.port=5232"
    logging: *default-logging

config

[server]
hosts = 0.0.0.0:5232

[auth]
type = htpasswd
htpasswd_filename = /config/users
htpasswd_encryption = md5

[storage]
filesystem_folder = /data/collections

linkding - Bookmark manager (link)

  linkding:
    container_name: linkding
    image: sissbruecker/linkding
    restart: unless-stopped
    networks:
      - t2_proxy
    volumes:
      - $CONFIGDIR/linkding:/etc/linkding/data
    user: "${PUID}:${PGID}"
    environment:
      - TZ=$TZ
      - PUID=$PUID
      - PGID=$PGID
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.linkding-rtr.entrypoints=web-secure"
      - "traefik.http.routers.linkding-rtr.rule=Host(`bm.$DOMAINNAME`)"
      - "traefik.http.routers.linkding-rtr.tls=true"
      - "traefik.http.routers.linkding-rtr.service=linkding-svc"
      - "traefik.http.services.linkding-svc.loadbalancer.server.port=9090"
    logging: *default-logging

restic-hc4 - Automatic backups on Odroid HC4 (link)

  restic-hc4:
    container_name: restic-hc4
    image: mazzolino/restic
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - BACKUP_CRON=0 14 * * * # Backup at 3am every day
      - RESTIC_REPOSITORY=sftp://thomas@pierrick.tdehaeze.xyz:10022//srv/storage/backup
      - RESTIC_PASSWORD=$RESTIC_PASSWORD
      - RESTIC_BACKUP_SOURCES=/source
      - RESTIC_FORGET_ARGS=--group-by tag --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
      - RESTIC_BACKUP_ARGS=--tag local --exclude-file /exclude.txt --verbose
      - RESTIC_GOTIFY_TOKEN=$RESTIC_GOTIFY_TOKEN
      - SUCCESS_ON_INCOMPLETE_BACKUP="true"
      - UID=$PUID
      - GID=$PGID
      - TZ=$TZ
      - POST_COMMANDS_FAILURE=curl "https://gotify.tdehaeze.xyz/message?token=$RESTIC_GOTIFY_TOKEN" -F "title=Restic HC4" -F "message=Backup failed" -F "priority=5"
      - POST_COMMANDS_EXIT=ssh -p 10022 thomas@pierrick.tdehaeze.xyz "sudo systemctl poweroff"
    volumes:
      - $CONFIGDIR/restic-hc4/exclude.txt:/exclude.txt:ro
      - /srv/storage/Users:/source/Users:ro # User Clouds
      - /srv/storage/Cloud:/source/Cloud:ro # My Own Cloud
      - /srv/storage/Music:/source/Music:ro # Musics
      - /home/thomas:/source/home:ro # Homelab - home directory
      - /home/thomas/.ssh/known_hosts:/root/.ssh/known_hosts:ro
      - /home/thomas/.ssh/id_rsa:/root/.ssh/id_rsa:ro
    logging: *default-logging

exclude.txt - Exclude files

*.db
*.log
*.log.*

miniflux - RSS reader (link)

  miniflux:
    container_name: miniflux
    image: miniflux/miniflux
    restart: unless-stopped
    networks:
      - t2_proxy
      - backend
    depends_on:
      - miniflux_db
    environment:
      - DATABASE_URL=postgres://miniflux:SCJWWXqHwehP7f8g@miniflux_db/miniflux?sslmode=disable
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=$MINIFLUX_ADMIN_NAME
      - ADMIN_PASSWORD=$MINIFLUX_ADMIN_PASS
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.miniflux-rtr.entrypoints=web-secure"
      - "traefik.http.routers.miniflux-rtr.rule=Host(`rss.$DOMAINNAME`)"
      - "traefik.http.routers.miniflux-rtr.tls=true"
      - "traefik.http.routers.miniflux-rtr.service=miniflux-svc"
      - "traefik.http.services.miniflux-svc.loadbalancer.server.port=8080"
    logging: *default-logging
  miniflux_db:
    container_name: miniflux_db
    image: postgres:12
    restart: unless-stopped
    networks:
      - backend
    user: "${PUID}:${PGID}"
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=$MINIFLUX_POSTGRES_PASSWORD
    volumes:
      - $CONFIGDIR/miniflux_db:/var/lib/postgresql/data
    logging: *default-logging

Home

mosquitto - MQTT broker (link)

  mosquitto:
    container_name: mosquitto
    image: eclipse-mosquitto
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - UID=$PUID
      - GID=$PGID
      - TZ=$TZ
    expose:
      - 1883
      - 9001
    ports:
      - 1883:1883
      - 9001:9001
    volumes:
      - $CONFIGDIR/mosquitto/config:/mosquitto/config
      - $CONFIGDIR/mosquitto/log:/mosquitto/log
      - $CONFIGDIR/mosquitto/data:/mosquitto/data
    logging: *default-logging

zigbee2mqtt - Zigbee to MQTT bridge (link)

In /etc/udev/rules.d/99-usb-serial.rules:

SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", SYMLINK+="zigbee/slaesh"
  zigbee2mqtt:
    container_name: zigbee2mqtt
    image: koenkk/zigbee2mqtt
    restart: unless-stopped
    privileged: true
    depends_on:
      - mosquitto
    networks:
      - t2_proxy
    environment:
      - UID=$PUID
      - GID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/zigbee2mqtt:/app/data
      - /run/udev:/run/udev:ro
      - /dev/zigbee:/dev/zigbee:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.zigbee2mqtt-rtr.entrypoints=web-secure"
      - "traefik.http.routers.zigbee2mqtt-rtr.rule=Host(`zigbee2mqtt.$DOMAINNAME`)"
      - "traefik.http.routers.zigbee2mqtt-rtr.tls=true"
      - "traefik.http.routers.zigbee2mqtt-rtr.service=zigbee2mqtt-svc"
      - "traefik.http.routers.zigbee2mqtt-rtr.middlewares=authelia@docker"
      - "traefik.http.services.zigbee2mqtt-svc.loadbalancer.server.port=8080"
    logging: *default-logging

node-red - Automation tool

  node-red:
    container_name: node-red
    image: nodered/node-red
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/node-red:/data
    ports:
      - 1880:1880
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.node-red-rtr.entrypoints=web-secure"
      - "traefik.http.routers.node-red-rtr.rule=Host(`node-red.$DOMAINNAME`)"
      - "traefik.http.routers.node-red-rtr.tls=true"
      - "traefik.http.routers.node-red-rtr.service=node-red-svc"
      - "traefik.http.routers.node-red-rtr.middlewares=authelia@docker"
      - "traefik.http.services.node-red-svc.loadbalancer.server.port=1880"
    logging: *default-logging

esphome - Automation tool

  esphome:
    container_name: esphome
    image: esphome/esphome
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - ESPHOME_DASHBOARD_USE_PING=true
    volumes:
      - $CONFIGDIR/esphome:/config
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.esphome-rtr.entrypoints=web-secure"
      - "traefik.http.routers.esphome-rtr.rule=Host(`esphome.$DOMAINNAME`)"
      - "traefik.http.routers.esphome-rtr.tls=true"
      - "traefik.http.routers.esphome-rtr.service=esphome-svc"
      - "traefik.http.routers.esphome-rtr.middlewares=authelia@docker"
      - "traefik.http.services.esphome-svc.loadbalancer.server.port=6052"
    logging: *default-logging

tina2 - Web interface for 3D printing (link)

In order for the 3D printer to always have the same /dev/path, sudoedit /etc/udev/rules.d/99-usb-serial.rules:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="3d-printer/tina2"
  tina2:
    container_name: tina2
    image: octoprint/octoprint
    restart: unless-stopped
    privileged: true
    networks:
      - t2_proxy
    environment:
      - UID=$PUID
      - GID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/tina2:/octoprint
      - /run/udev:/run/udev:ro
      - /dev/3d-printer:/dev/3d-printer:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.tina2-rtr.entrypoints=web-secure"
      - "traefik.http.routers.tina2-rtr.rule=Host(`3d-printer.$DOMAINNAME`)"
      - "traefik.http.routers.tina2-rtr.tls=true"
      - "traefik.http.routers.tina2-rtr.service=tina2-svc"
      - "traefik.http.services.tina2-svc.loadbalancer.server.port=80"
    logging: *default-logging

Photo - Immich

immich-proxy

  immich-proxy:
    container_name: immich-proxy
    image: ghcr.io/immich-app/immich-proxy:release
    restart: unless-stopped
    networks:
      - t2_proxy
      - immich
    environment:
      # Make sure these values get passed through from the env file
      - IMMICH_SERVER_URL
      - IMMICH_WEB_URL
    depends_on:
      - immich-server
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.immich-rtr.entrypoints=web-secure"
      - "traefik.http.routers.immich-rtr.rule=Host(`immich.$DOMAINNAME`)"
      - "traefik.http.routers.immich-rtr.tls=true"
      - "traefik.http.routers.immich-rtr.service=immich-svc"
      - "traefik.http.services.immich-svc.loadbalancer.server.port=8080"
    logging: *default-logging

immich-server

  immich-server:
    container_name: immich-server
    image: ghcr.io/immich-app/immich-server:release
    restart: unless-stopped
    entrypoint: ["/bin/sh", "./start-server.sh"]
    networks:
      - immich
    volumes:
      - /srv/storage/immich:/usr/src/app/upload
    env_file:
      - immich.env
    depends_on:
      - immich-redis
      - immich-database
      - immich-typesense
    logging: *default-logging

immich-microservices

  immich-microservices:
    container_name: immich-microservices
    image: ghcr.io/immich-app/immich-server:release
    restart: unless-stopped
    command: ["start.sh", "microservices"]
    networks:
      - immich
    volumes:
      - /srv/storage/immich:/usr/src/app/upload
    env_file:
      - immich.env
    depends_on:
      - immich-redis
      - immich-database
      - immich-typesense
    logging: *default-logging

immich-machine-learning

  immich-machine-learning:
    container_name: immich-machine-learning
    image: ghcr.io/immich-app/immich-machine-learning:release
    restart: unless-stopped
    networks:
      - immich
    volumes:
      - /srv/storage/immich:/usr/src/app/upload
      - $CONFIGDIR/immich/machine-learning-cache:/cache
    env_file:
      - immich.env
    logging: *default-logging

immich-web

  immich-web:
    container_name: immich-web
    image: ghcr.io/immich-app/immich-web:release
    restart: unless-stopped
    networks:
      - immich
    env_file:
      - immich.env
    logging: *default-logging

immich-typesense

  immich-typesense:
    container_name: immich-typesense
    image: typesense/typesense:0.24.1@sha256:9bcff2b829f12074426ca044b56160ca9d777a0c488303469143dd9f8259d4dd
    restart: unless-stopped
    networks:
      - immich
    env_file:
      - immich.env
    environment:
      - TYPESENSE_DATA_DIR=/data
    volumes:
      - $CONFIGDIR/immich/typesense-data:/data
    logging: *default-logging

immich-redis

  immich-redis:
    container_name: immich-redis
    image: redis:6.2-alpine@sha256:70a7a5b641117670beae0d80658430853896b5ef269ccf00d1827427e3263fa3

    restart: unless-stopped
    networks:
      - immich
    logging: *default-logging

immich-database

  immich-database:
    container_name: immich-database
    image: postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441
    restart: unless-stopped
    networks:
      - immich
    env_file:
      - immich.env
    environment:
      - POSTGRES_PASSWORD=$${DB_PASSWORD}
      - POSTGRES_USER=$${DB_USERNAME}
      - POSTGRES_DB=$${DB_DATABASE_NAME}
      - PG_DATA=/var/lib/postgresql/data
    volumes:
      - $CONFIGDIR/immich/postgresql-data:/var/lib/postgresql/data
    logging: *default-logging

immich.env

###################################################################################
# Database
###################################################################################

DB_HOSTNAME=immich-database
DB_USERNAME=postgres
DB_PASSWORD=aC2fdTEHiRcrb0U5
DB_DATABASE_NAME=immich

# Optional Database settings:
# DB_PORT=5432

###################################################################################
# Redis
###################################################################################

REDIS_HOSTNAME=immich-redis

###################################################################################
# Log message level - [simple|verbose]
###################################################################################

LOG_LEVEL=simple

###################################################################################
# Typesense
###################################################################################
TYPESENSE_ENABLED=true
TYPESENSE_API_KEY=I7kSTDznqhmIcjPB
TYPESENSE_HOST=immich-typesense
# TYPESENSE_PORT: 8108
# TYPESENSE_PROTOCOL: http

####################################################################################
# Alternative Service Addresses - Optional
#
# This is an advanced feature for users who may be running their immich services on different hosts.
# It will not change which address or port that services bind to within their containers, but it will change where other services look for their peers.
# Note: immich-microservices is bound to 3002, but no references are made
####################################################################################

IMMICH_WEB_URL=http://immich-web:3000
IMMICH_SERVER_URL=http://immich-server:3001
IMMICH_MACHINE_LEARNING_URL=http://immich-machine-learning:3003

####################################################################################
# Alternative API's External Address - Optional
#
# This is an advanced feature used to control the public server endpoint returned to clients during Well-known discovery.
# You should only use this if you want mobile apps to access the immich API over a custom URL. Do not include trailing slash.
# NOTE: At this time, the web app will not be affected by this setting and will continue to use the relative path: /api
# Examples: http://localhost:3001, http://immich-api.example.com, etc
####################################################################################

#IMMICH_API_URL_EXTERNAL=http://localhost:3001

Download

transmission-openvpn - Torrent server (link)

  transmission:
    container_name: transmission
    image: haugene/transmission-openvpn
    cap_add:
      - NET_ADMIN
    networks:
      - t2_proxy
    sysctls:
      - net.ipv6.conf.all.disable_ipv6=0
    restart: unless-stopped
    ports:
      - 9091:9091
    dns:
      - 8.8.8.8
      - 8.8.4.4
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - $CONFIGDIR/transmission:/config
      - /srv/storage/Downloads:/data
      - /srv/storage/Downloads/watch:/watch
    environment:
      - CREATE_TUN_DEVICE=true
      - PUID=$PUID
      - PGID=$PGID
      - TRANSMISSION_WEB_UI=flood-for-transmission
      - LOCAL_NETWORK=192.168.0.0/16
      - OPENVPN_PROVIDER=NORDVPN
      - OPENVPN_USERNAME=$NORDVPN_NAME
      - OPENVPN_PASSWORD=$NORDVPN_PASS
      - NORDVPN_COUNTRY=FR
      - NORDVPN_CATEGORY=legacy_p2p
      - NORDVPN_PROTOCOL=udp
      - TRANSMISSION_UTP_ENABLED=false
      - TRANSMISSION_RPC_AUTHENTICATION_REQUIRED=true
      - TRANSMISSION_RPC_USERNAME=$TRANSMISSION_NAME
      - TRANSMISSION_RPC_PASSWORD=$TRANSMISSION_PASS
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=t2_proxy"
      - "traefik.http.routers.transmission-rtr.entrypoints=web-secure"
      - "traefik.http.routers.transmission-rtr.rule=Host(`torrent.$DOMAINNAME`)"
      - "traefik.http.routers.transmission-rtr.tls=true"
      - "traefik.http.routers.transmission-rtr.service=transmission-svc"
      - "traefik.http.services.transmission-svc.loadbalancer.server.port=9091"
    logging: *default-logging

TODO Matrix

Basic Config

matrix_domain: tdehaeze.xyz
matrix_ssl_lets_encrypt_support_email: 'dehaeze.thomas@gmail.com'
matrix_coturn_turn_static_auth_secret: 'nxSdNOonPYXHmpog8j6dC1EciAmdYPNgpre1SZw1yc8VybtJcAQrzArVLAjzDR2z'
matrix_synapse_macaroon_secret_key: 'exz3Wv7eWBDGYpnp5x3o3qGg6oalG04teu2eNlzMv6H7HxhW5U8Dr1HXZhMHafhl'
matrix_postgres_connection_password: '4WmtV4utoNMKMOY1TxfJ9EsgCV8dTIV8hyB8YrCpZqd33bsursGKEP6BA1gY4YZJ'
matrix_client_element_enabled: false
matrix_homeserver_generic_secret_key: "{{ matrix_synapse_macaroon_secret_key }}"
# =================================================================================================
# Setting up the Shared Secret Auth password provider module
matrix_synapse_ext_password_provider_shared_secret_auth_enabled: true
matrix_synapse_ext_password_provider_shared_secret_auth_shared_secret: Ru1kRNNyj8k7cVx2q2aAZCZL3R3Ph79Pq762W17CfExhmnAfxb9BI7zOktsBK32O

Use Traefik as reverse proxy

# =================================================================================================
# Disable Nginx and use Traefik instead
# =================================================================================================

# Disable generation and retrieval of SSL certs
matrix_ssl_retrieval_method: none

# Configure Nginx to only use plain HTTP
matrix_nginx_proxy_https_enabled: false

# Don't bind any HTTP or federation port to the host
# (Traefik will proxy directly into the containers)
matrix_nginx_proxy_container_http_host_bind_port: ''
matrix_nginx_proxy_container_federation_host_bind_port: ''

# Disable Coturn because it needs SSL certs
# (Clients can, though exposing IP address, use Matrix.org TURN)
matrix_coturn_enabled: false

# All containers need to be on the same Docker network as Traefik
# (This network should already exist and Traefik should be using this network)
matrix_docker_network: 't2_proxy'

matrix_nginx_proxy_container_extra_arguments:
  - '--label "traefik.enable=true"'
  - '--label "traefik.http.routers.matrix-nginx-proxy.entrypoints=https"'
  - '--label "traefik.http.routers.matrix-nginx-proxy.rule=Host(`{{ matrix_server_fqn_matrix }}`,`{{ matrix_server_fqn_element }}`,`{{ matrix_server_fqn_dimension }}`,`{{ matrix_server_fqn_jitsi }}`)"'
  - '--label "traefik.http.routers.matrix-nginx-proxy.tls=true"'
  - '--label "traefik.http.services.matrix-nginx-proxy.loadbalancer.server.port=8080"'
  # - '--label "traefik.http.routers.matrix-nginx-proxy.middlewares=matrix-regex"'
  # - '--label "traefik.http.middlewares.matrix-regex.redirectregex.regex=https://matrix.tdehaeze.xyz/.well-known/matrix/(client|server)"'
  # - '--label "traefik.http.middlewares.matrix-regex.redirectregex.replacement=https://matrix.tdehaeze.xyz/"'

matrix_synapse_container_extra_arguments:
  - '--label "traefik.enable=true"'
  - '--label "traefik.http.routers.matrix-synapse.entrypoints=synapse"'
  - '--label "traefik.http.routers.matrix-synapse.rule=Host(`{{ matrix_server_fqn_matrix }}`)"'
  - '--label "traefik.http.routers.matrix-synapse.tls=true"'
  - '--label "traefik.http.routers.matrix-synapse.service=matrix-synapse"'
  - '--label "traefik.http.services.matrix-synapse.loadbalancer.server.port=8048"'

Bridges

Slack

# Slack
matrix_mx_puppet_slack_enabled: true
matrix_mx_puppet_slack_client_id: "299050134212.1969032215654"
matrix_mx_puppet_slack_client_secret: "9a3240e570997645d4961d3cb595e798"

WhatsApp

# WhatsApp
matrix_mautrix_whatsapp_enabled: true

Signal

# Signal
matrix_mautrix_signal_enabled: true

Facebook

# Facebook
matrix_mautrix_facebook_enabled: true

Telegram

# Telegram
matrix_mautrix_telegram_enabled: true
matrix_mautrix_telegram_api_id: 5596434
matrix_mautrix_telegram_api_hash: 29d6742e35799b88b9a7b5a46fe05ff2

Backup server

Hardware

Install

Install MicroSD

First boot

Choose "Exit to shell" (switch to console then)

(back to petiboot menu)

Setup SSH and Drive

  • create thomas user
  • add user to sudo group
  • add SSH key (use ssh-copy-id)
  • disable root ssh and password authentication
  • format disk drive
  • edit /etc/fstab to add the disk drive and mount it to /srv/storage.

Install packages

sudo apt install neovim tmux fd-find ripgrep fzf apache2-utils unrar ranger man git

Poweroff without sudo

add the following at the end of /etc/sudoers:

thomas backup =NOPASSWD: /usr/bin/systemctl poweroff,/usr/bin/systemctl halt,/usr/bin/systemctl reboot

Cron Jobs

Caddy Update

Create a script ~/cron/caddy_update.sh with:

docker exec caddy /bin/sh -c "cd /srv/www && echo -e \"Update repo $(date)\" && git submodule update --recursive --remote --merge"

Type crontab -e and add this line:

*/5 * * * * /home/thomas/cron/caddy_update.sh >> /home/thomas/cron/caddy_update.log 2>&1

Back OpenWRT Config

Create a script ~/cron/backup_openwrt_conf.sh with:

ssh root@192.168.1.1 "umask go=; sysupgrade -b /tmp/backup-${HOSTNAME}-$(date +%F).tar.gz" && \
    scp root@192.168.1.1:/tmp/backup-*.tar.gz /srv/storage/Backups/openWRT/

Type crontab -e and add this line:

*/5 * * * * /home/thomas/cron/backup_openwrt_conf.sh >> /home/thomas/cron/backup_openwrt_conf.log 2>&1