ITGOIT - Wiki

Secure Your Containers with Automated Backup scripts

Table of Contents

The OG Docker GUI
- Portainer

--

Home Dashboards
- Homepage
- Dashy
- Homarr

--

Media Servers
the arrs all in one is highly recommended to use
- THE ARRS ALL IN ONE
- Jellyfin
- Jellyseerr
- Navidrome
- Ampache
- Mango epubs

--

Security
- Authentik
- Zitadel
- Authelia 2FA
- Vaultwarden
- Changedetection
- iSpy
- UniFi Controller
- UniFi Protect

--

Monitoring
- Grafana
- Prometheus
- Uptime Kuma
- Matomo
- Librespeed
- Netdata

--

Networking
- Traefik
- Nginx Proxy Manager
- Unbound
- Pihole
- Netbootxyz
- Duck DNS
- Netbird
- Technitium
- Wireguard
- fail2ban
- CrowdSec
- Cloudflared
- Teleport
- Mailcow
- Netbox

--

Communication
- Matrix
- Zulip
- Jitsi
- Rocket.Chat
- Nextcloud
- Workadventure
- Invision Community
- HumHub
- Spacebar
- Discord Bot
- Habbo Hotel Retro

--

Management
- Ansible Semaphore
- Guacamole
- Remotely
- RustDesk
- UpSnap
- Pterodactyl
- PufferPanel
- Seafile
- Webtop
- Filebrowser
- Home Assistant
- Zigbee2MQTT
- Copyparty

--

Productivity
- Dolibarr
- Wiki.js
- Nginx
- Tor
- Wordpress
- Gitea
- Gitlab
- OpenProject
- LinkWarden
- LinkStack
- Draw.io
- Pwndrop
- Snapdrop
- UVDesk
- GLPI
- KASM
- Whoogle
- PrivateBin
- Hastebin
- Firefox
- Mealie
- Jenkins

Dashy (app dashboard)

cd /home/myusername/docker
mkdir -p dashy/{public,icons}
cd dashy

nano docker-compose.yml

services:
  dashy:
    image: lissy93/dashy:latest
    container_name: dashy
    restart: unless-stopped
    volumes:
      - ./public/conf.yml:/app/public/conf.yml
      - ./icons:/app/public/item-icons/icons
    ports:
      - 8100:80
cd icons
git clone https://github.com/walkxcode/Dashboard-Icons.git
cd public

nano conf.yml

appConfig:
  theme: colorful
  layout: auto
  iconSize: medium
  language: en
pageInfo:
  title: Home Lab
  description: Welcome to your Home Lab!
  navLinks:
    - title: GitHub
      path: https://github.com/Lissy93/dashy
    - title: Documentation
      path: https://dashy.to/docs
  footerText: ''
sections:
  - name: Starter Only
    icon: fas fa-server
    items:
      - title: Google
        description: Search
        url: https://google.com

Configure Dashy

Edit Item example:
Item Text: Portainer
Description: Docker GUI
Icon: icons/dashboard-icons/png/portainer.png
Service URL: 192.168.1.50:9999
Opening Method: newtab

Homepage (app dashboard)

cd /home/myusername/docker
mkdir hpage && cd "$_"

nano docker-compose.yml

services:
  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: hpage
    restart: unless-stopped
    volumes:
      - ./config:/app/config
      - ./icons:/app/public/icons
      - ./images:/app/public/images # (optional) For custom background images
      - /var/run/docker.sock:/var/run/docker.sock:ro # (optional) For docker integrations
    environment:
      HOMEPAGE_ALLOWED_HOSTS: "*" # The * means it is disabled. This is optional but not recommended
    ports:
      - 8101:3000
docker compose up -d

Configure Homepage

https://gethomepage.dev/en/configs/services/

Add authentik widget

  1. In authentik go to: Admin interface > Directory > Tokens and App passwords

  2. Click on: Create

  3. Insert the following info:

Identifier: homepage
Intent: API Token
User: admin
Description: API Token to display widget info of authentik.
Expiring: disabled

  1. Click on: Copy token

  2. Edit services.yaml and insert the following:

- Remote Management:
    - Authentik:
        href: http://AUTHENTIK_IP_HERE:9160
        description: Single Sign On (SSO)
        icon: authentik.png
        server: docker
        container: authentik
        widget:
            type: authentik
            url: https://portal.DOMAIN.COM
            key: api_token

Homarr (app dashboard)

cd /home/myusername/docker
mkdir homarr && cd "$_"

nano docker-compose.yml

services:
  homarr:
    image: ghcr.io/ajnart/homarr:latest
    container_name: homarr
    restart: unless-stopped
    volumes:
      - ./configs:/app/data/configs
      - ./icons:/app/public/icons
      - /var/run/docker.sock:/var/run/docker.sock:ro
    ports:
      - 8102:7575

docker compose up -d

Nginxproxymanager

cd /home/myusername/docker
mkdir nginxpm && cd "$_"
mkdir data letsencrypt

nano docker-compose.yml

services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginxpm
    restart: unless-stopped
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    ports:
      - 80:80
      - 81:81
      - 443:443
docker compose up -d

Default login
Email: [email protected]
Password: changeme

 

Reverse proxy config

docker network create -d bridge nginx-pmnet
docker network connect nginx-pmnet nginxpm_app_1
docker network connect nginx-pmnet nginxpm_db_1

portainer:

Click on recycle bin to remove ports
Advanced container settings --> Network: remove all the ports
network: nginx-pmnet
Deploy the container

Nginx Proxy Manager:

Add proxy host

Domain names: myapp.DOMAIN.COM
Scheme: http
Forward Hostname / IP: myapp
Forward Port: 80

Cache Assets.
Block Common Exploits.
Websockets Support.
SAVE

 

Ampache (Music server)

cd /home/myusername/docker
mkdir ampache && cd "$_"
services:
  ampache:
    image: ampache/ampache
    container_name: ampache
    restart: unless-stopped
    volumes:
      - ./media:/media
    ports:
      - 8051:80
      - 8543:443
docker compose up -d

Configure Ampache

Enable CREATE DATABASE USER for first time setup web

Ampache Database Username: ampache

Ampache Database User Password: ampache!

Click INSERT DATABASE
Insert Database Password that you just created

For Allow Transcoding:

Template Configuration: ffmpeg

For Players Enable the following:

  • Web Interface,
  • Ampache API,
  • Subsonic,
  • UPnP,
  • DAAP(iTunes),
  • WebDAV.

For Create Admin Account:
Choose differnt username then database name

Username: admin
Password: ampache!

Add a catalog in the Ampache-webapp

Catalog Name: User music
Catalog Type: Local
Path: /media
 

Navidrome (Music server)

cd /home/myusername/docker
mkdir navidrome && cd "$_"

nano docker-compose.yml

services:
  navidrome:
    image: deluan/navidrome:latest
    container_name: navidrome
    restart: unless-stopped
    environment:
      ND_SCANINTERVAL: 30m
      ND_LOGLEVEL: info
      ND_BASEURL: 
    volumes:
      - /path/to/your/music/files:/music:ro
      - ./data:/data
    ports:
      - 4533:4533
docker compose up -d

Snapdrop

cd /home/myusername/docker
mkdir snapdrop && cd "$_"
services:
  snapdrop:
    image: lscr.io/linuxserver/snapdrop:latest
    container_name: snapdrop
    restart: unless-stopped
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Etc/UTC
    volumes:
      - ./config:/config
    ports:
      - 80:80
      - 443:443
docker compose up -d

Home Assistant (with app store)

cd /home/myusername/docker
mkdir homeassistant && cd "$_"

nano docker-compose.yml

services:
  homeassistant:
    image: ghcr.io/home-assistant/home-assistant:stable
    container_name: homeassistant
    restart: unless-stopped
    volumes:
      - ./config:/config
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 8260:8123

#    depends_on:
#      - mariadb

#  db:
#    image: linuxserver/mariadb
#    container_name: homeassistant_db
#    restart: unless-stopped
#    environment:
#      MYSQL_DATABASE: homeassistant
#      MYSQL_USER: homeassistant
#      MYSQL_PASSWORD: homeassistant!
#      MYSQL_ROOT_PASSWORD: homeassistant!!
#    volumes:
#      - ./db:/var/lib/mysql
#    ports:
#      - 8261:3306

docker compose up -d

Themes

https://github.com/basnijholt/lovelace-ios-themes

Alternative

sudo apt install jq
sudo apt install network-manager
sudo curl -sL https://github.com/Kanga-Who/home-assistant/blob/master/supervised-installer.sh | bash -s

Jellyfin

cd /home/myusername/docker
mkdir jellyfin && cd "$_"

nano docker-compose.yml

services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    restart: unless-stopped
    environment:
      PGID: 1000
      PUID: 1000
      UMASK: 002
      TZ: Etc/UTC
    devices:
      - /dev/dri:/dev/dri
    volumes:
      - /media/disk/DISKNAME/SERIESPATH:/media/TV
      - /media/disk/DISKNAME/MOVIEPATH:/media/movies
      - /media/disk/DISKNAME/MUSICPATH:/media/music
      - /media/disk/DISKNAME/PICTURESPATH:/media/pictures
      - /media/disk/DISKNAME/BOOKSPATH:/media/books
      - /dev/shm:/transcode
      - ./config:/config
      - ./cache:/cache
    ports:
      - 8110:8096
    networks:
      - jellyfin-net
    
networks:
  jellyfin-net:
    driver: bridge
docker compose up -d

Jellyfin config

Account --> Dashboard --> Plugins --> Repositories

Repositories name: jellyfinPluginMan
Repository URL: https://raw.githubusercontent.com/danieladov/JellyfinPluginManifest/master/manifest.json

Repositories name: Robiro
Repository URL: https://repo.codyrobibero.dev/manifest.json

Jellyseerr (jellyfin media requester)

cd /home/myusername/docker
mkdir jellyseerr && cd "$_"

nano docker-compose.yml

services:
  jellyseerr:
    image: ghcr.io/seerr-team/seerr:latest
    container_name: jellyseerr
    restart: unless-stopped
    environment:
      TZ: Etc/UTC
      LOG_LEVEL: debug
    volumes:
      - ./config:/app/config
    ports:
      - 8111:5055
docker compose up -d

Tixati

cd /home/myusername/docker
mkdir tixati && cd "$_"

nano docker-compose.yml

services:
  tixati:
    image: kyzimaspb/tixati:latest
    container_name: tixati
    restart: unless-stopped
    environment:
      XVFB_RESOLUTION: 1000x900x24 # optional
      VNC_SERVER_PASSWORD: tixati! # optional
    volumes:
      - ./downloads:/home/user/Desktop/downloads
      - ./torrent-files:/home/user/Desktop/torrent-files
      - ./config:/home/user/.config
    ports:
      - 8117:5900
docker compose up -d

Unbound

cd /home/myusername/docker
mkdir unbound && cd "$_"
services:
  unbound:
    image: mvance/unbound:latest
    container_name: unbound
    restart: unless-stopped
    healthcheck:
      disable: true
    volumes:
      - ./data:/opt/unbound/etc/unbound
    ports:
      - 8120:53/tcp
      - 8120:53/udp

PrivateBin

cd /home/myusername/docker
mkdir -p privatebin/config && cd privatebin/config

Download the conf.php below and drop it into config folder
conf.php

cd ..

nano docker-compose.yml

services:
  privatebin:
    image: privatebin/nginx-fpm-alpine:latest
    container_name: privatebin
    restart: unless-stopped
    read_only: true
    volumes:
      - ./data:/srv/data
      - ./config/conf.php:/srv/cfg/conf.php:ro
    ports:
      - 9215:8080
docker compose up -d

Hastebin

cd /home/myusername/docker
mkdir hastebin && cd "$_"

nano docker-compose.yml

services:
  hastebin:
    image: arminfriedl/hastebin:latest
    container_name: hastebin
    restart: unless-stopped
    volumes:
      - ./data:/app/data
    ports:
      - 8132:7777
docker compose up -d

Nextcloud

cd /home/myusername/docker
mkdir nextcloud && cd "$_"

nano docker-compose.yml

services:
  db:
    image: postgres:16
    container_name: nextcloud_postgres
    restart: unless-stopped
    user: ${UID}:${GID}
    volumes:
      - ./db:/var/lib/postgresql/data
#      - /etc/passwd:/etc/passwd:ro
    env_file:
      - .env
    healthcheck:
      test: ["CMD-SHELL", "pg_isready --dbname='${POSTGRES_DB}' --username='${POSTGRES_USER}' || exit 1"]
      interval: 5m
      start_period: 30s
      timeout: 5s
      retries: 3
    networks:
      - nextcloud-net

  app:
    image: nextcloud:latest
    container_name: nextcloud
    restart: unless-stopped
    user: ${UID}:${GID}
    env_file:
      - .env
    volumes:
      - ./nextcloud:/var/www/html
      - ./apps:/var/www/html/custom_apps
      - ./data:/var/www/html/data
      - ./config:/var/www/html/config
      - ./redis-session.ini:/usr/local/etc/php/conf.d/redis-session.ini
      - ./remoteip.conf:/etc/apache2/conf-available/remoteip.conf:ro
    ports:
      - 8330:80
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - nextcloud-net

  notify_push:
    image: nextcloud:latest
    container_name: nextcloud_push
    restart: unless-stopped
    user: 1004:1004
    environment:
      TZ: Etc/UTC
      PORT: 7867
      NEXTCLOUD_URL: http://app      # don't go through the proxy to contact the nextcloud server
    entrypoint: /var/www/html/custom_apps/notify_push/bin/x86_64/notify_push /var/www/html/config/config.php
    volumes:
      - ./apps:/var/www/html/custom_apps
      - ./config:/var/www/html/config
    ports:
      - 8331:7867
    depends_on:
      - app
    networks:
      - nextcloud-net

  cron:
    image: nextcloud:latest
    container_name: nextcloud_cron
    restart: unless-stopped
    # special UID handling https://github.com/nextcloud/docker/issues/1740
    environment:
      TZ: ${TIMEZONE}
      UID: ${UID}
    env_file:
      - .env
    volumes:
      - ./nextcloud:/var/www/html
      - ./apps:/var/www/html/custom_apps
      - ./data:/var/www/html/data
      - ./config:/var/www/html/config
      - ./cron.sh:/cron.sh
    entrypoint: /cron.sh
    depends_on:
      - app
    networks:
      - nextcloud-net

  redis:
    image: redis:bookworm
    container_name: nextcloud_redis
    restart: unless-stopped
    user: ${UID}:${GID}
    command:
      - --save ""
#    volumes:
#      - ./redis:/data
    environment:
      TZ: ${TIMEZONE}
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      start_period: 10s
      interval: 30s
      retries: 3
      timeout: 3s
    networks:
      - nextcloud-net

  imaginary:
    image: nextcloud/aio-imaginary:latest
    container_name: nextcloud_imaginary
    restart: unless-stopped
    user: ${UID}:${GID}
    expose:
      - "9000"
    environment:
      TZ: ${TIMEZONE}
    cap_add:
      - SYS_NICE
    tmpfs:
      - /tmp
    depends_on:
      - app	  
    networks:
      - nextcloud-net


  nextcloud-collabora:
    image: collabora/code
    container_name: nextcloud_collabora
    restart: unless-stopped
    ports:
      - 8332:9980
#    expose:
#      - "9980"  
    environment:
      #should work as "domain=cloud1\.nextcloud\.com|cloud2\.nextcloud\.com"
      - domain=${COLLABORA_DOMAINS}
      - 'dictionaries=en_US,nl_NL'
      - VIRTUAL_PROTO=http
      - VIRTUAL_PORT=9980
      - VIRTUAL_HOST=${COLLABORA_FQDN}
      - "extra_params=--o:ssl.enable=false  --o:ssl.termination=true"
    env_file:
      - .env
    cap_add:
      - MKNOD
    tty: true
    networks:
      - nextcloud-net


networks:
  nextcloud-net:
    external: true

Download nextcloud_launcher.sh then drop it into the nextcloud folder

nextcloud_launcher.sh

sudo chmod +x nextcloud_launcher.sh && sudo ./nextcloud_launcher.sh

Configure for traefik

cd /home/myusername/docker/traefik-crowdsec/traefik-data
nano fileConfig.yml
http:
  routers:

##########################################################
###======================ROUTERS======================###

  ### nextcloud - router ###
    nextcloud:
      entryPoints:
        - https
      rule: "Host(`nextcloud.DOMAIN.COM`) || Host(`nextcloud.local.DOMAIN.COM`)"
      service: nextcloud
      priority: 1


  # nextcloud push - router
    nextcloud-push:
      rule: "Host(`nextcloud.DOMAIN.COM`) && PathPrefix(`/push`)"
      service: nextcloud-push
      priority: 2


  # collabora - router
    collabora:
      rule: "Host(`collabora.DOMAIN.COM`) || Host(`collabora.local.DOMAIN.COM`)"
      service: collabora
##########################################################
###======================SERVICES======================###
  services:

  ### nextcloud - service ###
    nextcloud:
      loadBalancer:
        servers:
          - url: http://192.168.1.x:8330

  # nextcloud push - service
    nextcloud-push:
      loadBalancer:
        servers:
          - url: http://192.168.1.x:8331

  # collabora - service
    collabora:
      loadBalancer:
        servers:
          - url: http://192.168.1.x:8332

Whoogle (search engine)

cd /home/myusername/docker
mkdir whoogle && cd "$_"

nano docker-compose.yml

services:
  whoogle:
    image: benbusby/whoogle-search:latest
    container_name: whoogle
    restart: unless-stopped
    user: root
    volumes:
      - ./config:/config
    ports:
      - 8140:5000
docker compose up -d

DUCKDNS

cd /home/myusername/docker
mkdir duckdns && cd "$_"
mkdir config

nano docker-compose.yml

services:
  duckdns:
    image: ghcr.io/linuxserver/duckdns
    container_name: duckdns
    restart: unless-stopped
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Etc/UTC
# subdomain example: nicecloud.duckdns.org
      SUBDOMAINS: subdomain1,subdomain2,subdomain3
      TOKEN: token
      LOG_FILE: false
    volumes:
      - ./config:/config
docker compose up -d

WorkAdventure

cd /home/myusername/docker
mkdir workadventure
cd workadventure
touch .env
touch docker-compose.yml

nano .env

# Server Information
SERVER_NAME=
SERVER_MOTD=
SERVER_ICON=

DEBUG_MODE=false
JITSI_URL=meet.jit.si
# If your Jitsi environment has authentication set up, you MUST set JITSI_PRIVATE_MODE to "true" and you MUST pass a SECRET_JITSI_KEY to generate the JWT secret
JITSI_PRIVATE_MODE=false
JITSI_ISS=
SECRET_JITSI_KEY=

# Jitsi settings for the low-level Jitsi API (used by the live-streaming area)
# JITSI_DOMAIN is the domain name of your Jitsi web instance (only the domain name, not the full URL)
JITSI_DOMAIN=
# JITSI_XMPP_DOMAIN is the domain name used by Prosody.
# You can find this value in the Jitsi config.js file ("hosts.domain" key)
# If you are using Jitsi Docker install, this is the value of the XMPP_DOMAIN environment variable.
JITSI_XMPP_DOMAIN=
# JITSI_XMPP_MUC_DOMAIN is the domain name used by Prosody for MUC.
# You can find this value in the Jitsi config.js file ("hosts.muc" key)
# If you are using Jitsi Docker install, this is the value of the XMPP_MUC_DOMAIN environment variable.
JITSI_MUC_DOMAIN=

