83 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	Home Server
- Hardware
 - Installation
- Ubuntu
 - Install Important software
 - Terminal Problem
 - Minor Modifications of 
~/.inputrc - Partition and Format Disk Drives
 - MergerFS and FStab
 - Automating with SnapRAID Runner
 - Install Docker
 - Executing the Docker Command Without Sudo
 - Install Docker-Compose
 - Setup Docker Networks
 - Change Timezone
 - Secure the Web Server
 - Automatic Security Updates
 - Setup cronjobs
 - Run 
docker-compose - Docker config 
~/.docker/config.json 
 - Maintenance - How To
 - Docker-Compose
- Networks
 - Logging
 traefik- Application proxy (link)authelia- Single Sign-On Multi-Factor portal (link)lldap- LDAP Server (link)gotify- Notification service (link)nginx- Root (used for Matrix)homer- Home page (link)linkding- Bookmark manager (link)snapraid- Manage local backup with parity disk (link)portainer- Manage docker (link)wireguard- VPN (link)gluetun- Provide VPN connection to other containers (link)transmission- Torrent client (link)gitea- Git server (link)wikijs- Wiki App (link)research- Research Pages (link)dotfiles- Dotfiles (link)hugo- Wiki + Blog (link)syncthing- File Synchronization (link)miniflux- RSS reader (link)homeassistant- Home Automation (link)jellyfin- Media server (link)jfa-go- Manage Jellyfin Users (link)audioserve- Audiobook server (link)filebrowser- Web file browser (link)scrutiny- Hard drive monitoring (link)radicale- CalDAV/CardDAV server (link)restic- Automatic online backups (link)octoprint- Web interface for 3D printing (link)mealie- Recipe Manager (link)diun- Notification for Docker image updates (link)commento- Commenting system (link)uptime-kuma- Monitoring Tool (link)kavita- Reading server (link)mosquitto- MQTT broker (link)zigbee2mqtt- Zigbee to MQTT bridge (link)zigbee2mqttassistant- GUI for Zigbee2Mqtt (link)
 - Cron Jobs
 
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 | 
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
Automating with SnapRAID Runner
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 
PasswordAuthenticationno 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.
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'
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
snapraid
To see all files "backed up" by snapraid, use:
docker exec -ti snapraid snapraid list | fzf
In reality, snapraid is ran from the docker container:
docker exec -ti snapraid snapraid fix -f <path_to_file>
The path to file should be relative: /srv/storage/Cloud/org/file.org -> Cloud/org/file.org
Restore Online backup with restic
To list backups:
docker exec restic restic snapshots
ID Time Host Tags Paths -------------------------------------------------------------------------------- a7b98408 2020-09-03 21:18:00 4803c2af7d4e /data/documents/manuals 088e31a4 2020-09-03 21:50:26 4803c2af7d4e /data/documents/manuals 9cf0b480 2020-09-03 22:05:47 4803c2af7d4e /data/documents/manuals -------------------------------------------------------------------------------- 3 snapshots
Force backup of folder:
docker exec restic restic backup /data/documents/manuals
Files: 0 new, 2 changed, 8475 unmodified Dirs: 0 new, 2 changed, 0 unmodified Added to the repo: 1.010 KiB processed 8477 files, 589.800 MiB in 0:02 snapshot 9cf0b480 saved
Find the path to the file within the snapshot:
docker exec restic restic find file_name
Find files only for a specific snapshot:
docker exec restic restic find -s latest file_name
Restore files/folders (replace file/folders):
docker exec restic restic restore --include /data/documents/manuals --target / 088e31a4
You can use latest instead of the ID.
If indeed, we want to make a copy of the file, we can use the backup folder
docker exec restic restic restore --include /data/documents/manuals --target /backup 088e31a4
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.confsudo chown root:root /etc/wireguard/interfacename.conf
Then, start the tunnel with:
wg-quick up interfacename
Docker-Compose
version: "3.4"
Networks
networks:
  t2_proxy:
    external:
      name: t2_proxy
  backend:
    external: false
  default:
    driver: bridge
Logging
x-logging:
  &default-logging
  driver: "json-file"
  options:
    max-size: "200k"
    max-file: "10"