# BigBlueButton settings.
# From your BBB instance, you can get the correct values using the command: "bbb-conf --secret"
# This defaults to a test instance kindly provided by blindsidenetworks.com. Please change this in production settings.
BBB_URL=https://test-install.blindsidenetworks.com/bigbluebutton/
BBB_SECRET=8cd8ef52e8e101574e400365b55e11a6
ADMIN_API_URL=
ADMIN_API_TOKEN=123
START_ROOM_URL=/_/global/maps.workadventure.localhost/starter/map.json
MAP_STORAGE_URL=map-storage:50053
# If your Turn server is configured to use the Turn REST API, you should put the shared auth secret here.
# If you are using Coturn, this is the value of the "static-auth-secret" parameter in your coturn config file.
# Keep empty if you are sharing hard coded / clear text credentials.
TURN_STATIC_AUTH_SECRET=
TURN_SERVER=
# You can uncomment the 2 lines below and the Coturn section in docker-compose.yaml to test this behaviour locally
#TURN_SERVER=turn:coturn.workadventure.localhost:3478,turns:coturn.workadventure.localhost:5349
#TURN_STATIC_AUTH_SECRET=SomeStaticAuthSecret
DISABLE_NOTIFICATIONS=true
SKIP_RENDER_OPTIMIZATIONS=false

# The email address used by Let's encrypt to send renewal warnings (compulsory)
ACME_EMAIL=

MAX_PER_GROUP=4
MAX_USERNAME_LENGTH=10

# Configure low and recommended bandwidth used by video and screen share in the peer-to-peer connection (in kbit/s)
PEER_VIDEO_LOW_BANDWIDTH=150
PEER_VIDEO_RECOMMENDED_BANDWIDTH=150
PEER_SCREEN_SHARE_LOW_BANDWIDTH=250
PEER_SCREEN_SHARE_RECOMMENDED_BANDWIDTH=1000

OPID_CLIENT_ID=
OPID_CLIENT_SECRET=
OPID_CLIENT_ISSUER=
OPID_PROFILE_SCREEN_PROVIDER=
OPID_PROMPT=login
OPID_LOCALE_CLAIM=
OPID_LOGOUT_REDIRECT_URL=
DISABLE_ANONYMOUS=
OPID_SCOPE=
OPID_USERNAME_CLAIM=
OPID_TAGS_CLAIM=


# Whether the user can choose its name or if the name is dictated by OpenID.
# Can be one of "user_input", "allow_override_opid", "force_opid"
# This setting is only useful if DISABLE_ANONYMOUS=true
#   user_input: the user will be prompted for his/her Woka name
#   force_opid: the user cannot decide his/her Woka name
#   allow_override_opid: by default, the user name from OpenID is used, but the user can change it
OPID_WOKA_NAME_POLICY=

# If you want to have a contact page in your menu, you MUST set CONTACT_URL to the URL of the page that you want
CONTACT_URL=

# Prometheus settings
## Uncomment this to enable the /metrics Prometheus endpoint.
## To hit this endpoint, you will need to configure Prometheus with:
## authorization:
##   type: Bearer
##   credentials: "[The value of PROMETHEUS_AUTHORIZATION_TOKEN env variable]"
PROMETHEUS_AUTHORIZATION_TOKEN=

# The maximum time to live of player variables for logged players, expressed in seconds (no limit by default).
# Use "-1" for infinity.
# Note that anonymous players don't have any TTL limit because their data is stored in local storage, not in Redis database.
PLAYER_VARIABLES_MAX_TTL=-1

# MAP EDITOR SETTINGS
ENABLE_MAP_EDITOR=true
# If you want to allow only some users to access the map editor, you can set the list of authorized users here, email separated by commas. (Only possible if OpenID Connect is configured)
# Leave blank if you want to allow all users to access the map editor.
# This variable is ignored if an AdminAPI is configured
MAP_EDITOR_ALLOWED_USERS=

# AWS environement variable for uploader
# AWS_ACCESS_KEY_ID=minio-access-key
# AWS_SECRET_ACCESS_KEY=minio-secret-access-key
# AWS_DEFAULT_REGION=eu-west-1
# AWS_BUCKET=workadventure-bucket
# AWS_ENDPOINT=http://cdn.workadventure.localhost/
#
# Time for which signed urls are valid (in seconds)
# UPLOADER_AWS_SIGNED_URL_EXPIRATION=60

# Redis for uploader service of WorkAdventure
## The uploader service stores all files uploaded by the chat service
## 2 possibilities to setup the uploader storage: AWS, REDIS
### AWS with all environement variable AWS
### Redis with this environment variable
UPLOADER_REDIS_HOST=redis
UPLOADER_REDIS_PORT=6379
UPLOADER_REDIS_DB_NUMBER=1


###############################
# Chat environement variables #
###############################
EJABBERD_JWT_SECRET=mySecretJwt
EJABBERD_DOMAIN=ejabberd
EJABBERD_USER=admin
EJABBERD_PASSWORD=admin

# Max day of chat history that can be fetched by users
## No restriction is : 0 or not defined value
# MAX_HISTORY_CHAT=0

# Embedely key api for rich media embeds
## used in the chat service and the map editor
EMBEDLY_KEY=

# Iframely key api for rich media embeds
## used in the chat service and the map editor
IFRAMELY_KEY=

# Enable / disable chat
ENABLE_CHAT=true
# Enable / disable upload of file in chat (MUST BE TRUE ONLY IF ENABLE_CHAT IS TRUE)
ENABLE_CHAT_UPLOAD=true
ENABLE_CHAT_ONLINE_LIST=true
ENABLE_CHAT_DISCONNECTED_LIST=true
# Chat max uploadable file size (Byte)
UPLOAD_MAX_FILESIZE=10485760

# JWT secret key
SECRET_KEY=yourSecretKey2020

# Report issues menu
ENABLE_REPORT_ISSUES_MENU=false
REPORT_ISSUES_URL=

# LogRocket
LOGROCKET_ID=

# Sentry integration
## Find the DSN in the Sentry UI
SENTRY_DSN_FRONT=
SENTRY_DSN_PUSHER=
SENTRY_DSN_MAPSTORAGE=
SENTRY_DSN_BACK=
SENTRY_DSN_CHAT=
## Find the  the release name in the Sentry UI
SENTRY_RELEASE=local
SENTRY_ENVIRONMENT=local
SENTRY_ORG=
SENTRY_PROJECT=

# RoomAPI
ROOM_API_SECRET_KEY=

# Integration tools
KLAXOON_ENABLED=false
KLAXOON_CLIENT_ID=
YOUTUBE_ENABLED=true
GOOGLE_DRIVE_ENABLED=true
GOOGLE_DOCS_ENABLED=true
GOOGLE_SHEETS_ENABLED=true
GOOGLE_SLIDES_ENABLED=true
GOOGLE_DRIVE_ENABLED=true
ERASER_ENABLED=true
EXCALIDRAW_ENABLED=true
EXCALIDRAW_DOMAINS=
# If you want to force allow some domains to be embedded in WorkAdventure, you can set the list of authorized domains here, separated by ','.
# Example: EMBEDDED_DOMAINS_WHITELIST=klaxoon.com,google.com
EMBEDDED_DOMAINS_WHITELIST=

# Google drive picker
GOOGLE_DRIVE_PICKER_CLIENT_ID=
GOOGLE_DRIVE_PICKER_APP_ID=

nano docker-compose.yml

services:
  reverse-proxy:
    image: traefik:v2.8
    restart: ${RESTART_POLICY}
    command:
      - --log.level=${LOG_LEVEL}
      - --providers.docker
      - --providers.docker.exposedbydefault=false
      # Entry points
      - --entryPoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entryPoint.scheme=https
      - --entryPoints.websecure.address=:443
      - --entryPoints.grpc.address=:50051
      # HTTP challenge
      - --certificatesresolvers.myresolver.acme.email=${ACME_EMAIL}
      - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
      # Let's Encrypt's staging server
      # uncomment during testing to avoid rate limiting
      #- --certificatesresolvers.dnsresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
    ports:
      - "${HTTP_PORT}:80"
      - "${HTTPS_PORT}:443"
      - "${GRPC_PORT}:50051"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ${DATA_DIR}/letsencrypt/:/letsencrypt/

  play:
    image: thecodingmachine/workadventure-play:${VERSION}
    restart: ${RESTART_POLICY}
    environment:
      - DEBUG_MODE
      - JITSI_URL
      - JITSI_PRIVATE_MODE
      - ENABLE_MAP_EDITOR
      - MAP_EDITOR_ALLOWED_USERS
      - PUSHER_URL=https://${DOMAIN}/
      - ICON_URL=/icon
      - TURN_SERVER
      - TURN_USER
      - TURN_PASSWORD
      - TURN_STATIC_AUTH_SECRET
      - STUN_SERVER
      - SKIP_RENDER_OPTIMIZATIONS
      - MAX_PER_GROUP
      - MAX_USERNAME_LENGTH
      - DISABLE_ANONYMOUS
      - DISABLE_NOTIFICATIONS
      - SECRET_KEY
      - API_URL=back:50051
      - FRONT_URL=/
      - CHAT_URL=/chat/
      - INTERNAL_MAP_STORAGE_URL=http://map-storage:3000
      - PUBLIC_MAP_STORAGE_URL=https://${DOMAIN}/map-storage
      - START_ROOM_URL
      - OPID_PROMPT=login
      - OPID_WOKA_NAME_POLICY
      - OPID_CLIENT_ID
      - OPID_CLIENT_SECRET
      - OPID_CLIENT_ISSUER
      - OPID_PROFILE_SCREEN_PROVIDER
      - OPID_SCOPE
      - OPID_USERNAME_CLAIM
      - OPID_LOCALE_CLAIM
      - OPID_LOGOUT_REDIRECT_URL
      - ENABLE_CHAT
      - ENABLE_CHAT_UPLOAD
      - ENABLE_CHAT_ONLINE_LIST
      - ENABLE_CHAT_DISCONNECTED_LIST
      - UPLOADER_URL=/uploader
      # Only used if you set up a JWT authentication mechanism in Ejabberd
      - EJABBERD_JWT_SECRET=${EJABBERD_JWT_SECRET}
      - EJABBERD_DOMAIN=${EJABBERD_DOMAIN}
      # Report issues menu
      - ENABLE_REPORT_ISSUES_MENU=${ENABLE_REPORT_ISSUES_MENU}
      - REPORT_ISSUES_URL=${REPORT_ISSUES_URL}
      - ENABLE_OPENAPI_ENDPOINT=true
      - ADMIN_API_TOKEN
      - ADMIN_API_URL
      - ADMIN_URL
      - ROOM_API_PORT=50051
      - ROOM_API_SECRET_KEY=${ROOM_API_SECRET_KEY}
      - GRPC_VERBOSITY=DEBUG
      - GRPC_TRACE=all
      - SENTRY_ORG=${SENTRY_ORG}
      - SENTRY_PROJECT=${SENTRY_PROJECT}
      - SENTRY_DSN_FRONT=${SENTRY_DSN_FRONT}
      - SENTRY_DSN_PUSHER=${SENTRY_DSN_PUSHER}
      - SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT}
      - SENTRY_RELEASE=${SENTRY_RELEASE}
      - SENTRY_TRACES_SAMPLE_RATE=${SENTRY_TRACES_SAMPLE_RATE}
      - JITSI_DOMAIN
      - JITSI_XMPP_DOMAIN
      - JITSI_MUC_DOMAIN
      - WOKA_SPEED
      - FEATURE_FLAG_BROADCAST_AREAS=${FEATURE_FLAG_BROADCAST_AREAS}
      # Tools integration
      - KLAXOON_ENABLED=${KLAXOON_ENABLED}
      - KLAXOON_CLIENT_ID=${KLAXOON_CLIENT_ID}
      - YOUTUBE_ENABLED=${YOUTUBE_ENABLED}
      - GOOGLE_DRIVE_ENABLED=${GOOGLE_DRIVE_ENABLED}
      - GOOGLE_DOCS_ENABLED=${GOOGLE_DOCS_ENABLED}
      - GOOGLE_SHEETS_ENABLED=${GOOGLE_SHEETS_ENABLED}
      - GOOGLE_SLIDES_ENABLED=${GOOGLE_SLIDES_ENABLED}
      - ERASER_ENABLED=${ERASER_ENABLED}
      - EXCALIDRAW_ENABLED=${EXCALIDRAW_ENABLED}
      - EXCALIDRAW_DOMAINS=${EXCALIDRAW_DOMAINS}
      - EMBEDDED_DOMAINS_WHITELIST=${EMBEDDED_DOMAINS_WHITELIST}
      - PEER_VIDEO_LOW_BANDWIDTH=${PEER_VIDEO_LOW_BANDWIDTH}
      - PEER_VIDEO_RECOMMENDED_BANDWIDTH=${PEER_VIDEO_RECOMMENDED_BANDWIDTH}
      - PEER_SCREEN_SHARE_LOW_BANDWIDTH=${PEER_SCREEN_SHARE_LOW_BANDWIDTH}
      - PEER_SCREEN_SHARE_RECOMMENDED_BANDWIDTH=${PEER_SCREEN_SHARE_RECOMMENDED_BANDWIDTH}
      # Google drive picker
      - GOOGLE_DRIVE_PICKER_CLIENT_ID=${GOOGLE_DRIVE_PICKER_CLIENT_ID}
      - GOOGLE_DRIVE_PICKER_APP_ID=${GOOGLE_DRIVE_PICKER_APP_ID}
    labels:
      traefik.enable: "true"
      traefik.http.routers.play.rule: "Host(`${DOMAIN}`) && PathPrefix(`/`)"
      traefik.http.routers.play.entryPoints: "web"
      traefik.http.services.play.loadbalancer.server.port: "3000"
      traefik.http.routers.play-ssl.rule: "Host(`${DOMAIN}`) && PathPrefix(`/`)"
      traefik.http.routers.play-ssl.entryPoints: "websecure"
      traefik.http.routers.play-ssl.tls: "true"
      traefik.http.routers.play-ssl.tls.certresolver: "myresolver"
      traefik.http.routers.play-ssl.service: "play"
      traefik.http.routers.room-api.rule: "Host(`${DOMAIN}`)"
      traefik.http.routers.room-api.entryPoints: "grpc"
      traefik.http.routers.room-api.service: "room-api"
      traefik.http.services.room-api.loadbalancer.server.port: "50051"
      traefik.http.services.room-api.loadbalancer.server.scheme: "h2c"
      traefik.http.routers.room-api.tls: "true"
      traefik.http.routers.room-api.tls.certresolver: "myresolver"

  chat:
    image: thecodingmachine/workadventure-chat:${VERSION}
    restart: ${RESTART_POLICY}
    environment:
      - PUSHER_URL=/
      - UPLOADER_URL=/uploader
      - EMBEDLY_KEY=${EMBEDLY_KEY}
      - ENABLE_CHAT_UPLOAD=${ENABLE_CHAT_UPLOAD}
      - EJABBERD_DOMAIN=${EJABBERD_DOMAIN}
      - EJABBERD_WS_URI=wss://${DOMAIN}/xmpp/ws
      - SENTRY_DSN=${SENTRY_DSN_CHAT}
      - SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT}
      - SENTRY_ORG=${SENTRY_ORG}
      - SENTRY_PROJECT=${SENTRY_PROJECT}
      - SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN}
      - SENTRY_RELEASE=${SENTRY_RELEASE}
      - SENTRY_TRACES_SAMPLE_RATE=${SENTRY_TRACES_SAMPLE_RATE}
    labels:
      traefik.enable: "true"
      traefik.http.middlewares.strip-chat-prefix.stripprefix.prefixes: "/chat"
      traefik.http.routers.chat.rule: "Host(`${DOMAIN}`) && PathPrefix(`/chat`)"
      traefik.http.routers.chat.middlewares: "strip-chat-prefix@docker"
      traefik.http.routers.chat.entryPoints: "web"
      traefik.http.services.chat.loadbalancer.server.port: "80"
      traefik.http.routers.chat-ssl.rule: "Host(`${DOMAIN}`) && PathPrefix(`/chat`)"
      traefik.http.routers.chat-ssl.middlewares: "strip-chat-prefix@docker"
      traefik.http.routers.chat-ssl.entryPoints: "websecure"
      traefik.http.routers.chat-ssl.service: "chat"
      traefik.http.routers.chat-ssl.tls: "true"
      traefik.http.routers.chat-ssl.tls.certresolver: "myresolver"


  back:
    image: thecodingmachine/workadventure-back:${VERSION}
    environment:
      - PLAY_URL=https://${DOMAIN}
      - SECRET_JITSI_KEY
      - ENABLE_MAP_EDITOR
      - SECRET_KEY
      - ADMIN_API_TOKEN
      - ADMIN_API_URL
      - TURN_SERVER
      - TURN_USER
      - TURN_PASSWORD
      - TURN_STATIC_AUTH_SECRET
      - STUN_SERVER
      - JITSI_URL
      - JITSI_ISS
      - BBB_URL
      - BBB_SECRET
      - MAX_PER_GROUP
      - STORE_VARIABLES_FOR_LOCAL_MAPS
      - REDIS_HOST=redis
      - PROMETHEUS_AUTHORIZATION_TOKEN
      - MAP_STORAGE_URL=map-storage:50053
      - INTERNAL_MAP_STORAGE_URL=http://map-storage:3000
      - PUBLIC_MAP_STORAGE_URL=https://${DOMAIN}/map-storage
      - PLAYER_VARIABLES_MAX_TTL
      - EJABBERD_API_URI
      - EJABBERD_DOMAIN=${EJABBERD_DOMAIN}
      - EJABBERD_USER=${EJABBERD_USER}
      - EJABBERD_PASSWORD=${EJABBERD_PASSWORD}
      - ENABLE_CHAT
      - ENABLE_CHAT_UPLOAD
      - SENTRY_DSN=${SENTRY_DSN_BACK}
      - SENTRY_RELEASE=${SENTRY_RELEASE}
      - SENTRY_TRACES_SAMPLE_RATE=${SENTRY_TRACES_SAMPLE_RATE}
    labels:
      traefik.enable: "true"
      traefik.http.middlewares.strip-api-prefix.stripprefix.prefixes: "/api"
      traefik.http.routers.back.rule: "Host(`${DOMAIN}`) && PathPrefix(`/api`)"
      traefik.http.routers.back.middlewares: "strip-api-prefix@docker"
      traefik.http.routers.back.entryPoints: "web"
      traefik.http.services.back.loadbalancer.server.port: "8080"
      traefik.http.routers.back-ssl.middlewares: "strip-api-prefix@docker"
      traefik.http.routers.back-ssl.rule: "Host(`${DOMAIN}`) && PathPrefix(`/api`)"
      traefik.http.routers.back-ssl.entryPoints: "websecure"
      traefik.http.routers.back-ssl.service: "back"
      traefik.http.routers.back-ssl.tls: "true"
      traefik.http.routers.back-ssl.tls.certresolver: "myresolver"
    restart: ${RESTART_POLICY}

  uploader:
    image: thecodingmachine/workadventure-uploader:${VERSION}
    environment:
      - UPLOADER_URL=https://${DOMAIN}/uploader
      #AWS
      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
      - AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
      - AWS_BUCKET=${AWS_BUCKET}
      - AWS_URL=${AWS_URL}
      - AWS_ENDPOINT=${AWS_ENDPOINT}
      #REDIS
      - REDIS_HOST=${UPLOADER_REDIS_HOST}
      - REDIS_PORT=${UPLOADER_REDIS_PORT}
      #CHAT
      - ADMIN_API_URL=${ADMIN_API_URL}
      - ENABLE_CHAT_UPLOAD=${ENABLE_CHAT_UPLOAD}
      - UPLOAD_MAX_FILESIZE=${UPLOAD_MAX_FILESIZE}
    labels:
      traefik.enable: "true"
      traefik.http.middlewares.strip-uploader-prefix.stripprefix.prefixes: "/uploader"
      traefik.http.routers.uploader.rule: "Host(`${DOMAIN}`) && PathPrefix(`/uploader`)"
      traefik.http.routers.uploader.middlewares: "strip-uploader-prefix@docker"
      traefik.http.routers.uploader.entryPoints: "web"
      traefik.http.services.uploader.loadbalancer.server.port: "8080"
      traefik.http.routers.uploader-ssl.middlewares: "strip-uploader-prefix@docker"
      traefik.http.routers.uploader-ssl.rule: "Host(`${DOMAIN}`) && PathPrefix(`/uploader`)"
      traefik.http.routers.uploader-ssl.entryPoints: "websecure"
      traefik.http.routers.uploader-ssl.service: "uploader"
      traefik.http.routers.uploader-ssl.tls: "true"
      traefik.http.routers.uploader-ssl.tls.certresolver: "myresolver"
    restart: ${RESTART_POLICY}

  icon:
    image: matthiasluedtke/iconserver:v3.15.0
    labels:
      traefik.enable: "true"
      traefik.http.middlewares.strip-icon-prefix.stripprefix.prefixes: "/icon"
      traefik.http.routers.icon.middlewares: "strip-icon-prefix@docker"
      traefik.http.routers.icon.rule: "Host(`${DOMAIN}`) && PathPrefix(`/icon`)"
      traefik.http.routers.icon.entryPoints: "web"
      traefik.http.services.icon.loadbalancer.server.port: "8080"
      traefik.http.routers.icon-ssl.middlewares: "strip-icon-prefix@docker"
      traefik.http.routers.icon-ssl.rule: "Host(`${DOMAIN}`) && PathPrefix(`/icon`)"
      traefik.http.routers.icon-ssl.entryPoints: "websecure"
      traefik.http.routers.icon-ssl.service: "icon"
      traefik.http.routers.icon-ssl.tls: "true"
      traefik.http.routers.icon-ssl.tls.certresolver: "myresolver"
    restart: ${RESTART_POLICY}

  redis:
    image: redis:6
    volumes:
      - redisdata:/data
    restart: ${RESTART_POLICY}

  ejabberd:
    image: workadventure/ejabberd:v1
    ports:
      - '5443:5443'
    environment:
      - CTL_ON_CREATE=register ${EJABBERD_USER} ${EJABBERD_DOMAIN} ${EJABBERD_PASSWORD}
      - JWT_SECRET=${EJABBERD_JWT_SECRET}
      - EJABBERD_DOMAIN=${EJABBERD_DOMAIN}
      - EJABBERD_USER=${EJABBERD_USER}
      - EJABBERD_PASSWORD=${EJABBERD_PASSWORD}
    volumes:
      - ../../xmpp/ejabberd.template.yml:/opt/ejabberd/conf/ejabberd.template.yml
    labels:
      traefik.enable: "true"
      traefik.http.middlewares.strip-ejabberd-prefix.stripprefix.prefixes: "/xmpp"
      traefik.http.routers.ejabberd.middlewares: "strip-ejabberd-prefix@docker"
      traefik.http.routers.ejabberd.rule: "Host(`${DOMAIN}`) && PathPrefix(`/xmpp`)"
      traefik.http.routers.ejabberd.entryPoints: "web"
      traefik.http.services.ejabberd.loadbalancer.server.port: "5443"
      traefik.http.routers.ejabberd-ssl.middlewares: "strip-ejabberd-prefix@docker"
      traefik.http.routers.ejabberd-ssl.rule: "Host(`${DOMAIN}`) && PathPrefix(`/xmpp`)"
      traefik.http.routers.ejabberd-ssl.entryPoints: "websecure"
      traefik.http.routers.ejabberd-ssl.service: "ejabberd"
      traefik.http.routers.ejabberd-ssl.tls: "true"
      traefik.http.routers.ejabberd-ssl.tls.certresolver: "myresolver"
    restart: ${RESTART_POLICY}

  map-storage:
    image: thecodingmachine/workadventure-map-storage:${VERSION}
    environment:
      API_URL: back:50051
      PROMETHEUS_AUTHORIZATION_TOKEN: "$PROMETHEUS_AUTHORIZATION_TOKEN"
      AUTHENTICATION_STRATEGY: "$MAP_STORAGE_AUTHENTICATION_STRATEGY"
      ENABLE_BEARER_AUTHENTICATION: "$MAP_STORAGE_ENABLE_BEARER_AUTHENTICATION"
      ENABLE_BASIC_AUTHENTICATION: "$MAP_STORAGE_ENABLE_BASIC_AUTHENTICATION"
      ENABLE_DIGEST_AUTHENTICATION: "$MAP_STORAGE_ENABLE_DIGEST_AUTHENTICATION"
      AUTHENTICATION_USER: "$MAP_STORAGE_AUTHENTICATION_USER"
      AUTHENTICATION_PASSWORD: "$MAP_STORAGE_AUTHENTICATION_PASSWORD"
      AUTHENTICATION_TOKEN: "$MAP_STORAGE_AUTHENTICATION_TOKEN"
      AUTHENTICATION_VALIDATOR_URL: "$MAP_STORAGE_AUTHENTICATION_VALIDATOR_URL"
      SENTRY_DSN: $SENTRY_DSN_MAPSTORAGE
      SENTRY_RELEASE: $SENTRY_RELEASE
      SENTRY_ENVIRONMENT: $SENTRY_ENVIRONMENT
      SENTRY_TRACES_SAMPLE_RATE: $SENTRY_TRACES_SAMPLE_RATE
      PATH_PREFIX: "/map-storage"
    volumes:
      - map-storage-data:/maps
    labels:
      traefik.enable: "true"
      traefik.http.middlewares.strip-map-storage-prefix.stripprefix.prefixes: "/map-storage"
      traefik.http.routers.map-storage.middlewares: "strip-map-storage-prefix@docker"
      traefik.http.routers.map-storage.rule: "Host(`${DOMAIN}`) && PathPrefix(`/map-storage`)"
      traefik.http.routers.map-storage.entryPoints: "web"
      traefik.http.services.map-storage.loadbalancer.server.port: "3000"
      traefik.http.routers.map-storage-ssl.middlewares: "strip-map-storage-prefix@docker"
      traefik.http.routers.map-storage-ssl.rule: "Host(`${DOMAIN}`) && PathPrefix(`/map-storage`)"
      traefik.http.routers.map-storage-ssl.entryPoints: "websecure"
      traefik.http.routers.map-storage-ssl.service: "map-storage"
      traefik.http.routers.map-storage-ssl.tls: "true"
      traefik.http.routers.map-storage-ssl.tls.certresolver: "myresolver"
    restart: ${RESTART_POLICY}

#  coturn:
#    image: coturn/coturn:4.5.2
#    command:
#      - turnserver
#      #- -c=/etc/coturn/turnserver.conf
#      - --log-file=stdout
#      - --external-ip=$$(detect-external-ip)
#      - --listening-port=3478
#      - --min-port=10000
#      - --max-port=10010
#      - --tls-listening-port=5349
#      - --listening-ip=0.0.0.0
#      - --realm=coturn.workadventure.localhost
#      - --server-name=coturn.workadventure.localhost
#      - --lt-cred-mech
#      # Enable Coturn "REST API" to validate temporary passwords.
#      #- --use-auth-secret
#      #- --static-auth-secret=SomeStaticAuthSecret
#      #- --userdb=/var/lib/turn/turndb
#      - --user=workadventure:WorkAdventure123
#      # use real-valid certificate/privatekey files
#      #- --cert=/root/letsencrypt/fullchain.pem
#      #- --pkey=/root/letsencrypt/privkey.pem
#    network_mode: host
docker compose up -d

Jitsi

cd /home/myusername/docker
mkdir jitsi && cd "$_"
mkdir -p ./jitsi-meet-cfg/{web/letsencrypt,transcripts,prosody/config,prosody/prosody-plugins-custom,jicofo,jvb,jigasi,jibri}
curl -sL $(curl -s https://api.github.com/repos/jitsi/docker-jitsi-meet/releases/latest | grep 'tarball_url' | cut -d\" -f4) -o docker-jitsi-meet-stable.tar.gz && tar -zxvf docker-jitsi-meet-stable.tar.gz && mv jitsi-docker-jitsi-meet-*/{*,.*} . && cp env.example .env && rm -rf docker-jitsi-meet-stable.tar.gz jitsi-docker-jitsi-meet-* 
nano .env
./gen-passwords.sh
docker compose up -d

Vaultwarden (passwd manager)

cd /home/myusername/docker
mkdir vaultwarden && cd "$_"

nano docker-compose.yml

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      DOMAIN: https://subdomain.DOMAIN.COM
      LOGIN_RATELIMIT_MAX_BURST: 10
      LOGIN_RATELIMIT_SECONDS: 60
      ADMIN_RATELIMIT_MAX_BURST: 10
      ADMIN_RATELIMIT_SECONDS: 60
      ADMIN_TOKEN: YourReallyStrongAdminTokenHere
      SENDS_ALLOWED: true
      EMERGENCY_ACCESS_ALLOWED: true
      WEB_VAULT_ENABLED: true
      SIGNUPS_ALLOWED: false
      SIGNUPS_VERIFY: true
      SIGNUPS_VERIFY_RESEND_TIME: 3600
      SIGNUPS_VERIFY_RESEND_LIMIT: 5
      SIGNUPS_DOMAINS_WHITELIST: DOMAIN.COM,YOURSECONDDOMAIN.COM
      SMTP_HOST: smtp.DOMAIN.COM
      SMTP_FROM: [email protected]
      SMTP_FROM_NAME: Vaultwarden
      SMTP_SECURITY: starttls # Possible values: “starttls” / “force_tls” / “off”
      SMTP_PORT: 587 # Possible values: 587 / 465
      SMTP_USERNAME: [email protected]
      SMTP_PASSWORD: emailpasswordhere
      SMTP_AUTH_MECHANISM: Plain # Possible values: “Plain” / “Login” / “Xoauth2”
    volumes:
      - ./data/:/data/
    ports:
      - 9200:80
docker compose up -d

Rocket.Chat (Chat server)

cd /home/myusername/docker
mkdir rocketchat
cd rocketchat

nano docker-compose.yml

services:
  rocketchat:
    image: rocketchat/rocket.chat:latest
    container_name: rocketchat
    restart: unless-stopped
    command: >
      bash -c
        "for i in `seq 1 30`; do
          node main.js &&
          s=$$? && break || s=$$?;
          echo \"Tried $$i times. Waiting 5 secs...\";
          sleep 5;
        done; (exit $$s)"
    environment:
      PORT: 3000
      ROOT_URL: http://localhost:3000
      MONGO_URL: mongodb://mongo:27017/rocketchat
      MONGO_OPLOG_URL: mongodb://mongo:27017/local
      MAIL_URL: smtp://smtp.email
#      HTTP_PROXY: http://proxy.DOMAIN.COM
#      HTTPS_PROXY: http://proxy.DOMAIN.COM
    volumes:
      - ./uploads:/app/uploads
    ports:
      - 8152:3000
    depends_on:
      - mongo
      
  mongo:
    image: mongo:4.0
    container_name: rocketchat-mongo
    restart: unless-stopped
    command: mongod --smallfiles --oplogSize 128 --replSet rs0 --storageEngine=mmapv1
    volumes:
     - ./data/db:/data/db
     #- ./data/dump:/dump

  # this container's job is just run the command to initialize the replica set.
  # it will run the command and remove himself (it will not stay running)
  mongo-init-replica:
    image: mongo:4.0
    command: >
      bash -c
        "for i in `seq 1 30`; do 
            mongo mongo/rocketchat --eval \"
            rs.initiate({
              _id: 'rs0',
              members: [ { _id: 0, host: 'localhost:27017' } ]})\" &&
          s=$$? && break || s=$$?;
          echo \"Tried $$i times. Waiting 5 secs...\";
          sleep 5;
        done; (exit $$s)"
    depends_on:
      - mongo
docker compose up -d

Matrix (Chat server)

cd /home/myusername/docker
mkdir synapse && cd "$_"
docker run -it --rm -v ./data:/data -e SYNAPSE_SERVER_NAME=<your-intended-url> -e SYNAPSE_REPORT_STATS=no matrixdotorg/synapse:latest generate
cd /home/myusername/docker/synapse/data

nano homeserver.yaml

line 68:  public_baseurl: https://chat.DOMAIN.COM/
line 83: enabled: false
line 116: allow_public_rooms_over_federation: true
line 126: default_room_version: "6"
line 159: enable_search: true
line 1151: enable_registration: true
line 2095: smtp_host: mail.DOMAIN.COM
line 2099: smtp_port: 587
line 2104: smtp_user: "[email protected]"
line 2105: smtp_pass: "REPLACE_WITH_YOUR_EMAIL_PASSWORD"
TLS via STARTTLS *if the SMTP server supports it* line 2112: require_transport_security: true 
line 2132: notif_from: "Your Friendly %(app)s homeserver <[email protected]>"
line 2137: app_name: my_branded_matrix_server
line 2142: enable_notifs: true
line 2147: notif_for_new_users: true
line 2166: invite_client_location: https://app.element.io

nano docker-compose.yml

services:
  synapse:
    image: matrixdotorg/synapse:latest
    container_name: synapse
    restart: unless-stopped
    volumes:
      - ./data:/data
    ports:
      - 8150:8008
      - 8151:443

To make yourself an admin, you will need to create a new account using ELEMENT then install sqlite3 on your linux machine.
Download the client: https://element.io/download

cd /home/myusername/docker/synapse/data
apt install sqlite3
sqlite3 homeserver.db
SELECT * FROM users;
UPDATE users SET admin=1 WHERE name= '@myusername:myserver.com';
.quit

Matrix clients

Debian:

apt update
apt install matrix-mirage

Arch Linux:

yay -S matrix-mirage

Windows:
https://element.io/get-started#download

IOS:
https://matrix.org/docs/projects/client/element-ios

Android:
https://matrix.org/docs/projects/client/element-android

Zulip (Chat server)

cd /home/myusername/docker
git clone https://github.com/zulip/docker-zulip.git
cd docker-zulip

If you use zulip with Cloudflare tunnel make sure to add DISABLE_HTTPS=True in the zulip environment docker-compose.yml file
and remove SSL_CERTIFICATE_GENERATION: "self-signed"

nano docker-compose.yml

services:
  db:
    image: zulip/zulip-postgresql:14
    container_name: zulip-postgresql
    restart: unless-stopped
    environment:
      POSTGRES_DB: zulip
      POSTGRES_USER: zulip
      # Note that you need to do a manual `ALTER ROLE` query if you
      # change this on a system after booting the postgres container
      # the first time on a host.  Instructions are available in README.md.
      POSTGRES_PASSWORD: zulip!
    volumes:
      - ./db:/var/lib/postgresql/data:rw
      
  memcached:
    image: memcached:alpine
    container_name: zulip-memcached
    restart: unless-stopped
    command:
      - "sh"
      - "-euc"
      - |
        echo 'mech_list: plain' > "$$SASL_CONF_PATH"
        echo "zulip@$$HOSTNAME:$$MEMCACHED_PASSWORD" > "$$MEMCACHED_SASL_PWDB"
        echo "zulip@localhost:$$MEMCACHED_PASSWORD" >> "$$MEMCACHED_SASL_PWDB"
        exec memcached -S
    environment:
      SASL_CONF_PATH: /home/memcache/memcached.conf
      MEMCACHED_SASL_PWDB: /home/memcache/memcached-sasl-db
      MEMCACHED_PASSWORD: zulip!

      
  rabbitmq:
    image: rabbitmq:3.7.7
    container_name: zulip-rabbitmq
   restart: unless-stopped
    environment:
      RABBITMQ_DEFAULT_USER: zulip
      RABBITMQ_DEFAULT_PASS: zulip!
    volumes:
      - ./rabbitmq:/var/lib/rabbitmq:rw
 
     
  redis:
    image: redis:alpine
    container_name: zulip-redis
    restart: unless-stopped
    command:
      - "sh"
      - "-euc"
      - |
        echo "requirepass '$$REDIS_PASSWORD'" > /etc/redis.conf
        exec redis-server /etc/redis.conf
    environment:
      REDIS_PASSWORD: zulip!
    volumes:
      - ./redis:/data:rw

      
  zulip:
    image: zulip/docker-zulip:6.0-0
    container_name: zulip
    restart: unless-stopped
    build:
      context: .
      args:
        # Change these if you want to build zulip from a different repo/branch
        ZULIP_GIT_URL: https://github.com/zulip/zulip.git
        ZULIP_GIT_REF: 6.0
        # Set this up if you plan to use your own CA certificate bundle for building
        # CUSTOM_CA_CERTIFICATES:
    environment:
      DB_HOST: database
      DB_HOST_PORT: 5432
      DB_USER: zulip
      SSL_CERTIFICATE_GENERATION: self-signed
      SETTING_MEMCACHED_LOCATION: memcached:11211
      SETTING_RABBITMQ_HOST: rabbitmq
      SETTING_REDIS_HOST: redis
      # These should match RABBITMQ_DEFAULT_PASS, POSTGRES_PASSWORD,
      # MEMCACHED_PASSWORD, and REDIS_PASSWORD above.
      SECRETS_rabbitmq_password: zulip!
      SECRETS_postgres_password: zulip!
      SECRETS_memcached_password: zulip!
      SECRETS_redis_password: zulip!
      SECRETS_secret_key: zulip!
      SETTING_EXTERNAL_HOST: zulip.DOMAIN.COM
      SETTING_ZULIP_ADMINISTRATOR: [email protected]
      SETTING_EMAIL_HOST: mail.DOMAIN.COM
      SETTING_EMAIL_HOST_USER: [email protected]
      SECRETS_email_password: REPLACE_WITH_YOUR_EMAIL_PASSWORD
      SETTING_EMAIL_PORT: 587
      # It seems that the email server needs to use ssl or tls and can't be used without it
      SETTING_EMAIL_USE_SSL: False
      SETTING_EMAIL_USE_TLS: True
      ZULIP_AUTH_BACKENDS: EmailAuthBackend
      # Uncomment this when configuring the mobile push notifications service
      # SETTING_PUSH_NOTIFICATION_BOUNCER_URL: https://push.zulipchat.com
    ulimits:
      nofile:
        soft: 1000000
        hard: 1048576
    volumes:
      - ./data:/data:rw
    ports:
      - 8157:80
      - 8158:443
docker compose up -d

Configure zulip

docker exec -it zulip_zulip_1 /bin/bash
cd /home/zulip/deployments/current/
su zulip
./manage.py generate_realm_creation_link

Troubleshoot zulip

Sending a test email

docker exec -it zulip_zulip_1 /bin/bash
su zulip -c '/home/zulip/deployments/current/manage.py send_test_email [email protected]'

Uptime-Kuma

cd /home/myusername/docker
mkdir uptime-kuma && cd "$_"

nano docker-compose.yml

services:
  uptimekuma:
    image: louislam/uptime-kuma:latest
    container_name: uptimekuma
    restart: unless-stopped
    volumes:
      - ./data:/app/data
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - 8160:3001
docker compose up -d

Mailcow (E-mail server)

sudo su
cd /opt
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
./generate_config.sh

mail.DOMAIN.COM
utc

nano mailcow.conf

docker compose up -d

 

Seafile (filehoster)

cd /home/myusername/docker
mkdir seafile && cd "$_" && mkdir onlyoffice && touch onlyoffice/local.conf

nano docker-compose.yml

services:
  seafile-db:
    image: mariadb:latest
    container_name: seafile_mariadb
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: seafile!
      MYSQL_LOG_CONSOLE: true
    volumes:
      - ./db:/var/lib/mysql
    ports:
      - "9308:3306"
    networks:
      - seafile-net

  seafile:
    image: seafileltd/seafile-mc:11.0-latest
    container_name: seafile
    restart: unless-stopped
    environment:
      DB_HOST: seafile-db
      DB_ROOT_PASSWD: seafile!
      TIME_ZONE: Etc/UTC
      SEAFILE_ADMIN_EMAIL: [email protected]
      SEAFILE_ADMIN_PASSWORD: seafile
      SEAFILE_SERVER_LETSENCRYPT: false
      SEAFILE_SERVER_HOSTNAME: seafile.DOMAIN.COM
    volumes:
      - ./data:/shared
    ports:
      - "8240:80"
    depends_on:
      - seafile-db
      - seafile-memcached
    networks:
      - seafile-net
  
  seafile-memcached:
    image: memcached:1.6
    container_name: seafile_memcached
    restart: unless-stopped
    command: memcached -m 256
    networks:
      - seafile-net

  onlyoffice-postgresql:
    image: postgres:12
    container_name: seafile_onlyoffice_postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: onlyoffice
      POSTGRES_USER: onlyoffice
      POSTGRES_HOST_AUTH_METHOD: trust
    volumes:
      - ./onlyoffice/db:/var/lib/postgresql
    ports:
      - "9310:5432"
    networks:
      - seafile-net

  onlyoffice-documentserver:
    image: onlyoffice/documentserver:latest
    container_name: seafile_onlyoffice_ds
    restart: unless-stopped
    environment:
      DB_TYPE: postgres
      DB_HOST: onlyoffice-postgresql
      DB_PORT: 5432
      DB_USER: onlyoffice
      DB_NAME: onlyoffice
      AMQP_URI: amqp://guest:guest@onlyoffice-rabbitmq
      # Uncomment strings below to enable the JSON Web Token validation.
      JWT_ENABLED: true
      JWT_SECRET: onlyoffice
      JWT_HEADER: Authorization
      JWT_IN_BODY: true
    volumes:
      # Optional: see https://manual.seafile.com/deploy/only_office/
      #- ./onlyoffice/local.json:/etc/onlyoffice/documentserver/local.json
      #- ./onlyoffice/local-production-linux.json:/etc/onlyoffice/documentserver/local-production-linux.json
      - ./onlyoffice/data:/var/www/onlyoffice/Data
      - ./onlyoffice/lib:/var/lib/onlyoffice
      - ./onlyoffice/logs:/var/log/onlyoffice
    ports:
      - "8243:80"
    networks:
      - seafile-net

  onlyoffice-rabbitmq:
    image: rabbitmq:latest
    container_name: seafile_onlyoffice_rabbitmq
    restart: unless-stopped
    volumes:
        - ./onlyoffice/rabbitmq/data:/var/lib/rabbitmq/
        - ./onlyoffice/rabbitmq/log:/var/log/rabbitmq
    networks:
      - seafile-net

networks:
  seafile-net:
    external: true
docker compose up -d

Configure Seafile

Default login
Username: [email protected]
Password: seafile


At the dashboard:
System admin -> Users -> Add User
Admin -> Add Admin

OnlyOffice Integration

Add the following config at the bottom to seahub_settings.py

# OnlyOffice
ENABLE_ONLYOFFICE = True
VERIFY_ONLYOFFICE_CERTIFICATE = False
ONLYOFFICE_APIJS_URL = 'https://YOUR_ONLYOFFICE_DOMAIN_HERE/web-apps/apps/api/documents/api.js'
ONLYOFFICE_FILE_EXTENSION = ('doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'odt', 'fodt', 'odp', 'fodp', 'ods', 'fods')
ONLYOFFICE_EDIT_FILE_EXTENSION = ('docx', 'pptx', 'xlsx')

# "Force Save" to allow users to save files when pressing the save button on the OnlyOffice file edit page.
ONLYOFFICE_FORCE_SAVE = True

# JWT secret can be used to secure your OnlyOffice server so other people will not be able to use it.
ONLYOFFICE_JWT_SECRET = 'onlyoffice'

Replace the following config at seafile.nginx.conf

# -*- mode: nginx -*-
# Auto generated at 02/12/2024 14:23:06

# Required for only office document server
map $http_x_forwarded_proto $the_scheme {
    default $http_x_forwarded_proto;
    "" $scheme;
}

map $http_x_forwarded_host $the_host {
    default $http_x_forwarded_host;
    "" $host;
}

map $http_upgrade $proxy_connection {
    default upgrade;
    "" close;
}

server {
listen 80;
server_name seafile.DOMAIN.COM;

    client_max_body_size 10m;

    location / {
        proxy_pass http://127.0.0.1:8000/;
        proxy_read_timeout 310s;
        proxy_set_header Host $http_host;
        proxy_set_header Forwarded "for=$remote_addr;proto=$scheme";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Connection "";
        proxy_http_version 1.1;

        client_max_body_size 0;
        access_log      /var/log/nginx/seahub.access.log seafileformat;
        error_log       /var/log/nginx/seahub.error.log;
    }

    location /seafhttp {
        rewrite ^/seafhttp(.*)$ $1 break;
        proxy_pass http://127.0.0.1:8082;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 0;
        proxy_connect_timeout  36000s;
        proxy_read_timeout  36000s;
        proxy_request_buffering off;
        access_log      /var/log/nginx/seafhttp.access.log seafileformat;
        error_log       /var/log/nginx/seafhttp.error.log;
    }

    location /onlyofficeds/ {
        # THIS ONE IS IMPORTANT ! - Trailing slash !
        proxy_pass http://127.0.0.1:8243/;

        proxy_http_version    1.1;
        client_max_body_size  100M; # Limit Document size to 100MB
        proxy_read_timeout    3600s;
        proxy_connect_timeout 3600s;
        proxy_set_header      Upgrade $http_upgrade;
        proxy_set_header      Connection $proxy_connection;

        # THIS ONE IS IMPORTANT ! - Subfolder and NO trailing slash !
        proxy_set_header X-Forwarded-Host $the_host/onlyofficeds;

        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Forwarded "for=$remote_addr;proto=https";

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        access_log /var/log/nginx/onlyoffice.access.log seafileformat;
        error_log  /var/log/nginx/onlyoffice.error.log;
    }

    location /notification/ping {
        proxy_pass http://127.0.0.1:8083/ping;
        access_log      /var/log/nginx/notification.access.log seafileformat;
        error_log       /var/log/nginx/notification.error.log;
    }

    location /notification {
        proxy_pass http://127.0.0.1:8083/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        access_log      /var/log/nginx/notification.access.log seafileformat;
        error_log       /var/log/nginx/notification.error.log;
    }

    location /seafdav {
        proxy_pass         http://127.0.0.1:8080;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_read_timeout  1200s;
        client_max_body_size 0;

        access_log      /var/log/nginx/seafdav.access.log seafileformat;
        error_log       /var/log/nginx/seafdav.error.log;
    }

    location /media {
        root /opt/seafile/seafile-server-latest/seahub;
    }


    location ~ /\.git {
        deny all;
    }

    # Optional error pages remove if not needed
    error_page 403 /forbidden.html;
    location = /forbidden.html {
        root /var/www/html;
        internal;
    }

    # Optional error pages remove if not needed
    error_page 502 /maintenance.html;
    error_page 504 /maintenance.html;
    error_page 500 /maintenance.html;
    location = /maintenance.html {
        root /usr/share/nginx/html;
        internal;
    }

}

Librespeed

cd /home/myusername/docker
mkdir librespeed && cd "$_"

nano docker-compose.yml

services:
  librespeed:
    image: lscr.io/linuxserver/librespeed:latest
    container_name: librespeed
    restart: unless-stopped
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Etc/UTC
      PASSWORD: librespeed
      CUSTOM_RESULTS: false #optional
#      DB_TYPE: sqlite #optional
#      DB_NAME: librespeed #optional
#      DB_HOSTNAME: db #optional
#      DB_USERNAME: librespeed #optional
#      DB_PASSWORD: librespeed! #optional
#      IPINFO_APIKEY: ACCESS_TOKEN #optional
    volumes:
      - ./config:/config
    ports:
      - 8161:80
docker compose up -d

 

PufferPanel

cd /home/myusername/docker
mkdir pufferpanel && cd "$_"

nano docker-compose.yml

services:
  pufferpanel:
    image: pufferpanel/pufferpanel:latest
    container_name: pufferpanel
    restart: unless-stopped
    volumes:
      - ./config:/etc/pufferpanel
      - ./servers:/var/lib/pufferpanel
    ports:
      - 8185:8080
      - 8186:5657
      - 25565:25565 # Example port used for a minecraft server
docker compose up -d
docker exec -it pufferpanel /pufferpanel/pufferpanel user add

Zitadel

cd /home/myusername/docker
mkdir zitadel && cd "$_"

nano docker-compose.yml

services:
  zitadel:
    image: ghcr.io/zitadel/zitadel:latest
    container_name: zitadel
    restart: unless-stopped
    command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled'
    environment:
      ZITADEL_DATABASE_COCKROACH_HOST: crdb
      ZITADEL_EXTERNALSECURE: false
    depends_on:
      crdb:
        condition: 'service_healthy'
    ports:
      - 9165:8080
    networks:
      - zitadel

  crdb:
    image: cockroachdb/cockroach:latest
    container_name: zitadel-cockroachdb
    restart: unless-stopped
    command: 'start-single-node --insecure'
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health?ready=1"]
      interval: '10s'
      timeout: '30s'
      retries: 5
      start_period: '20s'
    ports:
      - 9311:8080
      - 26257:26257
    networks:
      - zitadel

networks:
  zitadel:

Configure zitadel

Default login at http://IMPORT_ZITADEL_URL_HERE:9165/ui/console:
Username: [email protected]
Password: Password1!

Authelia (2FA)

cd /home/myusername/docker
mkdir -p authelia/{config,redis}

nano docker-compose.yml

services:
  authelia:
    image: authelia/authelia
    container_name: authelia
    restart: unless-stopped
    healthcheck:
      disable: true
    environment:
      TZ: Etc/UTC
    volumes:
      - ./config:/config
    ports:
      - 6190:9091
    depends_on:
      - redis

  redis:
    image: redis:alpine
    container_name: authelia-redis
    restart: unless-stopped
    environment:
      TZ: Etc/UTC
    volumes:
      - ./redis:/data
    ports:
      - 6379:6379
cd config

nano users_database.yml

users:
  john:
    displayname: "John Doe"
    password: "$argon2id$v=19$m=65536,t=3,p=2$BpLnfgDsc2WD8F2q$o/vzA4myCqZZ36bUGsDY//8mKUYNZZaR0t4MFFSs+iM"
    email: [email protected]
    groups:
      - admins
      - dev
  harry:
    displayname: "Harry Potter"
    password: "$argon2id$v=19$m=65536,t=3,p=2$BpLnfgDsc2WD8F2q$o/vzA4myCqZZ36bUGsDY//8mKUYNZZaR0t4MFFSs+iM"
    email: [email protected]
    groups: []

nano configuration.yml

##############################################################
#                   Authelia configuration                    #
###############################################################

host: 0.0.0.0
port: 9091 # change this if you changed it in the docker-compose file
log_level: info
jwt_secret: some-other-long-string-of-letters-and-numbers-in-mixed-case
default_redirection_url: https://auth.example.com
totp:
  issuer: example.com
  period: 30
  skew: 1

#duo_api:     ## You can use this api if you want push notifications of auth attempts
#  hostname: api-123456789.example.com
#  integration_key: ABCDEF
#  secret_key: yet-another-long-string-of-characters-and-numbers-and-symbols

authentication_backend:
  disable_reset_password: false
  file:
    path: /config/users_database.yml # create this file !IMPORTANT!
    password:
      algorithm: argon2id
      iterations: 1
      salt_length: 16
      parallelism: 8
      memory: 64

access_control:
  default_policy: deny # NOTE: all domains added in NPM rules will be denied unless added below
  rules:
    # Rules applied to everyone
    - domain:
        - "movies.example.com"
        - "auth.example.com"
      policy: bypass
    - domain:
        - "dashboard.example.com"
        - "search.example.com"
        - "example.com"
      policy: one_factor
#      networks:
#        - 192.168.1.0/24
    - domain:
        - "ntop.example.com"
      policy: two_factor
#      networks:
         - 192.168.1.0/24
         
session:
  name: authelia_session
  # This secret can also be set using the env variables AUTHELIA_SESSION_SECRET_FILE
  secret: <some-long-mix-set-of-numbers-and-letters-upper-and-lower-case>
  expiration: 3600 # 1 hour
  inactivity: 7200 # 2 hours
  domain: your-domain.org # Should match whatever your root protected domain is

  redis:
    host: authelia_redis_1
    port: 6379
    # This secret can also be set using the env variables AUTHELIA_SESSION_REDIS_PASSWORD_FILE
#    password: authelia

regulation:
  max_retries: 3
  find_time: 2m
  ban_time: 10m

theme: dark   # options: dark, light

storage:
  local:
    path: /config/db.sqlite3
    
notifier:
#  filesystem:
#    filename: /config/notification.txt
  smtp:
    username: [email protected]
    password: REPLACE_WITH_YOUR_EMAIL_PASSWORD
    host: mail.DOMAIN.COM
    port: 587  # 25 non-ssl, 443 ssl, 587 tls
    sender: [email protected]
    subject: "[Authelia] {title}"
    disable_require_tls: false # set to true if your domain uses no tls or ssl only
    disable_html_emails: false # set to true if you don't want html in your emails
    tls:
      server_name: <your-email-host-url-or-ip>
      skip_verify: false
      minimum_version: TLS1.2

 

Nginx (static html website)

cd /home/myusername/docker
mkdir -p nginx/{www,config} && cd nginx/www
mkdir website01
docker run --name tmp-nginx-container -d nginx
docker cp tmp-nginx-container:/etc/nginx/nginx.conf /home/myusername/docker/nginx/config/nginx.conf
docker rm -f tmp-nginx-container

nano docker-compose.yml

services:
  nginx_website01:
    image: nginx
    container_name: nginx_website01
    restart: unless-stopped
    volumes:
      - ./www/website01:/usr/share/nginx/html
      - ./config/nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - 8173:80
docker compose up -d

Strapi

cd /home/myusername/docker
mkdir strapi && cd "$_"

nano docker-compose.yml

services:
  strapi:
    image: strapi:latest
    container_name: strapi
    restart: unless-stopped
    environment:
      DB_CLIENT: "pg"
      DB_HOST: "db"
      DB_PORT: "5432"
      DB_DATABASE: "strapi"
      DB_USER: "strapi"
      DB_PASSWORD: "strapi"
      JWT_SECRET: "e3b1c83f5f7b42f9a3f678d55dcd96d3b7e78d3e"
      ADMIN_JWT_SECRET: "c5a8b2d7f4a9459e9d2e67a89b3c2f8a6e3d5c4f"
      APP_KEYS: "fd7e9c3b2d8a5f6e4b7c2a9d5e8f3b6a,4a9d7f6e2c8b5d3e7f2a9c4b6e8d3f7a"
      NODE_ENV: production
    volumes:
#      - ./config:/opt/app/config
#      - ./src:/opt/app/src
#      - ./package.json:/opt/package.json
#      - ./yarn.lock:/opt/yarn.lock
#      - ./.env:/opt/app/.env
#      - ./public/uploads:/opt/app/public/uploads
    ports:
      - "8178:1337"
    depends_on:
      - db

  db:
    image: postgis/postgis:latest
    container_name: strapi_postgresql
    restart: unless-stopped
    # Required when running on platform other than amd64, like Apple M1/M2:
    # platform: linux/amd64
    volumes:
      - ./db:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: "strapi"
      POSTGRES_PASSWORD: "strapi"
      POSTGRES_DB: "strapi"
docker compose up -d

Wordpress

cd /home/myusername/docker
mkdir wordpress && cd "$_"

nano docker-compose.yml

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress01
    restart: unless-stopped
    environment:
      WORDPRESS_DB_NAME: wpdocker
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress!
      WORDPRESS_DB_HOST: db
    volumes:
      - ./www/YOUREWEBSITENAME:/var/www/html
    ports:
      - 8172:80
    depends_on:
      - db

  db:
    image: mariadb:latest
    container_name: wordpress01_mariadb
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: wpdocker
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress!
      MYSQL_ROOT_PASSWORD: wordpress!!
    volumes:
      - ./www/db:/var/lib/mysql
docker compose up -d

Configure Wordpress

Edit htaccess

cd /home/myusername/docker/wordpress/www/YOURDOMAIN
nano .htaccess
php_value upload_max_filesize 64M
php_value post_max_size 64M
php_value max_execution_time 300
php_value max_input_time 300

Improve security

cd /home/myusername/docker/wordpress/www/YOURDOMAIN/wp-content/themes/YOURACTIVETHEME
nano functions.php
add_filter( 'rest_authentication_errors', function( $result ) {
    // If a previous authentication check was applied,
    // pass that result along without modification.
    if ( true === $result || is_wp_error( $result ) ) {
        return $result;
    }

    // No authentication has been performed yet.
    // Return an error if user is not logged in.
    if ( ! is_user_logged_in() ) {
        return new WP_Error(
            'rest_not_logged_in',
            __( 'You are not currently logged in.' ),
            array( 'status' => 401 )
        );
    }

    // Our custom authentication check should have no effect
    // on logged-in requests
    return $result;
});

remove_action('wp_head', 'rsd_link');
remove_action('wp_head', 'wlwmanifest_link');
remove_action('wp_head', 'wp_generator');
remove_action('wp_head', 'start_post_rel_link');
remove_action('wp_head', 'index_rel_link');
remove_action('wp_head', 'adjacent_posts_rel_link');

Verify if the endpoint returns a "status":401 JSON response by calling it from your browser.
https://DOMAIN.COM/wp-json/wp/v2/users/

Webtop (webdesktop)

cd /home/myusername/docker
mkdir webtop && cd "$_"

nano docker-compose.yml

services:
  webtop:
    image: lscr.io/linuxserver/webtop
    container_name: webtop
    restart: unless-stopped
    privileged: true
    shm_size: 1gb
    devices:
      - /dev/dri:/dev/dri
    security_opt:
      - seccomp=unconfined
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Etc/UTC
      SUBFOLDER: /
      KEYBOARD: en-us-qwerty
      TITLE: Webtop
    volumes:
      - ./config:/config
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - 8211:3000
docker compose up -d

Webtop Ubuntu-KDE image:

nano docker-compose.yml

services:
  webtop:
    image: lscr.io/linuxserver/webtop:ubuntu-kde
    container_name: webtop-ubuntu-kde
    restart: unless-stopped
    privileged: true
    shm_size: 1gb
    devices:
      - /dev/dri:/dev/dri
    security_opt:
      - seccomp=unconfined
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Etc/UTC
      SUBFOLDER: /
      KEYBOARD: en-us-qwerty
      TITLE: Webtop-Ubuntu-KDE
    volumes:
      - ./config:/config
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - 8211:3000
docker compose up -d

Configure Webtop

Default login
Username: abc
Password: abc

Mango (pdf, epubs)

cd /home/myusername/docker
mkdir mango && cd "$_"

nano docker-compose.yml

services:
  mango:
    image: hkalexling/mango
    container_name: mango
    restart: unless-stopped
    volumes:
      - ./data:/root/mango
      - ./config:/root/.config/mango
    ports:
      - 8135:9000
docker compose up -d

Filebrowser

cd /home/myusername/docker
mkdir filebrowser && cd "$_"
mkdir config database srv
cd config
touch filebrowser.db
cd database
touch settings.json

nano docker-compose.yml

services:
  filebrowser:
    image: filebrowser/filebrowser:latest
    container_name: filebrowser
    restart: unless-stopped
    environment:
      PUID: 1000
      PGID: 1000
    volumes:
      - ./srv:/srv
      - ./database/filebrowser.db:/database.db 
      - ./config/filebrowser.json:/filebrowser.json
    ports:
      - 8131:80
docker compose up -d

 

UVDesk (Service Management)

cd /home/myusername/docker
mkdir uvdesk && cd "$_"

nano docker-compose.yml

services:
  uvdesk:
    image: nuttcorp/uvdesk:latest
    container_name: uvdesk
    restart: unless-stopped
    tty: true
    environment:
      MYSQL_DATABASE: uvdesk
      MYSQL_USER: uvdesk
      MYSQL_PASSWORD: uvdesk!
      MYSQL_ROOT_PASSWORD: uvdesk!!
    ports:
        - 8221:80
    depends_on:
      - db

  db:
    image: "mysql:5.7"
    container_name: uvdesk-mysql
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: uvdesk
      MYSQL_USER: uvdesk
      MYSQL_PASSWORD: uvdesk!
      MYSQL_ROOT_PASSWORD: uvdesk!!
    volumes:
      - ./db:/var/lib/mysql
docker compose up -d

UVDesk config

Database Configuration
Server: uvdesk_db_1
Port: 3306
Username: root
Password: uvdesk
Database: uvdesk

Create Super Admin Account
Name: superroot
Email: [email protected]
Password: uvdesk!
Confirm Password: uvdesk!

Website Configuration
Member Panel Prefix: agent
Customer Panel Prefix: customer

Glpi (IT Service Management)

cd /home/myusername/docker
mkdir glpi && cd "$_"

nano docker-compose.yml

services:
  db:
    image: mariadb:10.7
    container_name: glpi-mariadb
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: glpi
      MARIADB_USER: glpi
      MARIADB_PASSWORD: glpi!
      MARIADB_ROOT_PASSWORD: glpi!!
    volumes:
      - ./db:/var/lib/mysql

  glpi:
    image: diouxx/glpi
    container_name: glpi
    restart: unless-stopped
    environment:
      TIMEZONE: Etc/UTC
    volumes:
      - ./data:/var/www/html/glpi
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 8222:80

docker compose up -d

Configure Glpi

Database connection parameters
SQL Server (MariaDB or MySQL): container_name
SQL User: MYSQL_USER
SQL Password: MYSQL_PASSWORD

Default logins
Administrator: glpi/glpi
Technician: tech/tech
Normal: normal/normal
Postonly: post-only/postonly

Matomo (web visitor stats)

cd /home/myusername/docker
mkdir matomo && cd "$_"

nano db.env

MYSQL_PASSWORD=Welkom123!
MYSQL_DATABASE=matomo
MYSQL_USER=matomo
MATOMO_DATABASE_ADAPTER=mysql
MATOMO_DATABASE_TABLES_PREFIX=matomo_
MATOMO_DATABASE_USERNAME=matomo
MATOMO_DATABASE_PASSWORD=Welkom123!
MATOMO_DATABASE_DBNAME=matomo
MARIADB_AUTO_UPGRADE=1
MARIADB_INITDB_SKIP_TZINFO=1

nano matomo.conf

upstream php-handler {
	server app:9000;
}

server {
	listen 80;

	add_header Referrer-Policy origin; # make sure outgoing links don't show the URL to the Matomo instance
	root /var/www/html; # replace with path to your matomo instance
	index index.php;
	try_files $uri $uri/ =404;

	## only allow accessing the following php files
	location ~ ^/(index|matomo|piwik|js/index|plugins/HeatmapSessionRecording/configs).php {
		# regex to split $uri to $fastcgi_script_name and $fastcgi_path
		fastcgi_split_path_info ^(.+\.php)(/.+)$;

		# Check that the PHP script exists before passing it
		try_files $fastcgi_script_name =404;

		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_param PATH_INFO $fastcgi_path_info;
		fastcgi_param HTTP_PROXY ""; # prohibit httpoxy: https://httpoxy.org/
		fastcgi_pass php-handler;
	}

	## deny access to all other .php files
	location ~* ^.+\.php$ {
		deny all;
		return 403;
	}

	## disable all access to the following directories
	location ~ /(config|tmp|core|lang) {
		deny all;
		return 403; # replace with 404 to not show these directories exist
	}
	location ~ /\.ht {
		deny all;
		return 403;
	}

	location ~ js/container_.*_preview\.js$ {
		expires off;
		add_header Cache-Control 'private, no-cache, no-store';
	}

	location ~ \.(gif|ico|jpg|png|svg|js|css|htm|html|mp3|mp4|wav|ogg|avi|ttf|eot|woff|woff2|json)$ {
		allow all;
		## Cache images,CSS,JS and webfonts for an hour
		## Increasing the duration may improve the load-time, but may cause old files to show after an Matomo upgrade
		expires 1h;
		add_header Pragma public;
		add_header Cache-Control "public";
	}

	location ~ /(libs|vendor|plugins|misc/user) {
		deny all;
		return 403;
	}

	## properly display textfiles in root directory
	location ~/(.*\.md|LEGALNOTICE|LICENSE) {
		default_type text/plain;
	}
}

# vim: filetype=nginx

nano docker-compose.yml

services:
  app:
    image: matomo:fpm-alpine
    container_name: matomo-app
    restart: unless-stopped
    environment:
      MATOMO_DATABASE_HOST: db
      PHP_MEMORY_LIMIT: 2048M
    env_file:
      - ./db.env
    volumes:
#      - ./config:/var/www/html/config:rw
#      - ./logs:/var/www/html/logs
      - ./data:/var/www/html
    depends_on:
      - db

  db:
    image: mariadb:latest
    container_name: matomo-mariadb
    restart: unless-stopped
    command: --max-allowed-packet=64MB
    environment:
      MYSQL_ROOT_PASSWORD: REPLACE_WITH_MYSQL_PASSWORD_FROM_ENV
    env_file:
      - ./db.env
    volumes:
      - ./db:/var/lib/mysql

  web:
    image: nginx:alpine
    container_name: matomo-web
    restart: unless-stopped
    volumes:
      - ./data:/var/www/html:ro
      # see https://github.com/matomo-org/matomo-nginx
      - ./matomo.conf:/etc/nginx/conf.d/default.conf:ro
    ports:
      - 8165:80

docker compose up -d

fail2ban (spam blocker IP)

cd /home/myusername/docker
mkdir fail2ban && cd "$_"

nano docker-compose.yml

services:
  fail2ban:
    image: crazymax/fail2ban:latest
    container_name: fail2ban
    restart: unless-stopped
    network_mode: host
    cap_add:
      - NET_ADMIN
      - NET_RAW
    environment:
      TZ: Etc/UTC
      F2B_LOG_TARGET: STDOUT
      F2B_LOG_LEVEL: INFO
      F2B_DB_PURGE_AGE: 365d
      SSMTP_HOST: mail.DOMAIN.COM
      SSMTP_PORT: 587
      SSMTP_HOSTNAME: DOMAIN.COM
      SSMTP_USER: [email protected]
      SSMTP_PASSWORD: REPLACE_WITH_YOUR_EMAIL_PASSWORD
      SSMTP_TLS: YES
    volumes:
      - /home/myusername/docker/fail2ban/data:/data
      - /home/myusername/docker/nginx-proxy-manager/data/logs/:/log/npm/:ro
      - /var/log/auth.log:/var/log/auth.log:ro

docker compose up -d

CrowdSec (spam blocker IP)

cd /home/myusername/docker
mkdir crowdsec
cd crowdsec
mkdir config

nano docker-compose.yml

services:
  crowdsec:
    image: crowdsecurity/crowdsec:latest
    container_name: crowdsec
    restart: unless-stopped
    environment:
      GID: "${GID-1000}"
      COLLECTIONS: "crowdsecurity/linux crowdsecurity/traefik"
    # depends_on:  #uncomment if running traefik in the same compose file
    #   - 'traefik'
    volumes:
      - ./config/acquis.yaml:/etc/crowdsec/acquis.yaml
      - crowdsec-db:/var/lib/crowdsec/data/
      - crowdsec-config:/etc/crowdsec/
      - traefik_traefik-logs:/var/log/traefik/:ro
    networks:
      - proxy

  bouncer-traefik:
    image: docker.io/fbonalair/traefik-crowdsec-bouncer:latest
    container_name: bouncer-traefik
    restart: unless-stopped
    environment:
      CROWDSEC_BOUNCER_API_KEY: komtlater
      CROWDSEC_AGENT_HOST: crowdsec:8080
    networks:
      - proxy # same network as traefik + crowdsec
    depends_on:
      - crowdsec
    
networks:
  proxy:
    external: true
    
volumes:
  crowdsec-db:
  crowdsec-config:
  traefik_traefik-logs: # this will be the name of the volume from trarfic logs
    external: true # remove if traefik is running on same stack
cd config

nano acquis.yml

filenames:
  - /var/log/traefik/*
labels:
  type: traefik
cd traefik
cd data

nano traefik.yml

api:
  dashboard: true
  debug: true
entryPoints:
  http:
    address: ":80"
    http:
      middlewares:
        - crowdsec-bouncer@file
  https:
    address: ":443"
    http:
      middlewares:
        - crowdsec-bouncer@file
serversTransport:
  insecureSkipVerify: true
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: /config.yml
certificatesResolvers:
  cloudflare:
    acme:
      email: [email protected]
      storage: acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
log:
  level: "INFO"
  filePath: "/var/log/traefik/traefik.log"
accessLog:
  filePath: "/var/log/traefik/access.log"
cd traefik

nano docker-compose.yml

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - 80:80
      - 443:443
    environment:
      CF_API_EMAIL: [email protected]
      CF_DNS_API_TOKEN: YOUR_API_TOKEN
      # - CF_API_KEY=YOUR_API_KEY
      # be sure to use the correct one depending on if you are using a token or key
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/traefik.yml:/traefik.yml:ro
      - ./data/acme.json:/acme.json
      - ./data/config.yml:/config.yml:ro
      - traefik-logs:/var/log/traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik-dashboard.local.example.com`)"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=USER:BASIC_AUTH_PASSWORD"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik-dashboard.local.example.com`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=local.example.com"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.local.example.com"
      - "traefik.http.routers.traefik-secure.service=api@internal"

networks:
  proxy:
    external: true
volumes:
  traefik-logs:
docker compose up -d
cd crowdsec
docker compose up -d
docker exec crowdsec cscli bouncers add bouncer-traefik

INSERT THE API KEY IN DOCKER-COMPOSE.YML OF CROWDSEC

nano docker-compose.yml

CROWDSEC_BOUNCER_API_KEY: place_the_api_key_here

docker compose up -d
cd traefik
cd data

nano config.yml

ADD THE FOLLOWING TO THE MIDDLEWARE CATEGORY:

    crowdsec-bouncer:
      forwardauth:
        address: http://bouncer-traefik:8080/api/v1/forwardAuth
        trustForwardHeader: true

nano traefik.yml

entryPoints:
  http:
    address: ":80"
    http:
      middlewares:
        - crowdsec-bouncer@file
  https:
    address: ":443"
    http:
      middlewares:
        - crowdsec-bouncer@file
docker compose up -d

Wiki.js (The current wiki you are on)

cd /home/myusername/docker
mkdir wikijs && cd "$_"

nano docker-compose.yml

services:
  wiki:
    image: ghcr.io/requarks/wiki:2
    container_name: wikijs
    restart: unless-stopped
    environment:
      DB_TYPE: postgres
      DB_HOST: db
      DB_PORT: 5432
      DB_USER: wikijs
      DB_PASS: wikijs!
      DB_NAME: wiki
    volumes:
      - ./data/content:/wiki/data/content
      - ./config:/config
    ports:
      - 8141:3000
    depends_on:
      - db

  db:
    image: postgres:11-alpine
    container_name: wikijs_postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: wiki
      POSTGRES_PASSWORD: wikijs!
      POSTGRES_USER: wikijs
    logging:
      driver: none
    volumes:
      - ./db:/var/lib/postgresql/data
docker compose up -d

Custom theme

body {
    background: #000
  }
  header {
    border-bottom: 1px solid #ccc
  }
  .v-navigation-drawer__content {
    --bkg: url("https://wallpaperaccess.com/full/797185.png");
    /*--bkg: url("https://mir-s3-cdn-cf.behance.net/project_modules/disp/451206106881743.5f9a1f8faa991.gif");*/
    --bkg-color: #171717;
    background: var(--bkg-color)!important;
    background-image: var(--bkg)!important;
    background-blend-mode: multiply;
    background-size: cover!important;
    background-attachment: fixed!important;
    background-repeat: no-repeat!important;
    background-position: center center!important;
  }
  .v-navigation-drawer__content::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    backdrop-filter: blur(5px);
  }
  #root .v-navigation-drawer__content div.v-list {
    background: 0 0!important;
    background-color: transparent!important
  }
  #root .v-application .grey.darken-4-d4,
  #root .v-application .grey.darken-5 {
    background: 0 0!important;
    background-color: transparent!important
  }