traefik - Application proxy (link)
services:
  traefik:
    container_name: traefik
    image: traefik:2.2.1
    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/rules:/rules
      - $CONFIGDIR/traefik2/acme/acme.json:/acme.json
      - $CONFIGDIR/traefik2/shared:/shared
      - $CONFIGDIR/traefik2/traefik.yaml:/etc/traefik/traefik.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=http"
      - "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=https"
      - "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.domains[0].main=$DOMAINNAME"
      - "traefik.http.routers.traefik-rtr.tls.domains[0].sans=*.$DOMAINNAME"
      - "traefik.http.services.traefik-svc.loadbalancer.server.port=8080"
      # Services - API
      - "traefik.http.routers.traefik-rtr.service=api@internal"
    logging: *default-logging
traefik.yaml
global:
  checkNewVersion: true
  sendAnonymousUsage: false
entryPoints:
  http:
    address: :80
  https:
    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
  synapse:
    address: :8448
api:
  dashboard: true
log:
  level: ERROR
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:
    directory: /rules
    watch: true
certificatesResolvers:
  dns-cloudflare:
    acme:
      email: $CLOUDFLARE_EMAIL
      storage: /acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers: 1.1.1.1:53,1.0.0.1:53
authelia - Single Sign-On Multi-Factor portal (link)
  authelia:
    image: authelia/authelia:4.30
    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=$AUTHELIA_NOTIFIER_SMTP_PASSWORD
      - AUTHELIA_JWT_SECRET=$AUTHELIA_JWT_SECRET
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.authelia-rtr.entrypoints=https"
      - "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: traefik.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: zigbee2mqttassistant.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: scrutiny.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: portainer.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: syncthing.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: octoprint.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: uptime.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: joal.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
    - domain: down.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
      - ["group:friends"]
      - ["group:family"]
    - domain: qobuz.tdehaeze.xyz
      policy: bypass
      resources:
      - "^/download([/?].*)?$"
    - domain: qobuz.tdehaeze.xyz
      policy: one_factor
      subject:
      - ["group:admins"]
      - ["group:friends"]
      - ["group:family"]
session:
  name: authelia_session
  expiration: 3600
  inactivity: 300
  domain: tdehaeze.xyz
regulation:
  max_retries: 3
  find_time: 120
  ban_time: 300
storage:
  local:
    path: /config/db.sqlite3
notifier:
  smtp:
    username: tdehaeze.xyz@gmail.com
    host: smtp.gmail.com
    port: 587
    sender: tdehaeze.xyz@gmail.com