OpenProject (Project Management)

cd /home/myusername/docker
mkdir openproject && cd "$_"

nano docker-compose.yml

services:
  openproject:
    image: openproject/community:11
    container_name: openproject
    restart: unless-stopped
    environment:
      PUID: 998
      PGID: 100
      SECRET_KEY_BASE: koZirTof1faEzGv7vGyKugOq6RnpislI
    volumes:
      - ./config:/var/openproject/pgdata
      - ./assets:/var/openproject/assets
    ports:
      - 8204:80
docker compose up -d

LinkWarden

cd /home/myusername/docker
mkdir linkwarden && cd "$_"

To generate a NEXTAUTH_SECRET use the following command:

openssl rand -hex 32

nano docker-compose.yml

services:
  linkwarden:
    image: ghcr.io/linkwarden/linkwarden:latest
    container_name: linkwarden
    restart: unless-stopped
    environment:
      DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres
      NEXTAUTH_SECRET: 04528de216fe029b3513e0a52ffb256dd671235942200348040a73acdf29a3c0
    env_file: .env
    volumes:
      - ./data:/data/data
    ports:
      - 8136:3000
    depends_on:
      - postgres

  postgres:
    image: postgres:16-alpine
    container_name: linkwarden_postgresql
    restart: unless-stopped
    env_file: .env
    volumes:
      - ./db:/var/lib/postgresql/data
nano .env
# Manual installation database settings
DATABASE_URL=postgresql://user:password@localhost:5432/linkwarden

# Docker installation database settings
POSTGRES_PASSWORD=linkwarden
docker compose up -d

LinkStack

cd /home/myusername/docker
mkdir linkstack && cd "$_"

nano docker-compose.yml

services:
  linkstack:
    image: linkstackorg/linkstack:latest
    container_name: linkstack
    restart: unless-stopped
    hostname: linkstack
    environment:
      TZ: Etc/UTC
      SERVER_ADMIN: [email protected]
      HTTP_SERVER_NAME: linkstack.DOMAIN.COM
      HTTPS_SERVER_NAME: linkstack.DOMAIN.COM
      LOG_LEVEL: info
      PHP_MEMORY_LIMIT: 256M
      UPLOAD_MAX_FILESIZE: 8M
      LINKSTACK_DB_HOST: mariadb
      LINKSTACK_DB_NAME: linkstack
      LINKSTACK_DB_USER: linkstack
      LINKSTACK_DB_PASSWORD: linkstack!
#    volumes:
#      - ./data:/htdocs
    ports:
      - 8229:80

  mariadb:
    image: mariadb:latest
    container_name: linkstack-mariadb
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: linkstack
      MYSQL_USER: linkstack
      MYSQL_PASSWORD: linkstack!
      MYSQL_ROOT_PASSWORD: linkstack!!
    volumes:
      - ./db:/var/lib/mysql
docker compose up -d

Configure LinkStack

The default database configuration from docker compose file:
Database type: MySQL

Database host: mariadb
Database port: 3306
Database name: linkstack
Database username: linkstack
Database password: linkstack!

Dolibarr (ERP/CRM)

cd /home/myusername/docker
mkdir dolibarr && cd "$_"

nano docker-compose.yml

services:
  web:
    image: dolibarr/dolibarr:latest
    container_name: dolibarr
    restart: unless-stopped
    environment:
      DOLI_DB_HOST: db
      DOLI_DB_NAME: dolibarr
      DOLI_DB_USER: dolibarr
      DOLI_DB_PASSWORD: dolibarr!
      DOLI_ADMIN_LOGIN: admin
      DOLI_ADMIN_PASSWORD: dolibarr
      DOLI_URL_ROOT: http://localhost
      PHP_INI_DATE_TIMEZONE: Etc/UTC
    volumes:
      - ./documents:/var/www/documents
      - ./html/custom:/var/www/html/custom
    ports:
      - 8200:80
    depends_on:
      - db

  db:
    image: mariadb:latest
    container_name: dolibarr-mariadb
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: dolibarr
      MYSQL_USER: dolibarr
      MYSQL_PASSWORD: dolibarr!
      MYSQL_ROOT_PASSWORD: dolibarr!!
    volumes:
      - ./db:/var/lib/mysql
docker compose up -d

Configure Dolibarr

Default login:
Username: admin
Password: dolibarr

Draw.io (flowchart creator)

cd /home/myusername/docker
mkdir drawio && cd "$_"

nano docker-compose.yml

services:
  drawio:
    image: jgraph/drawio
    container_name: drawio
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://192.168.1.125:8201|| exit 1"]
      interval: 1m30s
      timeout: 10s
      retries: 5
      start_period: 10s
    ports:
      - 8201:8080
      - 8202:8443
docker compose up -d

HumHub (Social Platform or Intranet)

cd /home/myusername/docker
mkdir humhub && cd "$_"
mkdir config && mkdir uploads && mkdir modules
cd uploads
mkdir profile_image && cd ..

nano docker-compose.yml

services:
  humhub:
    image: mriedmann/humhub:latest
    container_name: humhub
    restart: unless-stopped
    environment:
      HUMHUB_DB_USER: humhub
      HUMHUB_DB_PASSWORD: humhub!
    volumes:
      - ./config:/var/www/localhost/htdocs/protected/config
      - ./uploads:/var/www/localhost/htdocs/uploads
      - ./modules:/var/www/localhost/htdocs/protected/modules
      - ./themes:/var/www/localhost/htdocs/themes
    ports:
      - 8203:80
    depends_on:
      - db

  db:
    image: mariadb:latest
    container_name: humhub-mariadb
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: humhub
      MYSQL_USER: humhub
      MYSQL_PASSWORD: humhub!
      MYSQL_ROOT_PASSWORD: humhub!!
    volumes:
      - ./db:/var/lib/mysql
docker compose up -d

HumHub config

Hostname: humhub-mariadb
Port:
Username: humhub
Password: humhub!
Name of Database: humhub

✔️ Create the database if it doesn't exist yet.

✔️ External users can register (show registration form on login)
✔️ Newly registered users have to be activated by an admin first
Allow access for non-registered users to public content (guest access)
✔️ Registered members can invite new users via email
✔️ Allow friendships between members

Guacamole (RDP Internal)

cd home/myusername/docker
mkdir guacamole && cd "$_"

nano docker-compose.yml