TODO
[C]
lldap - LDAP Server (link)
  lldap:
    image: nitnelave/lldap
    container_name: lldap
    restart: unless-stopped
    networks:
      - t2_proxy
      - backend
    ports:
      - 3890:3890
    volumes:
      - $CONFIGDIR/lldap:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.lldap-rtr.entrypoints=https"
      - "traefik.http.routers.lldap-rtr.rule=Host(`lldap.$DOMAINNAME`)"
      - "traefik.http.routers.lldap-rtr.tls=true"
      - "traefik.http.routers.lldap-rtr.service=lldap-svc"
      - "traefik.http.routers.lldap-rtr.middlewares=authelia@docker"
      - "traefik.http.services.lldap-svc.loadbalancer.server.port=17170"
    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=https"
      - "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"
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=https"
      - "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;
        }
    }
}
homer - Home page (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=https"
      - "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: "Wiki"
      logo: "/assets/tools/wikijs.png"
      subtitle: "Shared Wiki"
      url: "https://wiki.tdehaeze.xyz"
    - name: "Research"
      logo: "/assets/tools/orgmode.png"
      subtitle: "Research Pages"
      url: "https://research.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: "Multimedia"
    icon: "fas fa-photo-video"
    items:
    - name: "Jellyfin"
      logo: "/assets/tools/jellyfin.png"
      subtitle: "Media Library"
      url: "https://jellyfin.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: "File Browser"
      logo: "/assets/tools/cloud.png"
      subtitle: "Simple Personnal Could"
      url: "https://cloud.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: "Miniflux"
      logo: "/assets/tools/miniflux.png"
      subtitle: "RSS Feeds"
      url: "https://rss.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: "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: "Transmission"
      logo: "/assets/tools/transmission.png"
      subtitle: "Torrent Client"
      url: "http://torrent.tdehaeze.xyz:9091/transmission/web/"
    - name: "Joal"
      logo: "/assets/tools/joal.png"
      subtitle: "Increase Ratio"
      url: "https://joal.tdehaeze.xyz/joal/ui/#/"
  - 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: "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: "http://192.168.1.1/"
    - name: "Home Assistant"
      logo: "/assets/tools/homeassistant.png"
      subtitle: "Home Assistant"
      url: "http://home.tdehaeze.xyz:8123"
    - name: "Zigbee2MQTT"
      logo: "/assets/tools/zigbee2mqtt.png"
      subtitle: "Zigbee2MQTT Assistant"
      url: "https://zigbee2mqttassistant.tdehaeze.xyz/"
    - name: "OctoPrint"
      logo: "/assets/tools/octoprint.png"
      subtitle: "3D-Printing"
      url: "https://octoprint.tdehaeze.xyz/"
linkding - Bookmark manager (link)
  linkding:
    container_name: linkding
    image: sissbruecker/linkding:latest
    restart: unless-stopped
    networks:
      - t2_proxy
    volumes:
      - $CONFIGDIR/linkding:/etc/linkding/data
    environment:
      - TZ=$TZ
      - PUID=$PUID
      - PGID=$PGID
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.linkding-rtr.entrypoints=https"
      - "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
snapraid - Manage local backup with parity disk (link)
  snapraid:
    container_name: snapraid
    image: xagaba/snapraid
    restart: unless-stopped
    privileged: true
    volumes:
      - /mnt:/mnt
      - $CONFIGDIR/snapraid:/config
      - type: "bind"
        source: /dev/disk
        target: /dev/disk
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    logging: *default-logging
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 d0 /mnt/disk0
disk d1 /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 *.unrecoverable
exclude /tmp/
exclude /lost+found/
exclude *.!sync
exclude .AppleDouble
exclude ._AppleDouble
exclude .DS_Store
exclude ._.DS_Store
exclude .Thumbs.db
exclude .fseventsd
exclude .Spotlight-V100
exclude .TemporaryItems
exclude .Trashes
exclude .AppleDB
snapraid-runner.conf
[snapraid]
; path to the snapraid executable (e.g. /bin/snapraid)
executable = /usr/bin/snapraid
; path to the snapraid config to be used
config = /config/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 = false
[logging]
; logfile to write to, leave empty to disable
file = /config/snapraid.log
; maximum logfile size in KiB, leave empty for infinite
maxsize = 5000
; [email]
; ; when to send an email, comma-separated list of [success, error]
; sendon = success,error
; ; set to false to get full programm output via email
; short = true
; subject = [SnapRAID] Status Report:
; from =
; to =
; ; maximum email size in KiB
; maxsize = 500
;
; [smtp]
; host =
; ; leave empty for default port
; port =
; ; set to "true" to activate
; ssl = false
; tls = false
; user =
; password =
[scrub]
; set to true to run scrub after sync
enabled = false
percentage = 12
older-than = 10
portainer - Manage docker (link)
  portainer:
    container_name: portainer
    image: portainer/portainer
    restart: unless-stopped
    command: -H unix:///var/run/docker.sock
    command: --no-auth
    networks:
      - t2_proxy
    security_opt:
      - no-new-privileges:true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - $CONFIGDIR/portainer:/data
    environment:
      - TZ=$TZ
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.portainer-rtr.entrypoints=https"
      - "traefik.http.routers.portainer-rtr.rule=Host(`portainer.$DOMAINNAME`)"
      - "traefik.http.routers.portainer-rtr.tls=true"
      - "traefik.http.routers.portainer-rtr.service=portainer-svc"
      - "traefik.http.routers.portainer-rtr.middlewares=authelia@docker"
      - "traefik.http.services.portainer-svc.loadbalancer.server.port=9000"
    logging: *default-logging
wireguard - VPN (link)
  wireguard:
    container_name: wireguard
    image: linuxserver/wireguard
    restart: unless-stopped
    networks:
      - t2_proxy
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - SERVERURL=wireguard.tdehaeze.xyz
      - SERVERPORT=51820
      - PEERS=3
      - PEERDNS=auto
    volumes:
      - $CONFIGDIR/wireguard:/config
      - /lib/modules:/lib/modules
    ports:
      - 51820:51820/udp
    logging: *default-logging
gluetun - Provide VPN connection to other containers (link)
  gluetun:
    image: qmcgaw/gluetun
    container_name: gluetun
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
    network_mode: bridge
    ports:
      - 8065:8065 # For transmission
      - 9091:9091 # For transmission
      - 51413:51413 # For transmission
      - 51413:51413/udp # For transmission
    environment:
      - OPENVPN_USER=$NORDVPN_NAME
      - OPENVPN_PASSWORD=$NORDVPN_PASS
      - VPNSP=nordvpn
      - REGION=France
      - SERVER_NUMBER=776
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/gluetun:/config
transmission - Torrent client (link)
  transmission:
    container_name: transmission
    image: ghcr.io/linuxserver/transmission
    restart: unless-stopped
    network_mode: container:gluetun
    depends_on:
      - gluetun
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - USER=$TRANSMISSION_NAME
      - PASS=$TRANSMISSION_PASS
    volumes:
      - $CONFIGDIR/transmission:/config
      - /srv/storage/Downloads:/downloads
      - /srv/storage/Downloads/watch:/watch
    logging: *default-logging
gitea - Git server (link)
  gitea:
    container_name: git
    image: gitea/gitea:1.13.2
    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=https"
      - "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
    environment:
      - MYSQL_ROOT_PASSWORD=$GITEA_DB_MYSQL_ROOT_PASSWORD
      - MYSQL_DATABASE=gitea
      - MYSQL_USER=gitea
      - MYSQL_PASSWORD=$GITEA_DB_MYSQL_PASSWORD
    volumes:
      - $CONFIGDIR/mariadb:/var/lib/mysql
wikijs - Wiki App (link)
  wikijs:
    image: ghcr.io/linuxserver/wikijs:version-2.5.201
    container_name: wikijs
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/wikijs/config:/config
      - $CONFIGDIR/wikijs/data:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wikijs-rtr.entrypoints=https"
      - "traefik.http.routers.wikijs-rtr.rule=Host(`wiki.$DOMAINNAME`)"
      - "traefik.http.routers.wikijs-rtr.tls=true"
      - "traefik.http.routers.wikijs-rtr.service=wikijs-svc"
      - "traefik.http.services.wikijs-svc.loadbalancer.server.port=3000"
    logging: *default-logging
research - Research Pages (link)
  caddy:
    container_name: caddy
    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/caddy/Caddyfile:/etc/Caddyfile
      - $CONFIGDIR/web:/srv
        # - ~/.ssh:/root/.ssh
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.caddy-rtr.entrypoints=https"
      - "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
    }
}
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=https"
      - "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
    }
}
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=https"
      - "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
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=https"
      - "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
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=https"
      - "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
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=$MINIFLUX_POSTGRES_PASSWORD
    volumes:
      - $CONFIGDIR/miniflux_db:/var/lib/postgresql/data
    logging: *default-logging