services:
  guacamole:
    image: abesnier/guacamole 	# The image didnt got updated --> jwetzell/guacamole
    container_name: guacamole
    restart: unless-stopped
    volumes:
      - ./postgres:/config
    ports:
      - 8210:8080

docker compose up -d

Guacamole config

Default login:
Username: guacadmin
Password: guacadmin

Add new user:
Guacadmin --> Settings --> Users --> New User

Delete user Guacadmin:
myusername --> Settings --> Users --> guacadmin --> Delete --> Delete

Create a connection
Connections --> New Connection

EDIT CONNECTION
Name: Win11test
Location: ROOT
Protocol: RDP

PARAMETERS
Hostname: IPV4 OF THE MACHINE!!!
Port: 3389

Authentication
Ignore server certificate: ENABLE

RustDesk (RDP Support)

Currently not recommended use remotely instead

cd /home/myusername/docker
mkdir rustdesk && cd "$_"

nano docker-compose.yml

services:
  hbbs:
    image: rustdesk/rustdesk-server:latest
    container_name: rustdesk-hbbs
    restart: unless-stopped
    command: hbbs -r rustdesk.DOMAIN.COM:21117 # Change the URL to your domain
    volumes:
      - ./hbbs/data:/root
    ports:
      - 21115:21115
      - 21116:21116
      - 21116:21116/udp
      - 21118:21118
    depends_on:
      - hbbr

  hbbr:
    image: rustdesk/rustdesk-server:latest
    container_name: rustdesk-hbbr
    restart: unless-stopped
    command: hbbr
    volumes:
      - ./hbbr/data:/root
    ports:
      - 21117:21117
      - 21119:21119
docker compose up -d

remotely (RDP Support)

cd /home/myusername/docker
mkdir remotely && cd "$_"

nano docker-compose.yml

services:
  remotely:
    image: immybot/remotely:latest
    container_name: remotely
    restart: unless-stopped
    ports:
      - 8215:5000
    environment:
      ASPNETCORE_ENVIRONMENT: Production
      ASPNETCORE_HTTP_PORTS: 5000
      # Other ASP.NET Core configurations can be overridden here, such as Logging.
      # See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-8.0
      # Values for DbProvider are SQLite, SQLServer, and PostgreSQL.
      Remotely_ApplicationOptions__DbProvider: SQLite
      # This path shouldn't be changed.  It points to the Docker volume.
      Remotely_ConnectionStrings__SQLite: Data Source=/app/AppData/Remotely.db
      # If using SQL Server, change the connection string to point to your SQL Server instance.
      #Remotely_ConnectionStrings__SQLServer: Server=(localdb)\\mssqllocaldb;Database=Remotely-Server-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true
      # If using PostgreSQL, change the connection string to point to your PostgreSQL instance.
      #Remotely_ConnectionStrings__PostgreSQL: Server=Host=localhost;Database=Remotely;Username=postgres;
    volumes:
      - ./data:/remotely-data
      - ./db:/app/AppData
#      - ./wwwroot:/app/wwwroot
docker compose up -d

Pwndrop (File sharing)

cd /home/myusername/docker
mkdir pwndrop
cd pwndrop

nano docker-compose.yml

services:
  pwndrop:
    image: lscr.io/linuxserver/pwndrop:latest
    container_name: pwndrop
    restart: unless-stopped
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Etc/UTC
      SECRET_PATH: /pwndrop # optional
    volumes:
      - ./config:/config
    ports:
      - 8133:8080

docker compose up -d

Netbox

cd /home/myusername/docker
mkdir netbox && cd "$_"
git clone -b release https://github.com/netbox-community/netbox-docker.git && cd netbox-docker
cp docker-compose.override.yml.example docker-compose.override.yml

nano docker-compose.yml

services:
  netbox:
    ports:
      - 9140:8080
nano netbox.env
nano ./env/netbox.env
CORS_ORIGIN_ALLOW_ALL=True
DB_HOST=postgres
DB_NAME=netbox
DB_PASSWORD=netbox!
DB_USER=netbox
[email protected]
EMAIL_PASSWORD= 
EMAIL_PORT=587
EMAIL_SERVER=mail.domainhere.com
EMAIL_SSL_CERTFILE=
EMAIL_SSL_KEYFILE=
EMAIL_TIMEOUT=5
[email protected]
# EMAIL_USE_SSL and EMAIL_USE_TLS are mutually exclusive, i.e. they can't both be `true`!
EMAIL_USE_SSL=false
EMAIL_USE_TLS=true
GRAPHQL_ENABLED=true
HOUSEKEEPING_INTERVAL=86400
MAX_PAGE_SIZE=1000
MEDIA_ROOT=/opt/netbox/netbox/media
METRICS_ENABLED=false
REDIS_CACHE_DATABASE=1
REDIS_CACHE_HOST=redis-cache
REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY=false
REDIS_CACHE_PASSWORD=netbox!
REDIS_CACHE_SSL=false
REDIS_DATABASE=0
REDIS_HOST=redis
REDIS_INSECURE_SKIP_TLS_VERIFY=false
REDIS_PASSWORD=netbox!
REDIS_SSL=false
RELEASE_CHECK_URL=https://api.github.com/repos/netbox-community/netbox/releases
SECRET_KEY=r8OwDznj!!dci#P9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj
SKIP_STARTUP_SCRIPTS=false
SKIP_SUPERUSER=false
SUPERUSER_API_TOKEN=6e04a389-a42d-4ca3-a4a3-9bf420d393fd
[email protected]
SUPERUSER_NAME=admin
SUPERUSER_PASSWORD=netbox
WEBHOOKS_ENABLED=true
docker compose up -d

With linuxserverio

cd /home/myusername/docker
mkdir netbox && cd "$_"

nano docker-compose.yml

services:
  netbox:
    image: lscr.io/linuxserver/netbox:latest
    container_name: netbox
    restart: unless-stopped
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Etc/UTC
      SKIP_SUPERUSER: false
      SUPERUSER_NAME: admin
      SUPERUSER_EMAIL: [email protected]
      SUPERUSER_PASSWORD: netbox
      ALLOWED_HOST: '*'  # to allow only sertain hosts use this ALLOWED_HOST: 'netbox.DOMAIN.COM'
      DB_NAME: netbox
      DB_USER: netbox
      DB_PASSWORD: netbox!
      DB_HOST: db
      DB_PORT: 5432
      REDIS_HOST: redis
      REDIS_PORT: 6379
      REDIS_PASSWORD: netbox!
      REDIS_DB_TASK: 0
      REDIS_DB_CACHE: 1
      BASE_PATH:  #optional
      REMOTE_AUTH_ENABLED:  #optional
      REMOTE_AUTH_BACKEND:  #optional
      REMOTE_AUTH_HEADER:  #optional
      REMOTE_AUTH_AUTO_CREATE_USER:  #optional
      REMOTE_AUTH_DEFAULT_GROUPS:  #optional
      REMOTE_AUTH_DEFAULT_PERMISSIONS:  #optional
      WEBHOOKS_ENABLED: true
    volumes:
      - ./config:/config
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 9140:8000

  db:
    image: postgres:latest
    container_name: netbox-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: netbox  # Set the same value as DB_NAME
      POSTGRES_USER: netbox  # Set the same value as DB_USER
      POSTGRES_PASSWORD: netbox!  # Set the same value as DB_PASSWORD
    volumes:
      - ./db:/var/lib/postgresql/data

  redis:
    image: redis:latest
    container_name: netbox-redis
    restart: unless-stopped
    command: redis-server --requirepass netbox!  # Set your Redis password
    volumes:
      - ./redis:/data
docker compose up -d

Invision Community

cd /home/myusername/docker
mkdir ipboard && cd "$_"

Make sure you insert the Invision Community files in the ipboard folder that you just made

chmod 0777 ./data/conf_global.php

nano docker-compose.yml

services:
  app:
    image: maxime1907/ipboard:latest 		# OPTIONAL, Use cmer81/ipboard:latest for php 8.1
    container_name: ipboard
    restart: unless-stopped
    environment:
      MYSQL_HOST: db
      MYSQL_DATABASE: ipboard
      MYSQL_USER: ipboard
      MYSQL_PASSWORD: ipboard!
      WEB_ALIAS_DOMAIN: forum.DOMAIN.COM
      APPLICATION_UID: 1000
      APPLICATION_GID: 1000
      PGID: 1000
      PUID: 1000
      TZ: Etc/UTC
    volumes:
      - ./data:/app
    ports:
      - 8156:80
    depends_on:
      - db

  db:
    image: mariadb:latest
    container_name: ipboard-mariadb
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    environment:
      MYSQL_DATABASE: ipboard
      MYSQL_USER: ipboard
      MYSQL_PASSWORD: ipboard!
      MYSQL_ROOT_PASSWORD: ipboard!!
    volumes:
      - ./db:/var/lib/mysql

docker compose up -d
docker exec -it ipboard /bin/bash
chmod 0777 -R /app/applications /app/datastore /app/plugins /app/uploads /app/uploads/logs

If you use cloudflared tunnel make sure to enable Trust IP addresses provided by proxies otherwise you will only see the same local ip address everywhere
AdminCP -> System -> Advanced Configuration. --> Enable Trust IP addresses provided by proxies

Configure Invision Community

Server Details:
Host: db
Username: ipboard
Password: ipboard!
Database Name: ipboard

After installation, If you see broken icons:
Upload Font Awesome 6 in IPS 6.3.0.tar to
System --> Applications --> manual upload

Update Invision Community

  1. Download data directory
  2. Copy all contents from the invision community update into data directory and overwrite all
  3. Visit: https://forum.DOMAIN.COM/admin/upgrade/

Selkies

cd /home/myusername/docker
mkdir selkies && cd "$_"
services:
  selkies:
    image: ghcr.io/linuxserver/baseimage-selkies:alpine323 # available images: alpine323, arch, debiantrixie, fedora44, kali, ubunturesolute,
    container_name: selkies
    restart: unless-stopped
    
    # Required for many web browsers / electron apps to run inside Docker
    security_opt:
      - seccomp=unconfined
    
    # Required for desktop environments to prevent memory crashes
    shm_size: "1gb"

    # -----------------------------------------------------------------------
    # NETWORKING & PORTS
    # -----------------------------------------------------------------------
    ports:
      # Default HTTPS port (Uncomment if not routing exclusively via a reverse proxy)
      # - "3001:3001"
      # Default HTTP port (Use if running reverse proxy)
      - "8301:3000" 
      # Default WebSocket port
      # - "8082:8082"
      # Secure Control Plane API (Do NOT expose publicly, for internal token management only)
      # - "8083:8083"

    # -----------------------------------------------------------------------
    # VOLUMES
    # -----------------------------------------------------------------------
    volumes:
      # Main configuration and persistent user home directory (if apps wont install try: chmod -R 777 config)
      - "./config:/config"
      
      # Map in your external HDD if you want access to your media inside the Selkies desktop
      # - "/media/disk/exthdd01:/media/disk/exthdd01"

      # Uncomment to use host's Docker socket (for Docker integration without privileged DinD)
      # - /var/run/docker.sock:/var/run/docker.sock
      
      # Uncomment to mount a custom watermark
      # - ./data/watermark.png:/usr/share/selkies/www/icon.png:ro

    # -----------------------------------------------------------------------
    # HARDWARE ACCELERATION
    # -----------------------------------------------------------------------
    
    # devices:
    #   - /dev/dri/renderD128:/dev/dri/renderD128
    #   - /dev/dri/card1:/dev/dri/card1

    # -----------------------------------------------------------------------
    # ENVIRONMENT VARIABLES
    # -----------------------------------------------------------------------
    environment:
      # --- System / Core ---
      PUID: 1000
      PGID: 1000
      TZ: Etc/UTC
      # LC_ALL: en_US.UTF-8 # Set language (e.g., fr_FR.UTF-8, zh_CN.UTF-8)
      # DISABLE_IPV6: true
      # START_DOCKER: false # Set to false to disable DinD if running in privileged mode

      # --- Authentication ---
      CUSTOM_USER: admin
      PASSWORD: selkies!
      # SELKIES_MASTER_TOKEN: your-secret-master-token # Enables secure token-based auth

      # --- Networking Overrides ---
      # CUSTOM_PORT: 3000
      # CUSTOM_HTTPS_PORT: 3001
      # CUSTOM_WS_PORT: 8082
      # SUBFOLDER: /selkies/

      # --- Display, GPU & Wayland ---
      PIXELFLUX_WAYLAND: true # Enables Wayland (Smithay/Labwc) instead of X11
      SELKIES_DESKTOP: true # Initializes a simple panel with labwc in Wayland mode
      AUTO_GPU: true # Automatically use the first available GPU for encoding/rendering
      # DRINODE: /dev/dri/renderD128 # Specify GPU for Rendering (EGL)
      # DRI_NODE: /dev/dri/renderD128 # Specify GPU for Encoding (VAAPI/NVENC)
      # DISABLE_ZINK: true # Disable Zink (forces CPU rendering for userspace apps)
      # DISABLE_DRI3: true # Disable DRI3 acceleration
      # MAX_RES: 15360x8640 # Pass a larger maximum resolution (X11 only)
      # PIXELFLUX_RECORDING_SOCKET: /defaults/recording # Unix socket path for recording streams

      # --- Application & Window Control ---
      # TITLE: Selkies
      # DASHBOARD: selkies-dashboard # Options: selkies-dashboard, selkies-dashboard-zinc, selkies-dashboard-wish
      # FILE_MANAGER_PATH: /config # Modifies the default upload/download path
      # NO_DECOR: true # Run without window borders (PWA style)
      # NO_FULL: true # Do not automatically fullscreen applications
      # NO_GAMEPAD: true # Disable userspace gamepad interposer
      # WATERMARK_PNG: /usr/share/selkies/www/icon.png
      # WATERMARK_LOCATION: 5 # 1:Top-L, 2:Top-R, 3:Bot-L, 4:Bot-R, 5:Center, 6:Animated

      # --- Hardening & Security ---
      # HARDEN_DESKTOP: true # Preset: Disables open tools, sudo, terminals
      # HARDEN_OPENBOX: true # Preset: Disables close button, mouse menus, keybinds, restarts app
      # DISABLE_OPEN_TOOLS: true
      # DISABLE_SUDO: true
      # DISABLE_TERMINALS: true
      # DISABLE_CLOSE_BUTTON: true
      # DISABLE_MOUSE_BUTTONS: true
      # HARDEN_KEYBINDS: true
      # RESTART_APP: true # Automatically restart the main application if closed

      # --- Selkies Core Stream Settings ---
      # SELKIES_AUDIO_ENABLED: true
      # SELKIES_MICROPHONE_ENABLED: true
      # SELKIES_GAMEPAD_ENABLED: true
      # SELKIES_CLIPBOARD_ENABLED: true
      # SELKIES_CLIPBOARD_IN_ENABLED: true
      # SELKIES_CLIPBOARD_OUT_ENABLED: true
      # SELKIES_COMMAND_ENABLED: true
      # SELKIES_FILE_TRANSFERS: upload,download # Set to "" or "none" to disable
      # SELKIES_SECOND_SCREEN: true
      
      # --- Selkies Encoding & Quality ---
      # Append "|locked" to values to prevent users from changing them in the UI (e.g. "x264enc|locked")
      # SELKIES_ENCODER: x264enc,jpeg
      # SELKIES_FRAMERATE: 8-120 # Can be a range "8-120" or fixed "60"
      # SELKIES_USE_CPU: false # Force CPU encoding
      # SELKIES_H264_CRF: 5-50
      # SELKIES_JPEG_QUALITY: 1-100
      # SELKIES_H264_FULLCOLOR: false
      # SELKIES_H264_STREAMING_MODE: false
      # SELKIES_AUDIO_BITRATE: 320000

      # --- Selkies Paint-Over (Static Scene Quality) ---
      # SELKIES_USE_PAINT_OVER_QUALITY: true
      # SELKIES_PAINT_OVER_JPEG_QUALITY: 1-100
      # SELKIES_H264_PAINTOVER_CRF: 5-50
      # SELKIES_H264_PAINTOVER_BURST_FRAMES: 1-30

      # --- Selkies Manual Resolution Mode ---
      # SELKIES_IS_MANUAL_RESOLUTION_MODE: false # Forces 1024x768 if true and w/h aren't set
      # SELKIES_MANUAL_WIDTH: 1920
      # SELKIES_MANUAL_HEIGHT: 1080
      # SELKIES_SCALING_DPI: 96
      # SELKIES_USE_CSS_SCALING: false

      # --- Selkies UI Customization ---
      # SELKIES_UI_TITLE: Selkies
      # SELKIES_UI_SHOW_LOGO: true
      # SELKIES_UI_SHOW_SIDEBAR: true
      # SELKIES_UI_SHOW_CORE_BUTTONS: true
      # SELKIES_UI_SIDEBAR_SHOW_VIDEO_SETTINGS: true
      # SELKIES_UI_SIDEBAR_SHOW_SCREEN_SETTINGS: true
      # SELKIES_UI_SIDEBAR_SHOW_AUDIO_SETTINGS: true
      # SELKIES_UI_SIDEBAR_SHOW_STATS: true
      # SELKIES_UI_SIDEBAR_SHOW_CLIPBOARD: true
      # SELKIES_UI_SIDEBAR_SHOW_FILES: true
      # SELKIES_UI_SIDEBAR_SHOW_APPS: true
      # SELKIES_UI_SIDEBAR_SHOW_SHARING: true
      # SELKIES_UI_SIDEBAR_SHOW_GAMEPADS: true
      # SELKIES_UI_SIDEBAR_SHOW_FULLSCREEN: true
      # SELKIES_UI_SIDEBAR_SHOW_GAMING_MODE: true
      # SELKIES_UI_SIDEBAR_SHOW_TRACKPAD: true
      # SELKIES_UI_SIDEBAR_SHOW_KEYBOARD_BUTTON: true
      # SELKIES_UI_SIDEBAR_SHOW_SOFT_BUTTONS: true

      # --- Sharing & Collaboration ---
      # SELKIES_ENABLE_SHARING: true
      # SELKIES_ENABLE_COLLAB: true
      # SELKIES_ENABLE_SHARED: true
      # SELKIES_ENABLE_PLAYER2: true
      # SELKIES_ENABLE_PLAYER3: true
      # SELKIES_ENABLE_PLAYER4: true

      # --- Debugging ---
      # SELKIES_DEBUG: true

    # -----------------------------------------------------------------------
    # DOCKER IN DOCKER (DinD) - Optional
    # -----------------------------------------------------------------------
    # To run Docker IN the container, you must uncomment `privileged: true`
    # Warning: Running privileged gives the container significant host access.
    # privileged: true

Cloudflared

cd /home/myusername/docker
mkdir cloudflared && cd "$_"

nano docker-compose.yml

networks:
#  frontend:
#    external: true
#  backend:
#    external: true
  bridge:
    driver: bridge

services:
  cloudflaretunnel:
    image: cloudflare/cloudflared:2023.6.1
    container_name: cloudflaretunnel
    restart: unless-stopped
    command: tunnel --no-autoupdate run
    environment:
      TUNNEL_TOKEN: IMPORT_CLOUDFLARE_TUNNEL_TOKEN_HERE
    networks:
#      - frontend
#      - backend
      - bridge
docker compose up -d

Teleport (Infrastructure Access)

cd /home/myusername/docker
mkdir teleport && cd "$_"
docker run --hostname localhost --rm --entrypoint=/bin/sh -v ./config/:/etc/teleport -it quay.io/gravitational/teleport:11 -c "teleport configure > /etc/teleport/teleport.yml"
cd config

You dont have to enable acme if you bought a domain name

nano teleport.yml

#
# A Sample Teleport configuration file.
#
# Things to update:
#  1. license.pem: You only need a license from https://dashboard.goteleport.com
#     if you are an Enterprise customer.
#
version: v3
teleport:
  nodename: teleport.DOMAIN.COM
  data_dir: /var/lib/teleport
  log:
    output: stderr
    severity: INFO
    format:
      output: text
  ca_pin: ""
  diag_addr: ""
auth_service:
  enabled: "yes"
  listen_addr: 0.0.0.0:3025
  proxy_listener_mode: multiplex
  cluster_name: teleport.DOMAIN.COM
  # ---
  # (Optional) Passwordless Authentication
  # authentication:
  #   type: local
  #   second_factor: on
  #   webauthn:
  #     rp_id: teleport.DOMAIN.COM
  #   connector_name: passwordless
  # ---
ssh_service:
  enabled: "yes"
  commands:
  - name: hostname
    command: [hostname]
    period: 1m0s
proxy_service:
  enabled: "yes"
  web_listen_addr: 0.0.0.0:443
  public_addr: teleport.DOMAIN.COM
  https_keypairs: []
  acme: {}
  # ---
  # (Optional) ACME
  # acme:
  #   enabled: "yes"
  #   email: your-email-address
  # ---

nano docker-compose.yml

services:
  teleport:
    image: quay.io/gravitational/teleport:11
    container_name: teleport
    restart: unless-stopped
    user: 1000:1000
    entrypoint: /bin/sh
    command: -c "/usr/bin/dumb-init teleport start -d -c /etc/teleport/teleport.yml"
    volumes:
      - ./config:/etc/teleport
      - ./data:/var/lib/teleport
    ports:
      - 9010:3023
      - 9011:3024
      - 9012:3025
      - 9013:443
docker compose up -d

UpSnap (Wake on LAN)

cd /home/myusername/docker
mkdir upsnap && cd "$_"

nano docker-compose.yml

services:
  app:
    image: truecharts/upsnap:latest
    container_name: upsnap
    restart: unless-stopped
    network_mode: host
    environment:
      FRONTEND_PORT: 8000
      BACKEND_PORT: 8001
      BACKEND_IS_PROXIED: false # set this to true, if you use a reverse proxy
      DB_TYPE: sqlite # required
      REDIS_HOST: 127.0.0.1 # required (make sure to use the same ip as below)
      REDIS_PORT: 6379 # required (make sure to use the same port as below)
#      PING_INTERVAL: 5 # optional (default: 5 seconds)
#      DJANGO_SUPERUSER_USER: admin # optional (default: backend login disabled)
#      DJANGO_SUPERUSER_PASSWORD: admin # optional (default: backend login disabled)
#      DJANGO_SECRET_KEY: secret # optional (default: randomly generated)
#      DJANGO_DEBUG: True # optional (default: False)
#      DJANGO_LANGUAGE_CODE: de # optional (default: en)
#      DJANGO_TIME_ZONE: Etc/UTC # optional (default: UTC)
#      NMAP_ARGS: -sP # optional, set this if your devices need special nmap args so they can be found (default: -sP)
#      PAGE_TITLE: Custom Title # optional, set a custom page title (default: UpSnap)
    volumes:
      - ./db:/app/backend/db/
    depends_on:
      redis:
        condition: service_healthy

  redis:
    image: redis:alpine
    container_name: upsnap-redis
    restart: unless-stopped
    command: redis-server --loglevel warning
    healthcheck:
      test: redis-cli ping
      interval: 10s
    ports:
      - 9015:6379
docker compose up -d

KASM (Container Workspaces)

cd /home/myusername/docker
mkdir kasm && cd "$_"

nano docker-compose.yml

services:
  kasm:
    image: lscr.io/linuxserver/kasm:latest
    container_name: kasm
    privileged: true
    security_opt:
      - apparmor:rootlesskit
    environment:
      KASM_PORT: 443
      # DOCKER_HUB_USERNAME: USER
      # DOCKER_HUB_PASSWORD: PASS
      DOCKER_MTU: 1500
    volumes:
      - ./data:/opt
      - ./data/profiles:/profiles
      - /dev/input:/dev/input
      - /run/udev/data:/run/udev/data
    ports:
      - 3000:3000
    restart: unless-stopped
docker compose up -d

iSpy (cam surveillance)

cd /home/myusername/docker
mkdir ispy && cd "$_"

nano docker-compose.yml

services:
  ispyagentdvr:
    image: mekayelanik/ispyagentdvr:latest
    container_name: ispyagentdvr
    restart: unless-stopped
    environment:
      - PUID: 1000
      - PGID: 1000
      - AGENTDVR_WEBUI_PORT: 8090 
      - TZ: Etc/UTC
    volumes:
      - ./config:/AgentDVR/Media/XML
      - ./recordings:/AgentDVR/Media/WebServerRoot/Media
      - ./models:/AgentDVR/Media/Models
      - ./commands:/AgentDVR/Commands
    ports:
      - 8090:8090
      - 3478:3478/udp
      - 50000-50100:50000-50100/udp
docker compose up -d

UniFi Controller

cd /home/myusername/docker
mkdir unifi-controller && cd "$_"

nano docker-compose.yml

services:
  unifi-controller:
    image: lscr.io/linuxserver/unifi-controller:latest
    container_name: unifi-controller
    restart: unless-stopped
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Etc/UTC
      MEM_LIMIT: 1024 #optional
      MEM_STARTUP: 1024 #optional
    volumes:
      - ./config:/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
docker compose up -d

UniFi Protect

cd /home/myusername/docker
mkdir unifi-protect && cd "$_"

nano docker-compose.yml

x84 version WE ARE TESTING THIS

services:
  unifi-protect-x86:
    image: markdegroot/unifi-protect-x86:latest
    container_name: unifi-protect-x86
    restart: unless-stopped
    tmpfs:
      - /srv/unifi-protect/temp
    ports:
      - 7080:7080
      - 7443:7443
      - 7444:7444
      - 7447:7447
      - 7550:7550
      - 7442:7442
    mem_limit: 2048m
    volumes:
      - ./db:/var/lib/postgresql/10/main
      - ./data:/srv/unifi-protect

ARM64 version WE ARE TESTING THIS

services:
  unifi-protect:
    image: markdegroot/unifi-protect-arm64
    container_name: unifi-protect
    environment:
      STORAGE_DISK: /dev/sda1
    command: [ "sh", "-c", "systemd" ]
    privileged: true
    tmpfs:
      - /run
      - /run/lock
      - /tmp
    volumes:
      - ./cgroup:/sys/fs/cgroup:ro
      - ./srv:/srv
      - ./data:/data
      - ./persistent:/persistent
    network_mode: host
docker compose up -d

Netdata

cd /home/myusername/docker
mkdir netdata && cd "$_"

nano docker-compose.yml

services:
  netdata:
    image: netdata/netdata
    container_name: netdata
    restart: unless-stopped
    cap_add:
      - SYS_PTRACE
      - SYS_ADMIN
    security_opt:
      - apparmor:unconfined
    volumes:
#      - ./config:/etc/netdata        # Optional
#      - ./lib:/var/lib/netdata       # Optional
#      - ./cache:/var/cache/netdata   # Optional
      - /:/host/root:ro,rslave
      - /etc/passwd:/host/etc/passwd:ro
      - /etc/group:/host/etc/group:ro
      - /etc/localtime:/etc/localtime:ro
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /etc/os-release:/host/etc/os-release:ro
      - /var/log:/host/var/log:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    ports:
      - 8166:19999
docker compose up -d

DiscordBot

cd /home/myusername/docker
mkdir mydiscordbot01 && cd "$_"

nano docker-compose.yml

services:
  mydiscordbot01:
    image: jonasbonno/discordbot:latest
    container_name: mydiscordbot01
    restart: unless-stopped
    environment:
      TOKEN: IMPORT_DISCORD_BOT_TOKEN_HERE
    volumes:
      - ./data:/data
docker compose up -d

changedetection

cd /home/myusername/docker
mkdir changedetection && cd "$_"

nano docker-compose.yml

services:
  changedetection:
    image: ghcr.io/dgtlmoon/changedetection.io
    container_name: changedetection
    restart: unless-stopped
    volumes:
      - ./datastore:/datastore
#      - ./static:/app/changedetectionio/static
    environment:
      PUID: 1000
      PGID: 1000
      LOGGER_LEVEL: DEBUG                       # Log output levels: TRACE, DEBUG(default), INFO, SUCCESS, WARNING, ERROR, CRITICAL
#      BASE_URL: https://cdetect.DOMAIN.COM     # Base URL of your changedetection.io install (Added to the notification alert)
      HIDE_REFERER: true                       # Hides the `Referer` header so that monitored websites can't see the changedetection.io hostname.
#      FETCH_WORKERS: 10                        # Default number of parallel/concurrent fetchers
      PLAYWRIGHT_DRIVER_URL: ws://changedetection-chrome:3000/
    ports:
      - 8167:5000
    depends_on:
      - playwright-chrome
          condition: service_started


  playwright-chrome:
    image: dgtlmoon/sockpuppetbrowser:latest
    container_name: changedetection_chrome
    restart: unless-stopped
    hostname: changedetection-chrome
    cap_add:
      - SYS_ADMIN
#    ports:
#      - 8168:3000
    environment:
      SCREEN_WIDTH: 1920
      SCREEN_HEIGHT: 1024
      SCREEN_DEPTH: 16
      MAX_CONCURRENT_CHROME_PROCESSES: 10

docker compose up -d

Spacebar (discord clone)

cd /home/myusername/docker
mkdir spacebar && cd "$_"

nano docker-compose.yml

services:
  spacebar-server:
    image: ccgurley/spacebar-server:latest
    container_name: spacebar-server
    restart: unless-stopped
    environment:
      CONFIG_PATH: /spacebar-server/db/config.json
    volumes:
      - ./db:/spacebar-server/db/
    ports:
      - 8400:3001

  spacebar-client:
    image: ccgurley/spacebar-client:latest
    container_name: spacebar-client
    restart: unless-stopped
    environment:
      SERVER_API: https://api.spacebar.chat
      SERVER_CDN: https://cdn.spacebar.chat
      SERVER_GATEWAY: wss://gateway.spacebar.chat
    ports:
      - 8401:80
docker compose up -d

LanCache

cd /home/myusername/docker
mkdir lancache && cd "$_"

nano .env

## See the "Settings" section in README.md for more details

## Set this to true if you're using a load balancer, or set it to false if you're using seperate IPs for each service.
## If you're using monolithic (the default), leave this set to true
USE_GENERIC_CACHE=true

## IP addresses that the lancache monolithic instance is reachable on
## Specify one or more IPs, space separated - these will be used when resolving DNS hostnames through lancachenet-dns. Multiple IPs can improve cache priming performance for some services (e.g. Steam)
## Note: This setting only affects DNS, monolithic and sniproxy will still bind to all IPs by default
LANCACHE_IP=10.0.39.1

## IP address on the host that the DNS server should bind to
DNS_BIND_IP=10.0.39.1

## DNS Resolution for forwarded DNS lookups
UPSTREAM_DNS=8.8.8.8

## Storage path for the cached data
## Note that by default, this will be a folder relative to the docker-compose.yml file
CACHE_ROOT=./lancache

## Change this to customise the size of the disk cache (default 2000g)
## If you have more storage, you'll likely want to increase this
## The cache server will prune content on a least-recently-used basis if it
## starts approaching this limit.
## Set this to a little bit less than your actual available space 
CACHE_DISK_SIZE=2000g

## Change this to allow sufficient index memory for the nginx cache manager (default 500m)
## We recommend 250m of index memory per 1TB of CACHE_DISK_SIZE 
CACHE_INDEX_SIZE=500m

## Change this to limit the maximum age of cached content (default 3650d)
CACHE_MAX_AGE=3650d

## Set the timezone for the docker containers, useful for correct timestamps on logs (default Europe/London)
## Formatted as tz database names. Example: Europe/Oslo or America/Los_Angeles
TZ=Etc/UTC

nano docker-compose.yml

services:
  dns:
    image: lancachenet/lancache-dns:latest
    container_name: lancache
    restart: unless-stopped
    env_file: .env
    ports:
      - ${DNS_BIND_IP}:53:53/udp # This is provided in the .env file!
      - ${DNS_BIND_IP}:53:53/tcp # This is provided in the .env file!

## HTTPS requests are now handled in monolithic directly
## you could choose to return to sniproxy if desired
#
#  sniproxy:
#    image: lancachenet/sniproxy:latest
#    container_name: lancache-sniproxy
#    restart: unless-stopped
#    env_file: .env
#    ports:
#      - 443:443/tcp

  monolithic:
    image: lancachenet/monolithic:latest
    container_name: lancache-monolithic
    restart: unless-stopped
    env_file: .env
    volumes:
      - ${CACHE_ROOT}/cache:/data/cache # This is provided in the .env file!
      - ${CACHE_ROOT}/logs:/data/logs # This is provided in the .env file!
    ports:
      - 80:80/tcp
      - 443:443/tcp
docker compose up -d

Gotify

cd /home/myusername/docker
mkdir gotify && cd "$_"

nano docker-compose.yml

services:
  gotify:
    image: gotify/server
    container_name: gotify
    restart: unless-stopped
    ports:
      - 9210:80
    environment:
      TZ: Etc/UTC
    volumes:
      - ./data:/app/data
docker compose up -d

Watchtower

To use watchtower with Gotify make sure to deploy the Gotify container first from above
Currently Watchtower is set to notification only, if you want that watchtower automaticly updates all containers then set WATCHTOWER_MONITOR_ONLY: false and WATCHTOWER_NO_PULL: false

cd /home/myusername/docker
mkdir watchtower && cd "$_"

nano docker-compose.yml

services:
  watchtower:
    image: containrrr/watchtower:latest
    container_name: watchtower
    restart: unless-stopped
    environment:
      TZ: Etc/UTC
      NO_COLOR: true
      WATCHTOWER_SCHEDULE: 0 0 19 * * *
      WATCHTOWER_INCLUDE_STOPPED: true
      WATCHTOWER_INCLUDE_RESTARTING: true
      WATCHTOWER_NOTIFICATIONS_HOSTNAME: watchtower
      WATCHTOWER_NOTIFICATIONS: gotify
      WATCHTOWER_NOTIFICATION_GOTIFY_URL: IMPORT_GOTIFY_URL_HERE
      WATCHTOWER_NOTIFICATION_GOTIFY_TOKEN: IMPORT_WATCHTOWER_TOKEN_HERE
      WATCHTOWER_NOTIFICATION_GOTIFY_TLS_SKIP_VERIFY: true
      WATCHTOWER_MONITOR_ONLY: true # If set to true then also set WATCHTOWER_NO_PULL into true
      WATCHTOWER_NO_PULL: true # Set to true if WATCHTOWER_MONITOR_ONLY is set into true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
docker compose up -d

Configure Watchtower with gotify

Default login
Username: admin
Password: admin

  1. Go to: Apps
  2. Click on: Create Application
  3. Name it: Watchtower
  4. Copy the token then edit docker-compose.yml find WATCHTOWER_NOTIFICATION_GOTIFY_TOKEN then replace the following:
docker compose up -d

wud (watchtower fork)

cd /home/myusername/docker
mkdir wud && cd "$_"

nano docker-compose.yml

services:
  whatsupdocker:
    image: ghcr.io/fmartinou/whats-up-docker:latest
    container_name: wud
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - 8900:3000
docker compose up -d

Ansible Semaphore

cd /home/myusername/docker
mkdir ansiblesemaphore && cd "$_"

nano docker-compose.yml

services:
  semaphore:
    image: semaphoreui/semaphore:latest
    container_name: semaphore
    restart: unless-stopped
    environment:
      SEMAPHORE_DB_DIALECT: mysql
      SEMAPHORE_DB_HOST: mariadb
      SEMAPHORE_DB_PORT: 3306
      SEMAPHORE_DB: semaphore
      SEMAPHORE_DB_USER: semaphore
      SEMAPHORE_DB_PASS: semaphore!
      SEMAPHORE_PLAYBOOK_PATH: /tmp/semaphore/
      SEMAPHORE_ADMIN_PASSWORD: semaphore
      SEMAPHORE_ADMIN_NAME: admin
      SEMAPHORE_ADMIN_EMAIL: [email protected]
      SEMAPHORE_ADMIN: admin
      SEMAPHORE_ACCESS_KEY_ENCRYPTION: EUZi3BfINyLtUr0uZKfzGx+J14OfSTpUwLWTcks1dk0= # To generate a random key use: head -c32 /dev/urandom | base64
      ANSIBLE_HOST_KEY_CHECKING: false  # (optional) change to true if you want to enable host key checking
    user: "${UID}:${GID}"
    volumes:
      - ./inventory/:/inventory:ro
      - ./authorized-keys/:/authorized-keys:ro
      - ./config/:/etc/semaphore:rw
    ports:
      - 9300:3000
    depends_on:
      - db

  db:
    image: mariadb:latest
    container_name: semaphore-mariadb
    hostname: mariadb
    restart: unless-stopped
    volumes:
      - ./db:/var/lib/mysql
    environment:
      MYSQL_DATABASE: semaphore
      MYSQL_USER: semaphore
      MYSQL_PASSWORD: semaphore!
      MYSQL_ROOT_PASSWORD: semaphore!!

docker compose up -d

Owncast

cd /home/myusername/docker
mkdir owncast && cd "$_"

nano docker-compose.yml

services:
  owncast:
    image: owncast/owncast:latest
    container_name: owncast
    restart: unless-stopped
    volumes:
      - ./data:/app/data
    ports:
      - 8310:8080
      - 8311:1935
    tty: true
docker compose up -d

Mealie

cd /home/myusername/docker
mkdir mealie && cd "$_"

nano docker-compose.yml

services:
  mealie:
    image: ghcr.io/mealie-recipes/mealie:nightly
    container_name: mealie
    restart: unless-stopped
    environment:
      ALLOW_SIGNUP: true
      PUID: 1000
      PGID: 1000
      TZ: America/Anchorage
      MAX_WORKERS: 1
      WEB_CONCURRENCY: 1
      BASE_URL: https://mealie.DOMAIN.COM
      DB_ENGINE: postgres
      POSTGRES_USER: mealie
      POSTGRES_PASSWORD: mealie!
      POSTGRES_SERVER: postgres
      POSTGRES_PORT: 5432
      POSTGRES_DB: mealie
    ports:
        - 8228:9000
    volumes:
      - ./data:/app/data/
    depends_on:
      - db
    
  db:
    image: postgres:15
    container_name: postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: mealie
      POSTGRES_PASSWORD: mealie!
    volumes:
      - ./db:/var/lib/postgresql/data
docker compose up -d

Jenkins

With docker compose

cd /home/myusername/docker
mkdir jenkins && cd "$_"

nano docker-compose.yml

services:
  jenkins:
    image: jenkins/jenkins:lts
    container_name: jenkins
    restart: unless-stopped
    privileged: true
    user: root
    ports:
      - 50000:50000
      - 50001:8080
    volumes:
      - ./data:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock

  socat:
    image: alpine/socat
    container_name: socat
    restart: unless-stopped
    command: tcp-listen:2375,fork,reuseaddr unix-connect:/var/run/docker.sock
    ports:
      - 2376:2375
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
docker compose up -d

With dockerfile (with plugins)

cd /home/myusername/docker
mkdir jenkins && cd "$_"
docker network create jenkins
docker run \
  --name jenkins-docker \
  --rm \
  --detach \
  --privileged \
  --network jenkins \
  --network-alias docker \
  --env DOCKER_TLS_CERTDIR=/certs \
  --volume ./client-certs:/certs/client \
  --volume ./data:/var/jenkins_home \
  --publish 2376:2376 \
  docker:dind \
  --storage-driver overlay2