homeassistant - Home Automation (link)
  homeassistant:
    container_name: homeassistant
    image: homeassistant/home-assistant
    restart: unless-stopped
    #networks:
    #  - t2_proxy
    #ports:
    #  - target: 8123
    #    published: 8123
    #    protocol: tcp
    #    mode: host
    privileged: true
    ports:
      - 8123:8123
    # network_mode: host
    volumes:
      - $CONFIGDIR/homeassistant:/config
      - /etc/localtime:/etc/localtime:ro
      - /dev/bus/usb:/dev/bus/usb
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.homeassistant-rtr.entrypoints=https"
      - "traefik.http.routers.homeassistant-rtr.rule=Host(`home.$DOMAINNAME`)"
      - "traefik.http.routers.homeassistant-rtr.tls=true"
      - "traefik.http.routers.homeassistant-rtr.service=homeassistant-svc"
      - "traefik.http.services.homeassistant-svc.loadbalancer.server.port=8123"
      # - "traefik.http.services.homeassistant-svc.loadbalancer.servers.url=http://172.17.0.1:8123"
    logging: *default-logging
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:
    #   - 122
    # 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=https"
      - "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=https"
      - "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
audioserve - Audiobook server (link)
  audioserve:
    container_name: audioserve
    image: izderadicka/audioserve
    restart: unless-stopped
    command: /audiobooks
    networks:
      - t2_proxy
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - AUDIOSERVE_SHARED_SECRET=$AUDIOSERVE_SHARED_SECRET
    volumes:
      - /srv/storage/AudioBooks:/audiobooks
      - /etc/localtime:/etc/localtime:ro
      - $CONFIGDIR/audioserve:/home/audioserve/.audioserve
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.audioserve-rtr.entrypoints=https"
      - "traefik.http.routers.audioserve-rtr.rule=Host(`audiobook.$DOMAINNAME`)"
      - "traefik.http.routers.audioserve-rtr.tls=true"
      - "traefik.http.routers.audioserve-rtr.service=audioserve-svc"
      - "traefik.http.services.audioserve-svc.loadbalancer.server.port=3000"
    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=https"
      - "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"
}
scrutiny - Hard drive monitoring (link)
  scrutiny:
    container_name: scrutiny
    image: linuxserver/scrutiny
    restart: unless-stopped
    networks:
      - t2_proxy
    cap_add:
      - SYS_RAWIO
      - SYS_ADMIN
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
      - SCRUTINY_WEB=true
      - SCRUTINY_COLLECTOR=false
    volumes:
      - $CONFIGDIR/scrutiny:/config
      - /run/udev:/run/udev:ro
    devices:
      - /dev/sda:/dev/sda
      - /dev/sdb:/dev/sdb
      - /dev/sdc:/dev/sdc
      - /dev/sdd:/dev/sdd
      - /dev/nvme0n1:/dev/nvme0n1
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.scrutiny-rtr.entrypoints=https"
      - "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