nano dockerfile
# Use the base Jenkins image
FROM jenkins/jenkins:jdk21

# Switch to the root user to install packages
USER root

# Install lsb-release
RUN apt-get update && apt-get install -y lsb-release

# Add Docker GPG key
RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \
  https://download.docker.com/linux/debian/gpg

# Add Docker repository
RUN echo "deb [arch=$(dpkg --print-architecture) \
  signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \
  https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list

# Install Docker CLI
RUN apt-get update && apt-get install -y docker-ce-cli

# Switch back to the Jenkins user
USER jenkins

# Install Jenkins plugins using jenkins-plugin-cli
RUN jenkins-plugin-cli --plugins "blueocean docker-workflow"
docker build -t jenkins-blueocean:jdk21 .

nano docker-compose.yml

services:
  jenkins-blueocean:
    image: jenkins-blueocean:jdk21
    container_name: jenkins-blueocean
    restart: unless-stopped
    privileged: true
    user: root
    environment:
      DOCKER_HOST: tcp://docker:2376
      DOCKER_CERT_PATH: /certs/client
      DOCKER_TLS_VERIFY: 1
    ports:
      - 50000:50000
      - 50001:8080
    volumes:
      - ./data:/var/jenkins_home
      - ./client-certs:/certs/client:ro
      - /var/run/docker.sock:/var/run/docker.sock
docker compose up -d

SillyTavern

cd /home/myusername/docker
https://github.com/SillyTavern/SillyTavern.git && cd SillyTavern
docker build -t sillytavern:release . && cd docker

nano docker-compose.yml

services:
  sillytavern:
    build: ..
    image: sillytavern:release
    container_name: sillytavern
    restart: unless-stopped
    hostname: sillytavern
    ports:
      - 8123:8000
    volumes:
      - ./config:/home/node/app/config
      - ./user:/home/node/app/public/user

docker compose up -d

Immich

cd /home/myusername/docker
mkdir immich && cd "$_"

nano .env

# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables

# Connection secrets for postgres and typesense. You should change these to random passwords
TYPESENSE_API_KEY=;B^`65fTeX6c%XbaWEH
DB_PASSWORD=immich!

# DO NOT TOUCH THE LINES BELOW
###################################################################################
DB_HOSTNAME=immich_postgres
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

REDIS_HOSTNAME=immich_redis

nano docker-compose.yml

services:
  immich-server:
    container_name: immich_server
    image: ghcr.io/immich-app/immich-server:release
    restart: unless-stopped
    volumes:
      - ./library:/usr/src/app/upload
      - /etc/localtime:/etc/localtime:ro
    env_file:
      - .env
    ports:
     - 8295:2283
    depends_on:
      - redis
      - database
    healthcheck:
      disable: false
    networks:
      - production

  immich-machine-learning:
    image: ghcr.io/immich-app/immich-machine-learning:release
    container_name: immich_machine_learning
    restart: unless-stopped
    # For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.
    # Example tag: ${IMMICH_VERSION:-release}-cuda
    # extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
    #   file: hwaccel.ml.yml
    #   service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable
    volumes:
      - ./model-cache:/cache
    env_file:
      - .env
    healthcheck:
      disable: false
    networks:
      - production

  redis:
    image: docker.io/redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5
    container_name: immich_redis
    restart: unless-stopped
    healthcheck:
      test: redis-cli ping || exit 1

  database:
    container_name: immich_postgres
    image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
    env_file:
      - .env
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_DB: ${DB_DATABASE_NAME}
      POSTGRES_INITDB_ARGS: '--data-checksums'
    volumes:
      - ./db:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
      interval: 5m
      start_interval: 30s
      start_period: 5m
    command:
      [
        'postgres',
        '-c',
        'shared_preload_libraries=vectors.so',
        '-c',
        'search_path="$$user", public, vectors',
        '-c',
        'logging_collector=on',
        '-c',
        'max_wal_size=2GB',
        '-c',
        'shared_buffers=512MB',
        '-c',
        'wal_compression=on',
      ]


docker compose up -d

it-tools

cd /home/myusername/docker
mkdir it_tools && cd "$_"

nano docker-compose.yml

services:
  it_tools:
    image: ghcr.io/corentinth/it-tools:latest
    container_name: it_tools
    restart: unless-stopped
    ports:
      - 8270:80
docker compose up -d

paperless

cd /home/myusername/docker
mkdir paperless && cd "$_"

nano docker-compose.yml

services:
  broker:
    image: docker.io/library/redis:latest
    container_name: paperless_redis
    restart: unless-stopped
    volumes:
      - ./redis:/data
    networks:
      - production

  db:
    image: docker.io/library/postgres:latest
    container_name: paperless_postgres
    restart: unless-stopped
    volumes:
      - ./db:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperless
      POSTGRES_PASSWORD: paperless
    networks:
      - production

  webserver:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    container_name: paperless
    restart: unless-stopped
    depends_on:
      - db
      - broker
      - gotenberg
      - tika
    ports:
      - "8280:8000"
    volumes:
      - ./data:/usr/src/paperless/data
      - ./media:/usr/src/paperless/media
      - ./export:/usr/src/paperless/export
      - ./consume:/usr/src/paperless/consume
    env_file: .env
    environment:
      PAPERLESS_REDIS: redis://broker:6379
      PAPERLESS_DBHOST: db
      PAPERLESS_TIKA_ENABLED: 1
      PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
      PAPERLESS_TIKA_ENDPOINT: http://tika:9998
      PAPERLESS_URL: https://paperless.DOMAIN.COM
      PAPERLESS_ADMIN_USER: paperless
      PAPERLESS_ADMIN_PASSWORD: paperless
      PAPERLESS_APPS: "allauth.socialaccount.providers.openid_connect"
      PAPERLESS_SOCIALACCOUNT_PROVIDERS: '{"openid_connect": {"APPS": [{"provider_id": "authentik","name": "Authentik SSO","client_id": "IMPORT_CLIENT_ID_HERE","secret": "IMPORT_SECRET_HERE","settings": { "server_url": "IMPORT_SERVER_URL_HERE"}}]}}'
    networks:
      - production

  gotenberg:
    image: docker.io/gotenberg/gotenberg:latest
    container_name: paperless_gotenberg
    restart: unless-stopped

    # The gotenberg chromium route is used to convert .eml files. We do not
    # want to allow external content like tracking pixels or even javascript.
    command:
      - "gotenberg"
      - "--chromium-disable-javascript=true"
      - "--chromium-allow-list=file:///tmp/.*"
    networks:
      - production

  tika:
    image: ghcr.io/paperless-ngx/tika:latest
    container_name: paperless_tika
    restart: unless-stopped
    networks:
      - production


networks:
  production:
    external: true
docker compose up -d

Configure Paperless with Authentik

  1. Go to: Admin interface > Applications > Providers
  2. Click on: Create
  3. Select: OAuth2/OpenID Provider then click Next
  4. Insert the following settings then click on Finish:

Make sure to save the Client ID and Client Secret because you need it later for PAPERLESS_SOCIALACCOUNT_PROVIDERS in docker-compose.yml

  1. Go to: Admin interface > Applications > Applications
  2. Click on: Create
  3. Insert the following settings then click on Create:
  1. Go to: Admin interface > Applications > Providers
  2. Click on Paperless

Make sure to save the OpenID Configuration URL because you need it later for PAPERLESS_SOCIALACCOUNT_PROVIDERS in docker-compose.yml

  1. In docker-compose.yml find PAPERLESS_SOCIALACCOUNT_PROVIDERS then replace the following:

AzuraCast

cd /home/myusername/docker
mkdir azuracast && cd "$_"

nano docker-compose.yml

services:
  azuracast:
    image: ghcr.io/azuracast/azuracast:latest
    container_name: azuracast
    restart: unless-stopped
    environment:
      PUID: 1000
      PGID: 1000
      APPLICATION_ENV: production # Valid options: production, development, testing
      COMPOSER_PLUGIN_MODE: false
      SHOW_DETAILED_ERRORS: false
      AUTO_ASSIGN_PORT_MIN: 8500
      AUTO_ASSIGN_PORT_MAX: 8600
      # Database Configuration
      MYSQL_DATABASE: azuracast
      MYSQL_USER: azuracast
      MYSQL_PASSWORD: azuracast!
      MYSQL_ROOT_PASSWORD: azuracast!!
      MYSQL_HOST: localhost
      MYSQL_PORT: 3306
      MYSQL_SLOW_QUERY_LOG: 0
      MYSQL_MAX_CONNECTIONS: 100
      MYSQL_INNODB_BUFFER_POOL_SIZE: 128M
      MYSQL_INNODB_LOG_FILE_SIZE: 16M
      # Redis Configuration
      ENABLE_REDIS: true
      REDIS_HOST: localhost
      REDIS_PORT: 6379
      REDIS_DB: 1
      # Advanced Configuration
    ports:
      - 9150:80
#      - 9151:443 # optional
#      - 9152:2022 # SFTP optional
      - 11500-11600:8500-8600 # Ports to assign radio stations https://www.azuracast.com/docs/administration/docker/#using-non-standard-ports
    volumes:
      - ./stations:/var/azuracast/stations
      - ./backups:/var/azuracast/backups
      - ./db:/var/lib/mysql
      - ./storage/uploads:/var/azuracast/storage/uploads
      - ./storage/shoutcast2:/var/azuracast/storage/shoutcast2
      - ./storage/stereo_tool:/var/azuracast/storage/stereo_tool
      - ./storage/geoip:/var/azuracast/storage/geoip
      - ./storage/sftpgo_data:/var/azuracast/storage/sftpgo
      - ./storage/acme:/var/azuracast/storage/acme
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    logging:
      options:
        max-size: "1m"
        max-file: "5"
docker compose up -d

Visual Studio Code Server

cd /home/myusername/docker
mkdir code-server && cd "$_"

nano docker-compose.yml

services:
  code-server:
    image: lscr.io/linuxserver/code-server:latest
    container_name: code-server
    restart: unless-stopped
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Etc/UTC
#      PASSWORD: #optional
#      HASHED_PASSWORD= #optional
#      SUDO_PASSWORD: password #optional
#      SUDO_PASSWORD_HASH: #optional
#      PROXY_DOMAIN: vscode.DOMAIN.COM #optional
      DEFAULT_WORKSPACE: /config/workspace #optional
    volumes:
      - ./config:/config
    ports:
      - 8350:8443
docker compose up -d

vichan

cd /home/myusername/docker
git clone https://github.com/vichan-devel/vichan.git && cd vichan
docker compose up -d --build

Visit: https://chan.DOMAIN.COM/install.php

Configure vichan

Database connection parameters
Server: container_name
Database: vichan
Username: vichan
Password: MYSQL_PASSWORD

nano /local-instances/0/www/inc/secrets.php
$config['cookies']['secure_login_only'] = 0;

# 1 = for proxy
# 0 = for NO proxy
  1. Visit: https://chan.DOMAIN.COM/mod.php
  2. Login with:

ghost

cd /home/myusername/docker
mkdir ghostblog && cd "$_"

nano docker-compose.yml

services:
  db:
    image: mariadb:latest
    container_name: ghostblog-mariadb
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ghost
      MYSQL_USER: ghost
      MYSQL_PASSWORD: ghost!
      MYSQL_ROOT_PASSWORD: ghost!!
    volumes:
      - ./db:/var/lib/mysql

  ghost:
    image: ghost:latest
    container_name: ghostblog
    restart: unless-stopped
    environment:
      url: https://blog.DOMAIN.COM
      database__client: mysql
      database__connection__host: db
      database__connection__user: ghost
      database__connection__password: ghost!
      database__connection__database: ghost
    volumes:
        - ./data:/var/lib/ghost/content
        # - ./themes:/var/lib/ghost/content/themes
        - ./config.production.json:/var/lib/ghost/config.production.json:ro
    ports:
      - 8174:2368
    depends_on:
      - db
nano config.production.json
{
    "url": "http://localhost:2368",
    "server": {
    "port": 2368,
    "host": "::"
    },
    "mail": {
        "transport": "SMTP",
        "from": "[email protected]",
        "options": {
            "host": "mail.DOMAIN.COM",
            "port": 587,
            "secure": false,
            "auth": {
                "user": "[email protected]",
                "pass": "REPLACE_WITH_YOUR_EMAIL_PASSWORD"
            }
        }
    },
    "logging": {
    "transports": [
        "file",
        "stdout"
    ]
    },
    "process": "systemd",
    "paths": {
    "contentPath": "/var/lib/ghost/content"
    }
}
docker compose up -d

Configure Ghost

To create admin account visit: https://blog.DOMAIN.COM/ghost or http://192.168.x.x:8174/ghost

Neko vrchat

cd /home/myusername/docker
mkdir neko && cd "$_"
mkdir -p data/profile && sudo chown -R 1000:1000 data/profile && cat > data/policy.json <<'EOF'
{
  "policies": {
    "SanitizeOnShutdown": false,
    
    "Homepage": {
      "URL": "https://www.youtube.com",
      "Locked": false,
      "StartPage": "homepage"
    },

    "ManagedBookmarks": [
      {
        "toplevel_name": "🎬 Watch Party Links"
      },
      {
        "name": "YouTube",
        "url": "https://www.youtube.com"
      },
      {
        "name": "Twitch",
        "url": "https://www.twitch.tv"
      },
      {
        "name": "Odysee",
        "url": "https://odysee.com"
      },

      {
        "name": "🎮 Fun & Entertainment",
        "children": [
          {
            "name": "Radio Garden",
            "url": "https://radio.garden"
          },
          {
            "name": "Internet Archive Movies",
            "url": "https://archive.org/details/movies"
          },
          {
            "name": "Famelack - World Wide TV & Radio",
            "url": "https://famelack.com"
          },
          {
            "name": "OpenGuessr",
            "url": "https://www.openguessr.com"
          },
          {
            "name": "Neal.fun",
            "url": "https://neal.fun"
          },
          {
            "name": "Akinator",
            "url": "https://en.akinator.com"
          },
          {
            "name": "Earth View",
            "url": "https://earthview.withgoogle.com"
          }
        ]
      }
    ],

    "DisableTelemetry": true,
    "DisableFirefoxStudies": true,
    "DisablePocket": true,
    "DontCheckDefaultBrowser": true,
    "OverrideFirstRunPage": "",
    "OverridePostUpdatePage": "",
    "DisplayBookmarksToolbar": "always",
    
    "DisableFirefoxAccounts": true,
    "OfferToSaveLogins": false,
    "PasswordManagerEnabled": false,
    "DisableAppUpdate": true,
    "DisableProfileImport": true,
    "CaptivePortal": false,
    "HardwareAcceleration": true,
    
    "Autoplay": {
      "Default": "allow-audio-video"
    },
    
    "Preferences": {
      "browser.aboutwelcome.enabled": false,
      "browser.newtabpage.activity-stream.showSponsoredTopSites": false,
      "browser.newtabpage.activity-stream.showSponsored": false,
      "browser.newtabpage.activity-stream.feeds.topsites": false,
      "browser.urlbar.suggest.quicksuggest.sponsored": false,
      "media.eme.enabled": true,
      "media.gmp-widevinecdm.visible": true,
      "media.gmp-widevinecdm.enabled": true
    },
    
    "ExtensionSettings": {
      "*": {
        "installation_mode": "blocked"
      },
      "[email protected]": {
        "install_url": "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi",
        "installation_mode": "force_installed"
      },
      "[email protected]": {
        "install_url": "https://addons.mozilla.org/firefox/downloads/latest/darkreader/latest.xpi",
        "installation_mode": "force_installed"
      },
      "[email protected]": {
        "install_url": "https://addons.mozilla.org/firefox/downloads/latest/sponsorblock/latest.xpi",
        "installation_mode": "force_installed"
      }
    }
  }
}
EOF

nano docker-compose.yml

services:
  neko:
    image: ghcr.io/m1k1o/neko/intel-firefox:latest
    container_name: neko
    restart: unless-stopped
    shm_size: 4gb
    devices:
      - /dev/dri:/dev/dri # Required for hardware acceleration
    group_add:
      - video # Required for hardware acceleration
      - render # Required for hardware acceleration
    # cap_add:
    #   - SYS_ADMIN # Required for chrome browsers to boot its sandbox on modern Linux kernels
    # security_opt:
    #   - seccomp=unconfined # Required for chrome browsers to boot its sandbox on modern Linux kernels
    #   - apparmor=unconfined # Required for chrome browsers to boot its sandbox on modern Linux kernels
    ports:
      - "9350:8080"
      - "52000:52000/udp"
      - "52000:52000/tcp"
    volumes:
      - ./data/profile:/home/neko/.mozilla/firefox/profile.default
      - ./data/policy.json:/usr/lib/firefox/distribution/policies.json
    environment:
      TZ: Etc/UTC
      LIBVA_DRIVER_NAME: iHD

      # --- UI & Auth ---
      NEKO_DESKTOP_SCREEN: 1920x1080@30
      NEKO_MEMBER_PROVIDER: multiuser
      NEKO_MEMBER_MULTIUSER_USER_PASSWORD: "neko"
      NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: "NekoPurr123!"
      NEKO_SESSION_CONTROL_PROTECTION: "true"
      NEKO_SERVER_PROXY: "true"

      # --- WebRTC Settings ---
      NEKO_WEBRTC_ICELITE: "true"
      # BY USING YOUR LOCAL IP HERE, NO FIREWALL PORT FORWARD IS NEEDED (Local/VPN use only)
      NEKO_WEBRTC_NAT1TO1: "192.168.1.95"
      NEKO_WEBRTC_UDPMUX: 52000
      NEKO_WEBRTC_TCPMUX: 52000

      # --- WebRTC Pipeline (For your Browser UI, Hardware Accelerated) ---
      NEKO_CAPTURE_VIDEO_CODEC: h264
      NEKO_CAPTURE_VIDEO_PIPELINE: "ximagesrc display-name={display} show-pointer=true use-damage=false ! video/x-raw,framerate=30/1 ! videoconvert ! video/x-raw,format=NV12 ! vaapih264enc rate-control=vbr bitrate=6000 keyframe-period=120 ! appsink name=appsink"

      # --- Broadcast RTMP Pipeline (For VRChat, Hardware Accelerated) ---
      NEKO_CAPTURE_BROADCAST_AUTOSTART: "true"
      NEKO_CAPTURE_BROADCAST_URL: "rtmp://mediamtx:1935/vrc"
      NEKO_CAPTURE_BROADCAST_PIPELINE: "flvmux name=mux ! rtmpsink location={url} pulsesrc device={device} ! audio/x-raw,channels=2 ! audioconvert ! queue ! voaacenc bitrate=320000 ! audio/mpeg,rate=48000 ! mux. ximagesrc display-name={display} show-pointer=false use-damage=false ! video/x-raw,framerate=30/1 ! videoconvert ! video/x-raw,format=NV12 ! queue ! vaapih264enc rate-control=cbr bitrate=6144 keyframe-period=60 quality-level=2 ! h264parse ! video/x-h264,profile=main ! mux."

  mediamtx:
    image: bluenviron/mediamtx:latest-ffmpeg
    container_name: mediamtx
    restart: unless-stopped
    ports:
      - "8888:8888" # Only HLS port needs to be exposed for VRChat
    environment:
      MTX_RTSPTRANSPORTS: tcp
      MTX_HLSALWAYSREMUX: "yes"
      MTX_HLSVARIANT: mpegts
      MTX_HLSSEGMENTCOUNT: 7
      MTX_HLSSEGMENTDURATION: 2s