radicale - CalDAV/CardDAV server (link)
  radicale:
    container_name: radicale
    image: tomsquest/docker-radicale:latest
    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=https"
      - "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
restic - Automatic online backups (link)
  restic:
    container_name: restic
    image: mazzolino/restic
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - BACKUP_CRON=0 30 0 * * *
      - RESTIC_REPOSITORY=b2:tdehaeze:/restic
      - 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
      - B2_ACCOUNT_ID=$RESTIC_B2_ACCOUNT_ID
      - B2_ACCOUNT_KEY=$RESTIC_B2_ACCOUNT_KEY
      - UID=$PUID
      - GID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/restic/exclude.txt:/exclude.txt:ro
      - /srv/storage/Cloud/thesis:/source/Cloud/thesis:ro
      - /home/thomas/docker:/source/docker:ro
    logging: *default-logging
exclude.txt - Exclude files
*.db
*.log
*.log.*
/source/docker/config/gitea/git/
/source/docker/config/guacamole/
/source/docker/config/guacamole_db/
/source/docker/config/mariadb/
/source/docker/config/miniflux_db/
/source/docker/config/jellyfin/data/
/source/docker/config/dotfiles/www/
/source/docker/config/web/www/
octoprint - Web interface for 3D printing (link)
  octoprint:
    container_name: octoprint
    image: octoprint/octoprint
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - UID=$PUID
      - GID=$PGID
      - TZ=$TZ
    privileged: true
    volumes:
      - $CONFIGDIR/octoprint:/octoprint
      - /dev/bus/usb:/dev/bus/usb
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.octoprint-rtr.entrypoints=https"
      - "traefik.http.routers.octoprint-rtr.rule=Host(`octoprint.$DOMAINNAME`)"
      - "traefik.http.routers.octoprint-rtr.tls=true"
      - "traefik.http.routers.octoprint-rtr.service=octoprint-svc"
      - "traefik.http.routers.octoprint-rtr.middlewares=authelia@docker"
      - "traefik.http.services.octoprint-svc.loadbalancer.server.port=80"
    logging: *default-logging
mealie - Recipe Manager (link)
  miam:
    container_name: miam
    image: hkotel/mealie
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - db_type=sqlite
      - UID=$PUID
      - GID=$PGID
      - TZ=$TZ
    volumes:
      - $CONFIGDIR/mealie:/app/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.miam-rtr.entrypoints=https"
      - "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
diun - Notification for Docker image updates (link)
  diun:
    container_name: diun
    image: crazymax/diun
    restart: unless-stopped
    networks:
      - backend
    environment:
      - TZ=$TZ
      - LOG_LEVEL=info
      - LOG_JSON=false
      - DIUN_WATCH_WORKERS=20
      - DIUN_WATCH_SCHEDULE=0 7 * * 6
      - DIUN_PROVIDERS_DOCKER=true
      - DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT=true
      - DIUN_NOTIF_GOTIFY_ENDPOINT=$GOTIFY_URL
      - DIUN_NOTIF_GOTIFY_TOKEN=$DIUN_GOTIFY_TOKEN
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - $CONFIGDIR/diun:/data
    logging: *default-logging
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=$GMAIL_PASS
      - COMMENTO_SMTP_FROM_ADDRESS=tdehaeze.xyz@gmail.com
    depends_on:
      - commento_db
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.commento-rtr.entrypoints=https"
      - "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
    environment:
      - POSTGRES_DB=commento
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=$COMMENTO_DB_PASSWORD
    volumes:
      - $CONFIGDIR/commento_db:/var/lib/postgresql/data
    logging: *default-logging
uptime-kuma - Monitoring Tool (link)
  uptime-kuma:
    container_name: uptime-kuma
    image: louislam/uptime-kuma
    restart: unless-stopped
    networks:
      - t2_proxy
    volumes:
    environment:
      - TZ=$TZ
      - UID=$PUID
      - GID=$PGID
    volumes:
      - $CONFIGDIR/uptime-kuma:/app/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.uptime-rtr.entrypoints=https"
      - "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
kavita - Reading server (link)
  kavita:
    container_name: kavita
    image: kizaing/kavita:latest
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - TZ=$TZ
      - UID=$PUID
      - GID=$PGID
    volumes:
      - $CONFIGDIR/kavita:/kavita/data
      - /srv/storage/Books:/books
      - /srv/storage/Scans:/scans
      - /srv/storage/Comics:/comics
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.kavita-rtr.entrypoints=https"
      - "traefik.http.routers.kavita-rtr.rule=Host(`kavita.$DOMAINNAME`)"
      - "traefik.http.routers.kavita-rtr.tls=true"
      - "traefik.http.routers.kavita-rtr.service=kavita-svc"
      - "traefik.http.services.kavita-svc.loadbalancer.server.port=5000"
    logging: *default-logging
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)
  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
    devices:
      - /dev/ttyACM0:/dev/ttyACM0
zigbee2mqttassistant - GUI for Zigbee2Mqtt (link)
  zigbee2mqttAssistant:
    container_name: zigbee2mqttassistant
    image: carldebilly/zigbee2mqttassistant
    restart: unless-stopped
    networks:
      - t2_proxy
    environment:
      - Z2MA_SETTINGS__MQTTSERVER=192.168.1.21:1883
      # - Z2MA_SETTINGS__MQTTUSERNAME={MQTTUSERNAME}
      # - Z2MA_SETTINGS__MQTTPASSWORD={MQTTPASSWORD}
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.zigbee2mqttassistant-rtr.entrypoints=https"
      - "traefik.http.routers.zigbee2mqttassistant-rtr.rule=Host(`zigbee2mqttassistant.$DOMAINNAME`)"
      - "traefik.http.routers.zigbee2mqttassistant-rtr.tls=true"
      - "traefik.http.routers.zigbee2mqttassistant-rtr.service=zigbee2mqttassistant-svc"
      - "traefik.http.routers.zigbee2mqttassistant-rtr.middlewares=authelia@docker"
      - "traefik.http.services.zigbee2mqttassistant-svc.loadbalancer.server.port=80"
    logging: *default-logging
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