├── lemmy ├── sample.env.postfix ├── img │ ├── games.png │ ├── humor.png │ └── steve-wozniak-head.png ├── sample.env.postgres ├── sample.env.lemmy-ui ├── sample.lemmy.hjson ├── sample.env.pictrs ├── customPostgresql.conf ├── backup.sh ├── restore.sh ├── compose.yml └── nginx_internal.conf ├── homepage ├── public │ ├── logo.png │ ├── favicon.ico │ └── icons │ │ ├── lemmy.jpg │ │ ├── calibre.jpg │ │ ├── gitlab.jpg │ │ ├── proxmox.png │ │ ├── router.png │ │ ├── shamir.jpg │ │ ├── authelia.png │ │ ├── mastodon.jpg │ │ ├── miniflux.jpg │ │ ├── portainer.png │ │ ├── synology.png │ │ ├── wastebin.jpg │ │ ├── roher-twins.png │ │ ├── jellyfin.svg │ │ └── home-assistant.svg ├── compose.yml └── config.json ├── .gitignore ├── shamir └── compose.yml ├── nginx ├── sample.env.authelia_users_database.yml ├── backup.sh ├── readme.md ├── renew.sh ├── restore.sh ├── sites │ ├── default.conf │ ├── default.conf.sample │ ├── authelia.conf │ ├── homepage.conf │ ├── shamir.conf │ ├── gitlab.conf │ ├── miniflux.conf │ ├── lemmy.conf │ ├── jellyfin.conf │ ├── portainer.conf │ └── mastodon.conf ├── snippets │ ├── authelia-authrequest.conf │ ├── authelia-location.conf │ ├── proxy.conf │ └── ssl.conf ├── compose.yml └── sample.env.authelia_configuration.yml ├── portainer ├── compose.yml ├── backup.sh └── restore.sh ├── calibre ├── backup.sh ├── compose.yml └── restore.sh ├── miniflux ├── backup.sh ├── compose.yml └── restore.sh ├── jellyfin ├── backup.sh ├── compose.yml └── restore.sh ├── gitlab ├── compose.yml ├── sample.gitlab.rb ├── backup.sh ├── readme.md └── restore.sh ├── mastodon ├── backup.sh ├── restore.sh ├── readme.md └── compose.yml ├── backup-all.sh └── readme.md /lemmy/sample.env.postfix: -------------------------------------------------------------------------------- 1 | POSTFIX_myhostname={{ domain }} -------------------------------------------------------------------------------- /lemmy/img/games.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/lemmy/img/games.png -------------------------------------------------------------------------------- /lemmy/img/humor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/lemmy/img/humor.png -------------------------------------------------------------------------------- /lemmy/sample.env.postgres: -------------------------------------------------------------------------------- 1 | POSTGRES_USER=lemmy 2 | POSTGRES_PASSWORD={{ postgres_password }} 3 | POSTGRES_DB=lemmy -------------------------------------------------------------------------------- /homepage/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/logo.png -------------------------------------------------------------------------------- /homepage/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/favicon.ico -------------------------------------------------------------------------------- /homepage/public/icons/lemmy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/lemmy.jpg -------------------------------------------------------------------------------- /homepage/public/icons/calibre.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/calibre.jpg -------------------------------------------------------------------------------- /homepage/public/icons/gitlab.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/gitlab.jpg -------------------------------------------------------------------------------- /homepage/public/icons/proxmox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/proxmox.png -------------------------------------------------------------------------------- /homepage/public/icons/router.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/router.png -------------------------------------------------------------------------------- /homepage/public/icons/shamir.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/shamir.jpg -------------------------------------------------------------------------------- /lemmy/img/steve-wozniak-head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/lemmy/img/steve-wozniak-head.png -------------------------------------------------------------------------------- /homepage/public/icons/authelia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/authelia.png -------------------------------------------------------------------------------- /homepage/public/icons/mastodon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/mastodon.jpg -------------------------------------------------------------------------------- /homepage/public/icons/miniflux.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/miniflux.jpg -------------------------------------------------------------------------------- /homepage/public/icons/portainer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/portainer.png -------------------------------------------------------------------------------- /homepage/public/icons/synology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/synology.png -------------------------------------------------------------------------------- /homepage/public/icons/wastebin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/wastebin.jpg -------------------------------------------------------------------------------- /lemmy/sample.env.lemmy-ui: -------------------------------------------------------------------------------- 1 | LEMMY_UI_LEMMY_INTERNAL_HOST=lemmy:8536 2 | LEMMY_UI_LEMMY_EXTERNAL_HOST=lemmy.starbase80.dev 3 | LEMMY_UI_HTTPS=true -------------------------------------------------------------------------------- /homepage/public/icons/roher-twins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notclickable-jordan/docker-symphony/HEAD/homepage/public/icons/roher-twins.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | */env.* 3 | */*.env 4 | *.tgz 5 | *.pem 6 | homepage/config/logs 7 | nginx/sites/default.* 8 | lemmy/lemmy.hjson 9 | gitlab/gitlab.rb -------------------------------------------------------------------------------- /shamir/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | shamir: 3 | image: jordanroher/shamirs-secret-sharing-scheme 4 | container_name: shamir 5 | ports: 6 | - 8200:80 7 | restart: unless-stopped -------------------------------------------------------------------------------- /nginx/sample.env.authelia_users_database.yml: -------------------------------------------------------------------------------- 1 | users: 2 | jordan: 3 | displayname: "Jordan Roher" 4 | password: "HASH" # hash using: docker run authelia/authelia:latest authelia crypto hash generate argon2 --password 'password' 5 | email: jordan@website.com 6 | groups: 7 | - admins 8 | - dev -------------------------------------------------------------------------------- /portainer/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | portainer: 3 | image: portainer/portainer-ce:linux-amd64-2.19.1 4 | container_name: portainer 5 | restart: unless-stopped 6 | volumes: 7 | - /var/run/docker.sock:/var/run/docker.sock 8 | - data:/data 9 | ports: 10 | - 8160:9000 11 | 12 | volumes: 13 | data: -------------------------------------------------------------------------------- /calibre/backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set variables 4 | BackupContainer="calibre" 5 | 6 | File1="calibre-config.tgz" 7 | Folder1="/config" 8 | 9 | # Backup existing volumes by tarring and gzipping them 10 | docker run --rm --volumes-from ${BackupContainer} \ 11 | -v $(pwd):/backup ${Image} sh -c \ 12 | "tar -C ${Folder1} -cvzf /backup/${File1} ." 13 | 14 | # Copy to external drive and overwrite if files already exist 15 | cp "./${File1}" "${BackupFolder}/${dateString}/${File1}" -f 16 | -------------------------------------------------------------------------------- /portainer/backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set variables 4 | BackupContainer="portainer" 5 | 6 | File1="portainer-data.tgz" 7 | Folder1="/data" 8 | 9 | # Backup existing volumes by tarring and gzipping them 10 | docker run --rm --volumes-from ${BackupContainer} \ 11 | -v $(pwd):/backup ${Image} sh -c \ 12 | "tar -C ${Folder1} -cvzf /backup/${File1} ." 13 | 14 | # Copy to external drive and overwrite if files already exist 15 | cp "./${File1}" "${BackupFolder}/${dateString}/${File1}" -f 16 | -------------------------------------------------------------------------------- /miniflux/backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set variables 4 | BackupContainer="miniflux_db" 5 | 6 | File1="miniflux-db.tgz" 7 | Folder1="/var/lib/postgresql/data" 8 | 9 | # Backup existing volumes by tarring and gzipping them 10 | docker run --rm --volumes-from ${BackupContainer} \ 11 | -v $(pwd):/backup ${Image} sh -c \ 12 | "tar -C ${Folder1} -cvzf /backup/${File1} ." 13 | 14 | # Copy to external drive and overwrite if files already exist 15 | cp "./${File1}" "${BackupFolder}/${dateString}/${File1}" -f 16 | -------------------------------------------------------------------------------- /homepage/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | homepage: 3 | image: jordanroher/starbase-80:latest 4 | container_name: homepage 5 | ports: 6 | - 8090:4173 7 | restart: unless-stopped 8 | environment: 9 | - TITLE=Starbase 80 10 | - LOGO=/logo.png 11 | - NEWWINDOW=false 12 | volumes: 13 | - ./config.json:/app/src/config/config.json 14 | - ./public/favicon.ico:/app/public/favicon.ico 15 | - ./public/logo.png:/app/public/logo.png 16 | - ./public/icons:/app/public/icons -------------------------------------------------------------------------------- /calibre/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | calibre: 3 | image: linuxserver/calibre-web:latest 4 | container_name: calibre 5 | environment: 6 | - PUID=1000 7 | - PGID=1000 8 | - TZ=America/Los_Angeles 9 | - DOCKER_MODS=linuxserver/mods:universal-calibre #optional 10 | - OAUTHLIB_RELAX_TOKEN_SCOPE=1 #optional 11 | volumes: 12 | - config:/config 13 | - /mnt/synology/downloads/Calibre:/books 14 | ports: 15 | - 8170:8083 16 | restart: unless-stopped 17 | 18 | volumes: 19 | config: -------------------------------------------------------------------------------- /lemmy/sample.lemmy.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # for more info about the config, check out the documentation 3 | # https://join-lemmy.org/docs/en/administration/configuration.html 4 | 5 | database: { 6 | host: postgres 7 | password: "password" 8 | } 9 | hostname: "lemmy.starbase80.dev" 10 | pictrs: { 11 | url: "http://pictrs:8080/" 12 | api_key: "password" 13 | } 14 | email: { 15 | smtp_server: "smtp.sendgrid.net:465" 16 | smtp_from_address: "lemmy@starbase80.dev" 17 | tls_type: "tls", 18 | smtp_login: "apikey", 19 | smtp_password: "password" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /miniflux/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | miniflux: 3 | image: miniflux/miniflux 4 | container_name: miniflux 5 | env_file: env.miniflux 6 | restart: unless-stopped 7 | ports: 8 | - 8050:8080 9 | depends_on: 10 | db: 11 | condition: service_healthy 12 | 13 | db: 14 | image: postgres:15 15 | container_name: miniflux_db 16 | env_file: env.postgres 17 | restart: unless-stopped 18 | healthcheck: 19 | test: ["CMD", "pg_isready", "-U", "miniflux"] 20 | interval: 10s 21 | start_period: 30s 22 | volumes: 23 | - db:/var/lib/postgresql/data 24 | 25 | volumes: 26 | db: -------------------------------------------------------------------------------- /miniflux/restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables 4 | File1="miniflux-db.tgz" 5 | Volume1="miniflux_db" 6 | Folder1="/restore/${Volume1}" 7 | 8 | # Bring down the existing site 9 | docker compose down -v 10 | 11 | # Bring up the containers to recreate the volumes 12 | docker compose up -d --build db 13 | docker compose down 14 | 15 | # Restore the volume data from the backups 16 | docker run --rm \ 17 | -v "$(pwd)/${File1}:/backup/${File1}" \ 18 | -v "${Volume1}:${Folder1}" \ 19 | alpine:3.17.2 sh -c \ 20 | "tar -xvzf /backup/${File1} -C ${Folder1}" 21 | 22 | # Restore the site with the data 23 | docker compose up -d 24 | -------------------------------------------------------------------------------- /calibre/restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables 4 | File1="calibre-config.tgz" 5 | Volume1="calibre_config" 6 | Folder1="/restore/${Volume1}" 7 | 8 | # Bring down the existing site 9 | docker-compose down -v 10 | 11 | # Bring up the containers to recreate the volumes 12 | docker-compose up -d --build calibre 13 | docker-compose down 14 | 15 | # Restore the volume data from the backups 16 | docker run --rm \ 17 | -v "$(pwd)/${File1}:/backup/${File1}" \ 18 | -v "${Volume1}:${Folder1}" \ 19 | alpine:3.17.2 sh -c \ 20 | "tar -xvzf /backup/${File1} -C ${Folder1}" 21 | 22 | # Restore the site with the data 23 | docker-compose up -d 24 | -------------------------------------------------------------------------------- /lemmy/sample.env.pictrs: -------------------------------------------------------------------------------- 1 | PICTRS_OPENTELEMETRY_URL=http://otel:4137 2 | PICTRS__API_KEY= 3 | RUST_LOG=debug 4 | RUST_BACKTRACE=full 5 | PICTRS__MEDIA__VIDEO_CODEC=vp9 6 | PICTRS__MEDIA__GIF__MAX_WIDTH=256 7 | PICTRS__MEDIA__GIF__MAX_HEIGHT=256 8 | PICTRS__MEDIA__GIF__MAX_AREA=65536 9 | PICTRS__MEDIA__GIF__MAX_FRAME_COUNT=400 10 | 11 | PICTRS__STORE__TYPE=object_storage 12 | PICTRS__STORE__ENDPOINT=http://s3-us-west-2.amazonaws.com 13 | PICTRS__STORE__BUCKET_NAME=lemmy-starbase80-dev 14 | PICTRS__STORE__REGION=us-west-2 15 | PICTRS__STORE__USE_PATH_STYLE=false 16 | PICTRS__STORE__ACCESS_KEY= 17 | PICTRS__STORE__SECRET_KEY= 18 | -------------------------------------------------------------------------------- /portainer/restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables 4 | File1="portainer-data.tgz" 5 | Volume1="portainer_data" 6 | Folder1="/restore/${Volume1}" 7 | 8 | # Bring down the existing site 9 | docker compose down -v 10 | 11 | # Bring up the containers to recreate the volumes 12 | docker compose up -d --build portainer 13 | docker compose down 14 | 15 | # Restore the volume data from the backups 16 | docker run --rm \ 17 | -v "$(pwd)/${File1}:/backup/${File1}" \ 18 | -v "${Volume1}:${Folder1}" \ 19 | alpine:3.17.2 sh -c \ 20 | "tar -xvzf /backup/${File1} -C ${Folder1}" 21 | 22 | # Restore the site with the data 23 | docker compose up -d 24 | -------------------------------------------------------------------------------- /jellyfin/backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set variables 4 | BackupContainer="jellyfin" 5 | 6 | File1="jellyfin-config.tgz" 7 | Folder1="/config" 8 | 9 | File2="jellyfin-cache.tgz" 10 | Folder2="/cache" 11 | 12 | # Backup existing volumes by tarring and gzipping them 13 | docker run --rm --volumes-from ${BackupContainer} \ 14 | -v $(pwd):/backup ${Image} sh -c \ 15 | "tar -C ${Folder1} -cvzf /backup/${File1} . && \ 16 | tar -C ${Folder2} -cvzf /backup/${File2} ." 17 | 18 | # Copy to external drive and overwrite if files already exist 19 | cp "./${File1}" "${BackupFolder}/${dateString}/${File1}" -f 20 | cp "./${File2}" "${BackupFolder}/${dateString}/${File2}" -f 21 | -------------------------------------------------------------------------------- /nginx/backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set variables 4 | BackupContainer="switchboard_backup" 5 | 6 | File1="nginx-letsencrypt.tgz" 7 | Folder1="/etc/letsencrypt" 8 | 9 | File2="nginx-authelia-db.tgz" 10 | Folder2="/var/lib/postgresql/data" 11 | 12 | # Backup existing volumes by tarring and gzipping them 13 | docker run --rm --volumes-from ${BackupContainer} \ 14 | -v $(pwd):/backup ${Image} sh -c \ 15 | "tar -C ${Folder1} -cvzf /backup/${File1} . && \ 16 | tar -C ${Folder2} -cvzf /backup/${File2} ." 17 | 18 | # Copy to external drive and overwrite if files already exist 19 | cp "./${File1}" "${BackupFolder}/${dateString}/${File1}" -f 20 | cp "./${File2}" "${BackupFolder}/${dateString}/${File2}" -f 21 | -------------------------------------------------------------------------------- /nginx/readme.md: -------------------------------------------------------------------------------- 1 | # Authelia 2 | 3 | Setting up two factor authentication requires clicking a link in an email. 4 | 5 | Emails sent from this local server will not be delivered. 6 | 7 | To get the link, open **env.authelia_notification.txt** in this folder. 8 | 9 | # OIDC 10 | 11 | Setting up OIDC for Outline authentication 12 | 13 | 1. Generate a private key 14 | ``` bash 15 | openssl genrsa -out authelia-private.pem 4096 16 | openssl rsa -in authelia-private.pem -outform PEM -pubout -out authelia-public.pem 17 | ``` 18 | 19 | # nginx conf file override 20 | 21 | When pulling updates to nginx conf files, the site may fail with a permissions issue. Run this command to fix it: 22 | 23 | ``` bash 24 | sudo chown -R $USER:$USER ./sites 25 | ``` -------------------------------------------------------------------------------- /nginx/renew.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" 3 | 4 | # Log file path 5 | LOG_FILE="/home/jordan/cron/renew.log" 6 | 7 | # Truncate log file to 1 megabyte 8 | truncate -s 1M "$LOG_FILE" 9 | 10 | # Redirect stdout and stderr to the log file 11 | exec &> >(tee -a "$LOG_FILE") 12 | 13 | echo "nginx/renew.sh: $(date)" 14 | 15 | # Run letsencrypt container and remove it after it exits 16 | docker compose -f /home/jordan/docker-symphony/nginx/compose.yml run --rm --workdir /home/jordan/docker-symphony/nginx letsencrypt 17 | 18 | # Reload nginx configuration in the switchboard container 19 | cd /home/jordan/docker-symphony/nginx 20 | docker exec switchboard nginx -s reload 21 | -------------------------------------------------------------------------------- /jellyfin/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | jellyfin: 3 | image: jellyfin/jellyfin 4 | container_name: jellyfin 5 | user: 1000:1000 6 | ports: 7 | - 8030:8096 8 | volumes: 9 | - config:/config 10 | - cache:/cache 11 | - /mnt/synology/video:/video 12 | - /mnt/synology/manga:/manga 13 | - /mnt/synology/downloads/Calibre:/calibre 14 | restart: unless-stopped 15 | # Optional - alternative address used for autodiscovery 16 | environment: 17 | - JELLYFIN_PublishedServerUrl=https://jellyfin.starbase80.dev 18 | # Optional - may be necessary for docker healthcheck to pass if running in host network mode 19 | # extra_hosts: 20 | # - "host.docker.internal:host-gateway" 21 | 22 | volumes: 23 | cache: 24 | config: 25 | -------------------------------------------------------------------------------- /gitlab/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | gitlab: 3 | image: gitlab/gitlab-ce:latest 4 | container_name: gitlab 5 | restart: always 6 | hostname: 'gitlab.starbase80.dev' 7 | environment: 8 | GITLAB_OMNIBUS_CONFIG: "from_file('/gitlab.rb')" 9 | ports: 10 | - 8280:80 11 | - 8281:22 12 | volumes: 13 | - config:/etc/gitlab 14 | - logs:/var/log/gitlab 15 | - data:/var/opt/gitlab 16 | - runner:/etc/gitlab-runner:ro 17 | - ./gitlab.rb:/gitlab.rb:ro 18 | shm_size: '256m' 19 | 20 | runner: 21 | image: gitlab/gitlab-runner:latest 22 | container_name: gitlab_runner 23 | restart: always 24 | volumes: 25 | - /var/run/docker.sock:/var/run/docker.sock 26 | - runner:/etc/gitlab-runner 27 | 28 | volumes: 29 | config: 30 | logs: 31 | data: 32 | runner: -------------------------------------------------------------------------------- /lemmy/customPostgresql.conf: -------------------------------------------------------------------------------- 1 | # DB Version: 15 2 | # OS Type: linux 3 | # DB Type: web 4 | # Total Memory (RAM): 8 GB 5 | # CPUs num: 4 6 | # Data Storage: ssd 7 | 8 | max_connections = 200 9 | shared_buffers = 2GB 10 | effective_cache_size = 6GB 11 | maintenance_work_mem = 512MB 12 | checkpoint_completion_target = 0.9 13 | checkpoint_timeout = 86400 14 | wal_buffers = 16MB 15 | default_statistics_target = 100 16 | random_page_cost = 1.1 17 | effective_io_concurrency = 200 18 | work_mem = 5242kB 19 | min_wal_size = 1GB 20 | max_wal_size = 30GB 21 | max_worker_processes = 4 22 | max_parallel_workers_per_gather = 2 23 | max_parallel_workers = 4 24 | max_parallel_maintenance_workers = 2 25 | 26 | # Other custom params 27 | temp_file_size=1GB 28 | synchronous_commit=off 29 | # This one shouldn't be on regularly, because DB migrations often take a long time 30 | # statement_timeout = 10000 -------------------------------------------------------------------------------- /lemmy/backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set variables 4 | BackupContainer="lemmy_backup" 5 | 6 | File1="lemmy-extra_themes.tgz" 7 | Folder1="/app/extra_themes" 8 | 9 | File2="lemmy-pictrs.tgz" 10 | Folder2="/mnt" 11 | 12 | File3="lemmy-postgres.tgz" 13 | Folder3="/var/lib/postgresql/data" 14 | 15 | # Backup existing volumes by tarring and gzipping them 16 | docker run --rm --volumes-from ${BackupContainer} \ 17 | -v $(pwd):/backup ${Image} sh -c \ 18 | "tar -C ${Folder1} -cvzf /backup/${File1} . && \ 19 | tar -C ${Folder2} -cvzf /backup/${File2} . && \ 20 | tar -C ${Folder3} -cvzf /backup/${File3} . " 21 | 22 | # Copy to external drive and overwrite if files already exist 23 | cp "./${File1}" "${BackupFolder}/${dateString}/${File1}" -f 24 | cp "./${File2}" "${BackupFolder}/${dateString}/${File2}" -f 25 | cp "./${File3}" "${BackupFolder}/${dateString}/${File3}" -f 26 | -------------------------------------------------------------------------------- /mastodon/backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set variables 4 | BackupContainer="mastodon_backup" 5 | 6 | File1="mastodon-web.tgz" 7 | Folder1="/mastodon/public/system" 8 | 9 | File2="mastodon-redis.tgz" 10 | Folder2="/data" 11 | 12 | File3="mastodon-db.tgz" 13 | Folder3="/var/lib/postgresql/data" 14 | 15 | # Backup existing volumes by tarring and gzipping them 16 | docker run --rm --volumes-from ${BackupContainer} \ 17 | -v $(pwd):/backup ${Image} sh -c \ 18 | "tar -C ${Folder1} -cvzf /backup/${File1} . && \ 19 | tar -C ${Folder2} -cvzf /backup/${File2} . && \ 20 | tar -C ${Folder3} -cvzf /backup/${File3} ." 21 | 22 | # Copy to external drive and overwrite if files already exist 23 | cp "./${File1}" "${BackupFolder}/${dateString}/${File1}" -f 24 | cp "./${File2}" "${BackupFolder}/${dateString}/${File2}" -f 25 | cp "./${File3}" "${BackupFolder}/${dateString}/${File3}" -f 26 | -------------------------------------------------------------------------------- /jellyfin/restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables 4 | File1="jellyfin-config.tgz" 5 | Volume1="jellyfin_config" 6 | Folder1="/restore/${Volume1}" 7 | 8 | File2="jellyfin-cache.tgz" 9 | Volume2="jellyfin_cache" 10 | Folder2="/restore/${Volume2}" 11 | 12 | # Bring down the existing site 13 | docker-compose down -v 14 | 15 | # Bring up the containers to recreate the volumes 16 | docker-compose up -d --build jellyfin 17 | docker-compose down 18 | 19 | # Restore the volume data from the backups 20 | docker run --rm \ 21 | -v "$(pwd)/${File1}:/backup/${File1}" \ 22 | -v "$(pwd)/${File2}:/backup/${File2}" \ 23 | -v "${Volume1}:${Folder1}" \ 24 | -v "${Volume2}:${Folder2}" \ 25 | alpine:3.17.2 sh -c \ 26 | "tar -xvzf /backup/${File1} -C ${Folder1} && \ 27 | tar -xvzf /backup/${File2} -C ${Folder2}" 28 | 29 | # Restore the site with the data 30 | docker-compose up -d 31 | -------------------------------------------------------------------------------- /gitlab/sample.gitlab.rb: -------------------------------------------------------------------------------- 1 | external_url 'http://gitlab.starbase80.dev'; 2 | gitlab_rails['smtp_enable'] = true; 3 | gitlab_rails['smtp_address'] = "smtp.sendgrid.net"; 4 | gitlab_rails['smtp_port'] = 587; 5 | gitlab_rails['smtp_user_name'] = "apikey"; 6 | gitlab_rails['smtp_password'] = "PASSWORD"; 7 | gitlab_rails['smtp_domain'] = "smtp.sendgrid.net"; 8 | gitlab_rails['smtp_authentication'] = "plain"; 9 | gitlab_rails['smtp_enable_starttls_auto'] = true; 10 | gitlab_rails['smtp_tls'] = false; 11 | # If use Single Sender Verification You must configure from. If not fail 12 | # 550 The from address does not match a verified Sender Identity. Mail cannot be sent until this error is resolved. 13 | # Visit https://sendgrid.com/docs/for-developers/sending-email/sender-identity/ to see the Sender Identity requirements 14 | gitlab_rails['gitlab_email_from'] = 'gitlab@starbase80.dev'; 15 | gitlab_rails['gitlab_email_reply_to'] = 'gitlab@starbase80.dev'; -------------------------------------------------------------------------------- /nginx/restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables 4 | File1="nginx-letsencrypt.tgz" 5 | VolumeName1="nginx_letsencrypt" 6 | FolderName1="/restore/${VolumeName1}" 7 | 8 | File2="authelia-db.tgz" 9 | VolumeName2="authelia_db" 10 | FolderName2="/restore/${VolumeName2}" 11 | 12 | # Bring down the existing site 13 | docker compose down -v 14 | 15 | # Bring up the containers to recreate the volumes 16 | docker compose up -d --build backup 17 | docker compose down 18 | 19 | # Restore the volume data from the backups 20 | # Using Ubuntu because its build of tar includes the --skip-old-files flag 21 | docker run --rm \ 22 | -v "$(pwd)/${File1}:/backup/${File1}" \ 23 | -v "$(pwd)/${File2}:/backup/${File2}" \ 24 | -v "${VolumeName1}:${FolderName1}" \ 25 | -v "${VolumeName2}:${FolderName2}" \ 26 | ubuntu sh -c \ 27 | "tar -xvzf /backup/${File1} -C ${FolderName1} --skip-old-files && \ 28 | tar -xvzf /backup/${File2} -C ${FolderName2}" 29 | 30 | # Restore the site with the data 31 | docker compose up -d 32 | -------------------------------------------------------------------------------- /gitlab/backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set variables 4 | BackupContainer="gitlab" 5 | 6 | File1="gitlab-config.tgz" 7 | Folder1="/etc/gitlab" 8 | 9 | File2="gitlab-logs.tgz" 10 | Folder2="/var/log/gitlab" 11 | 12 | File3="gitlab-data.tgz" 13 | Folder3="/var/opt/gitlab" 14 | 15 | File4="gitlab-runner.tgz" 16 | Folder4="/etc/gitlab-runner" 17 | 18 | # Backup existing volumes by tarring and gzipping them 19 | docker run --rm --volumes-from ${BackupContainer} \ 20 | -v $(pwd):/backup ${Image} sh -c \ 21 | "tar -C ${Folder1} -cvzf /backup/${File1} . && \ 22 | tar -C ${Folder2} -cvzf /backup/${File2} . && \ 23 | tar -C ${Folder3} -cvzf /backup/${File3} . && \ 24 | tar -C ${Folder4} -cvzf /backup/${File4} . " 25 | 26 | # Copy to external drive and overwrite if files already exist 27 | cp "./${File1}" "${BackupFolder}/${dateString}/${File1}" -f 28 | cp "./${File2}" "${BackupFolder}/${dateString}/${File2}" -f 29 | cp "./${File3}" "${BackupFolder}/${dateString}/${File3}" -f 30 | cp "./${File4}" "${BackupFolder}/${dateString}/${File4}" -f 31 | -------------------------------------------------------------------------------- /mastodon/restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables 4 | File1="mastodon-web.tgz" 5 | Volume1="mastodon_web" 6 | Folder1="/restore/${Volume1}" 7 | 8 | File2="mastodon-redis.tgz" 9 | Volume2="mastodon_redis" 10 | Folder2="/restore/${Volume2}" 11 | 12 | File3="mastodon-db.tgz" 13 | Volume3="mastodon_db" 14 | Folder3="/restore/${Volume3}" 15 | 16 | # Bring down the existing site 17 | docker compose down -v 18 | 19 | # Bring up the containers to recreate the volumes 20 | docker compose up -d --build backup 21 | docker compose down 22 | 23 | # Restore the volume data from the backups 24 | docker run --rm \ 25 | -v "$(pwd)/${File1}:/backup/${File1}" \ 26 | -v "$(pwd)/${File2}:/backup/${File2}" \ 27 | -v "$(pwd)/${File3}:/backup/${File3}" \ 28 | -v "${Volume1}:${Folder1}" \ 29 | -v "${Volume2}:${Folder2}" \ 30 | -v "${Volume3}:${Folder3}" \ 31 | alpine:3.17.2 sh -c \ 32 | "tar -xvzf /backup/${File1} -C ${Folder1} && \ 33 | tar -xvzf /backup/${File2} -C ${Folder2} && \ 34 | tar -xvzf /backup/${File3} -C ${Folder3}" 35 | 36 | 37 | # Restore the site with the data 38 | docker compose up -d 39 | -------------------------------------------------------------------------------- /lemmy/restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables 4 | BackupContainer="backup" 5 | 6 | File1="lemmy-extra_themes.tgz" 7 | Volume1="lemmy_extra_themes" 8 | Folder1="/restore/${Volume1}" 9 | 10 | File2="lemmy-pictrs.tgz" 11 | Volume2="lemmy_pictrs" 12 | Folder2="/restore/${Volume2}" 13 | 14 | File3="lemmy-postgres.tgz" 15 | Volume3="lemmy_postgres" 16 | Folder3="/restore/${Volume3}" 17 | 18 | # Bring down the existing site 19 | docker-compose down -v 20 | 21 | # Bring up the containers to recreate the volumes 22 | docker-compose up -d --build backup 23 | docker-compose down 24 | 25 | # Restore the volume data from the backups 26 | docker run --rm \ 27 | -v "$(pwd)/${File1}:/backup/${File1}" \ 28 | -v "$(pwd)/${File2}:/backup/${File2}" \ 29 | -v "$(pwd)/${File3}:/backup/${File3}" \ 30 | -v "${Volume1}:${Folder1}" \ 31 | -v "${Volume2}:${Folder2}" \ 32 | -v "${Volume3}:${Folder3}" \ 33 | alpine:3.17.2 sh -c \ 34 | "tar -xvzf /backup/${File1} -C ${Folder1} && \ 35 | tar -xvzf /backup/${File2} -C ${Folder2} && \ 36 | tar -xvzf /backup/${File3} -C ${Folder3}" 37 | 38 | # Restore the site with the data 39 | docker-compose up -d 40 | -------------------------------------------------------------------------------- /nginx/sites/default.conf: -------------------------------------------------------------------------------- 1 | ## Version 2023/04/13 - Changelog: https://github.com/linuxserver/docker-baseimage-alpine-nginx/commits/master/root/defaults/nginx/site-confs/default.conf.sample 2 | 3 | server { 4 | listen 80 default_server; 5 | listen [::]:80 default_server; 6 | 7 | listen 443 ssl http2 default_server; 8 | listen [::]:443 ssl http2 default_server; 9 | 10 | server_name _; 11 | 12 | include /config/nginx/ssl.conf; 13 | 14 | set $root /app/www/public; 15 | if (!-d /app/www/public) { 16 | set $root /config/www; 17 | } 18 | root $root; 19 | index index.html index.htm index.php; 20 | 21 | location / { 22 | # enable for basic auth 23 | #auth_basic "Restricted"; 24 | #auth_basic_user_file /config/nginx/.htpasswd; 25 | 26 | try_files $uri $uri/ /index.html /index.php$is_args$args =404; 27 | } 28 | 29 | location ~ ^(.+\.php)(.*)$ { 30 | fastcgi_split_path_info ^(.+\.php)(.*)$; 31 | fastcgi_pass 127.0.0.1:9000; 32 | fastcgi_index index.php; 33 | include /etc/nginx/fastcgi_params; 34 | } 35 | 36 | # deny access to .htaccess/.htpasswd files 37 | location ~ /\.ht { 38 | deny all; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /gitlab/readme.md: -------------------------------------------------------------------------------- 1 | # Initial setup 2 | 3 | After creating the container, the root login won't work. Go into the container manually to set the password. 4 | 5 | 1. `docker exec -it gitlab /bin/bash` 6 | 2. Run `gitlab-rake "gitlab:password:reset"` 7 | 3. Enter a user name, in this case 'root' (no quotes) and password 8 | 9 | # Runner 10 | 11 | To launch a short-lived gitlab-runner container to register the container you created during installation: 12 | 13 | 1. `docker run --rm -it -v gitlab_runner:/etc/gitlab-runner gitlab/gitlab-runner:latest register` 14 | 2. GitLab instance URL: `http://192.168.1.34:8280` 15 | 3. Entered registration token and name 16 | 4. Executor: `docker` 17 | 5. Default image: `node:16` 18 | 19 | # Runner clone failure 20 | 21 | Got an error from a pipeline job while trying to clone the repository. To solve this, I had to edit the runner container's config.toml. 22 | 23 | 1. `docker exec -it gitlab_runner /bin/bash` 24 | 2. `apt-get update` 25 | 3. `apt-get install nano` 26 | 4. `cd /etc/gitlab-runner` 27 | 5. `nano config.toml` 28 | 6. Add this clone_url below url 29 | ``` 30 | clone_url = "http://192.168.1.15:8280" 31 | ``` 32 | 7. Restart the container 33 | ``` 34 | docker restart gitlab_runner 35 | ``` -------------------------------------------------------------------------------- /nginx/sites/default.conf.sample: -------------------------------------------------------------------------------- 1 | ## Version 2023/04/13 - Changelog: https://github.com/linuxserver/docker-baseimage-alpine-nginx/commits/master/root/defaults/nginx/site-confs/default.conf.sample 2 | 3 | server { 4 | listen 80 default_server; 5 | listen [::]:80 default_server; 6 | 7 | listen 443 ssl http2 default_server; 8 | listen [::]:443 ssl http2 default_server; 9 | 10 | server_name _; 11 | 12 | include /config/nginx/ssl.conf; 13 | 14 | set $root /app/www/public; 15 | if (!-d /app/www/public) { 16 | set $root /config/www; 17 | } 18 | root $root; 19 | index index.html index.htm index.php; 20 | 21 | location / { 22 | # enable for basic auth 23 | #auth_basic "Restricted"; 24 | #auth_basic_user_file /config/nginx/.htpasswd; 25 | 26 | try_files $uri $uri/ /index.html /index.php$is_args$args =404; 27 | } 28 | 29 | location ~ ^(.+\.php)(.*)$ { 30 | fastcgi_split_path_info ^(.+\.php)(.*)$; 31 | fastcgi_pass 127.0.0.1:9000; 32 | fastcgi_index index.php; 33 | include /etc/nginx/fastcgi_params; 34 | } 35 | 36 | # deny access to .htaccess/.htpasswd files 37 | location ~ /\.ht { 38 | deny all; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nginx/snippets/authelia-authrequest.conf: -------------------------------------------------------------------------------- 1 | ## Send a subrequest to Authelia to verify if the user is authenticated and has permission to access the resource. 2 | auth_request /authelia; 3 | 4 | ## Set the $target_url variable based on the original request. 5 | 6 | ## Comment this line if you're using nginx without the http_set_misc module. 7 | set_escape_uri $target_url $scheme://$http_host$request_uri; 8 | 9 | ## Uncomment this line if you're using NGINX without the http_set_misc module. 10 | # set $target_url $scheme://$http_host$request_uri; 11 | 12 | ## Save the upstream response headers from Authelia to variables. 13 | auth_request_set $user $upstream_http_remote_user; 14 | auth_request_set $groups $upstream_http_remote_groups; 15 | auth_request_set $name $upstream_http_remote_name; 16 | auth_request_set $email $upstream_http_remote_email; 17 | 18 | ## Inject the response headers from the variables into the request made to the backend. 19 | proxy_set_header Remote-User $user; 20 | proxy_set_header Remote-Groups $groups; 21 | proxy_set_header Remote-Name $name; 22 | proxy_set_header Remote-Email $email; 23 | 24 | ## If the subreqest returns 200 pass to the backend, if the subrequest returns 401 redirect to the portal. 25 | error_page 401 =302 http://auth.starbase80.dev/?rd=$target_url; -------------------------------------------------------------------------------- /gitlab/restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Variables 4 | File1="gitlab-config.tgz" 5 | Volume1="gitlab_config" 6 | Folder1="/restore/${Volume1}" 7 | 8 | File2="gitlab-logs.tgz" 9 | Volume2="gitlab_logs" 10 | Folder2="/restore/${Volume2}" 11 | 12 | File3="gitlab-data.tgz" 13 | Volume3="gitlab_data" 14 | Folder3="/restore/${Volume3}" 15 | 16 | File4="gitlab-runner.tgz" 17 | Volume4="gitlab_runner" 18 | Folder4="/restore/${Volume4}" 19 | 20 | # Bring down the existing site 21 | docker-compose down -v 22 | 23 | # Bring up the containers to recreate the volumes 24 | docker-compose up -d --build gitlab 25 | docker-compose down 26 | 27 | # Restore the volume data from the backups 28 | docker run --rm \ 29 | -v "$(pwd)/${File1}:/backup/${File1}" \ 30 | -v "$(pwd)/${File2}:/backup/${File2}" \ 31 | -v "$(pwd)/${File3}:/backup/${File3}" \ 32 | -v "$(pwd)/${File4}:/backup/${File4}" \ 33 | -v "${Volume1}:${Folder1}" \ 34 | -v "${Volume2}:${Folder2}" \ 35 | -v "${Volume3}:${Folder3}" \ 36 | -v "${Volume4}:${Folder4}" \ 37 | alpine:3.17.2 sh -c \ 38 | "tar -xvzf /backup/${File1} -C ${Folder1} && \ 39 | tar -xvzf /backup/${File2} -C ${Folder2} && \ 40 | tar -xvzf /backup/${File3} -C ${Folder3} && \ 41 | tar -xvzf /backup/${File4} -C ${Folder4}" 42 | 43 | # Restore the site with the data 44 | docker-compose up -d 45 | -------------------------------------------------------------------------------- /nginx/snippets/authelia-location.conf: -------------------------------------------------------------------------------- 1 | set $upstream_authelia http://192.168.1.34:9091/api/verify; 2 | 3 | ## Virtual endpoint created by nginx to forward auth requests. 4 | location /authelia { 5 | ## Essential Proxy Configuration 6 | internal; 7 | proxy_pass $upstream_authelia; 8 | 9 | ## Headers 10 | ## The headers starting with X-* are required. 11 | proxy_set_header X-Original-URL $scheme://$http_host$request_uri; 12 | proxy_set_header X-Original-Method $request_method; 13 | proxy_set_header X-Forwarded-Method $request_method; 14 | proxy_set_header X-Forwarded-Proto $scheme; 15 | proxy_set_header X-Forwarded-Host $http_host; 16 | proxy_set_header X-Forwarded-Uri $request_uri; 17 | proxy_set_header X-Forwarded-For $remote_addr; 18 | proxy_set_header Content-Length ""; 19 | proxy_set_header Connection ""; 20 | 21 | ## Basic Proxy Configuration 22 | proxy_pass_request_body off; 23 | proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; # Timeout if the real server is dead 24 | proxy_redirect http:// $scheme://; 25 | proxy_http_version 1.1; 26 | proxy_cache_bypass $cookie_session; 27 | proxy_no_cache $cookie_session; 28 | proxy_buffers 4 32k; 29 | client_body_buffer_size 128k; 30 | 31 | ## Advanced Proxy Configuration 32 | send_timeout 5m; 33 | proxy_read_timeout 240; 34 | proxy_send_timeout 240; 35 | proxy_connect_timeout 240; 36 | } -------------------------------------------------------------------------------- /nginx/snippets/proxy.conf: -------------------------------------------------------------------------------- 1 | ## Headers 2 | proxy_set_header Host $host; 3 | proxy_set_header X-Original-URL $scheme://$http_host$request_uri; 4 | proxy_set_header X-Forwarded-Proto $scheme; 5 | proxy_set_header X-Forwarded-Host $http_host; 6 | proxy_set_header X-Forwarded-Uri $request_uri; 7 | proxy_set_header X-Forwarded-Ssl on; 8 | proxy_set_header X-Forwarded-For $remote_addr; 9 | proxy_set_header X-Real-IP $remote_addr; 10 | proxy_set_header Connection ""; 11 | 12 | ## Basic Proxy Configuration 13 | client_body_buffer_size 128k; 14 | proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; ## Timeout if the real server is dead. 15 | proxy_redirect http:// $scheme://; 16 | proxy_http_version 1.1; 17 | proxy_cache_bypass $cookie_session; 18 | proxy_no_cache $cookie_session; 19 | proxy_buffers 64 256k; 20 | 21 | ## Trusted Proxies Configuration 22 | ## Please read the following documentation before configuring this: 23 | ## https://www.authelia.com/integration/proxies/nginx/#trusted-proxies 24 | # set_real_ip_from 10.0.0.0/8; 25 | # set_real_ip_from 172.16.0.0/12; 26 | # set_real_ip_from 192.168.0.0/16; 27 | # set_real_ip_from fc00::/7; 28 | set_real_ip_from 10.0.0.0/8; 29 | set_real_ip_from 172.16.0.0/12; 30 | set_real_ip_from 192.168.0.0/16; 31 | set_real_ip_from fc00::/7; 32 | real_ip_header X-Forwarded-For; 33 | real_ip_recursive on; 34 | 35 | ## Advanced Proxy Configuration 36 | send_timeout 5m; 37 | proxy_read_timeout 360; 38 | proxy_send_timeout 360; 39 | proxy_connect_timeout 360; -------------------------------------------------------------------------------- /nginx/sites/authelia.conf: -------------------------------------------------------------------------------- 1 | # server { 2 | # listen 80; 3 | # listen [::]:80; 4 | # server_name auth.starbase80.dev; 5 | 6 | # access_log /var/log/nginx/auth.starbase80.dev.access.logs; 7 | # error_log /var/log/nginx/auth.starbase80.dev.error.logs; 8 | 9 | # location ^~ /.well-known/acme-challenge/ { 10 | # allow all; 11 | # root /var/www/certbot; 12 | # } 13 | 14 | # location / { 15 | # # proxy_pass http://10.10.10.70:9091; 16 | # return 301 https://$host$request_uri; 17 | # } 18 | # } 19 | 20 | server { 21 | listen 443 ssl http2; 22 | listen [::]:443 ssl http2; 23 | server_name auth.*; 24 | 25 | access_log /var/log/nginx/auth.starbase80.dev.access.logs; 26 | error_log /var/log/nginx/auth.starbase80.dev.error.logs; 27 | 28 | ssl_protocols TLSv1.2 TLSv1.3; 29 | ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; 30 | ssl_prefer_server_ciphers on; 31 | ssl_session_cache shared:SSL:10m; 32 | ssl_session_tickets off; 33 | 34 | ssl_certificate /etc/letsencrypt/live/auth.starbase80.dev/fullchain.pem; 35 | ssl_certificate_key /etc/letsencrypt/live/auth.starbase80.dev/privkey.pem; 36 | 37 | set $upstream http://192.168.1.34:9091; 38 | 39 | location ^~ /.well-known/acme-challenge/ { 40 | allow all; 41 | root /var/www/certbot; 42 | } 43 | 44 | location / { 45 | include /etc/nginx/snippets/proxy.conf; 46 | proxy_pass $upstream; 47 | } 48 | 49 | location /api/verify { 50 | proxy_pass $upstream; 51 | } 52 | } -------------------------------------------------------------------------------- /mastodon/readme.md: -------------------------------------------------------------------------------- 1 | # Mastodon setup 2 | 3 | ## Postgres 4 | 5 | 1. Create mastodon role 6 | ```bash 7 | docker run --rm --name postgres \ 8 | -v mastodon_db:/var/lib/postgresql/data \ 9 | -e POSTGRES_USER=mastodon \ 10 | -e POSTGRES_PASSWORD="" \ 11 | -d postgres:14-alpine 12 | ``` 13 | 1. Can sign in with 14 | ```bash 15 | docker exec -it postgres psql -U mastodon 16 | ``` 17 | 18 | ## Put this in .env.production 19 | 20 | ``` 21 | DB_HOST=db 22 | DB_PORT=5432 23 | DB_NAME=mastodon 24 | DB_USER=mastodon 25 | DB_PASS= 26 | REDIS_HOST=redis 27 | REDIS_PORT=6379 28 | REDIS_PASSWORD= 29 | ``` 30 | 31 | ## Started Mastodon setup 32 | 33 | ```bash 34 | docker compose run --rm web bundle exec rake mastodon:setup 35 | ``` 36 | 37 | ## Saved output to .env.production 38 | 39 | Copy what's in the terminal and paste it into .env.production 40 | 41 | ## Fixed 502 bad gateway in nginx config 42 | 43 | ```conf 44 | upstream backend { 45 | server localhost:3000 fail_timeout=0; 46 | } 47 | ``` 48 | 49 | ## Restored postgres database 50 | 51 | 1. Copied database backup to container 52 | ```bash 53 | docker cp '/Users/me/Desktop/Backup/backup.dump' postgres:/ 54 | ``` 55 | 1. Terminal to postgres container in Docker 56 | ``` bash 57 | pg_restore -Fc -U mastodon -n public --no-owner --role=mastodon -d mastodon -c backup.dump 58 | ``` 59 | 60 | ## Recompiled mastodon 61 | 62 | 1. Went into the web container terminal and ran 63 | ```bash 64 | RAILS_ENV=production bundle exec rails assets:precompile 65 | RAILS_ENV=production ./bin/tootctl feeds build 66 | ``` -------------------------------------------------------------------------------- /homepage/public/icons/jellyfin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /backup-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" 3 | 4 | # Log file path 5 | LOG_FILE="/home/jordan/cron/backup-all.log" 6 | 7 | # Truncate log file to 1 megabyte 8 | truncate -s 10M "$LOG_FILE" 9 | 10 | # Redirect stdout and stderr to the log file 11 | exec &> >(tee -a "$LOG_FILE") 12 | 13 | echo "backup-all.sh: $(date)" 14 | 15 | # Helper 16 | function Create-DatedDirectory { 17 | folderPath="$1" 18 | 19 | # Get the current date and format it as YYYY-MM-DD 20 | dateString=$(date +"%Y-%m-%d") 21 | 22 | # Combine the folder path and date string to create the directory path 23 | directoryPath="$folderPath/$dateString" 24 | 25 | # Check if the directory already exists, if not, create it 26 | if [ ! -d "$directoryPath" ]; then 27 | mkdir "$directoryPath" 28 | fi 29 | } 30 | 31 | # Variables 32 | export dateString=$(date +"%Y-%m-%d") 33 | export Image="alpine:3.17.2" 34 | 35 | # Create backup folder 36 | export BackupFolder="/mnt/synology/home/docker-symphony" 37 | Create-DatedDirectory "$BackupFolder" 38 | 39 | # Run all backup scripts 40 | "/home/jordan/docker-symphony/calibre/backup.sh" 41 | "/home/jordan/docker-symphony/gitlab/backup.sh" 42 | "/home/jordan/docker-symphony/jellyfin/backup.sh" 43 | "/home/jordan/docker-symphony/lemmy/backup.sh" 44 | "/home/jordan/docker-symphony/mastodon/backup.sh" 45 | "/home/jordan/docker-symphony/miniflux/backup.sh" 46 | "/home/jordan/docker-symphony/nginx/backup.sh" 47 | 48 | # Delete backups older than 7 days 49 | find "$BackupFolder" -type d -mtime +7 -exec rm -rf {} \; 50 | 51 | # Delete local backups 52 | rm -rf *.tgz -------------------------------------------------------------------------------- /nginx/sites/homepage.conf: -------------------------------------------------------------------------------- 1 | upstream homepage_backend { 2 | server 192.168.1.34:8090; 3 | } 4 | 5 | # server { 6 | # listen 80; 7 | # server_name starbase80.dev www.starbase80.dev; 8 | 9 | # access_log /var/log/nginx/starbase80.dev.access.logs; 10 | # error_log /var/log/nginx/starbase80.dev.error.logs; 11 | 12 | # location ^~ /.well-known/acme-challenge/ { 13 | # allow all; 14 | # root /var/www/certbot; 15 | # } 16 | 17 | # location / { 18 | # proxy_set_header X-Real-IP $remote_addr; 19 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | # proxy_set_header X-Forwarded-Proto $scheme; 21 | # proxy_set_header Host $http_host; 22 | # proxy_set_header X-NginX-Proxy true; 23 | 24 | # # proxy_pass http://homepage_backend; 25 | # return 301 https://$host$request_uri; 26 | # } 27 | # } 28 | 29 | server { 30 | listen 443 ssl http2; 31 | listen [::]:443 ssl http2; 32 | server_name starbase80.dev www.starbase80.dev; 33 | 34 | access_log /var/log/nginx/starbase80.dev.access.logs; 35 | error_log /var/log/nginx/starbase80.dev.error.logs; 36 | 37 | ssl_protocols TLSv1.2 TLSv1.3; 38 | ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; 39 | ssl_prefer_server_ciphers on; 40 | ssl_session_cache shared:SSL:10m; 41 | ssl_session_tickets off; 42 | 43 | ssl_certificate /etc/letsencrypt/live/starbase80.dev/fullchain.pem; 44 | ssl_certificate_key /etc/letsencrypt/live/starbase80.dev/privkey.pem; 45 | 46 | location ^~ /.well-known/acme-challenge/ { 47 | allow all; 48 | root /var/www/certbot; 49 | } 50 | 51 | location / { 52 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 53 | proxy_set_header Host $host; 54 | proxy_redirect off; 55 | proxy_pass http://homepage_backend; 56 | } 57 | } -------------------------------------------------------------------------------- /nginx/sites/shamir.conf: -------------------------------------------------------------------------------- 1 | upstream shamir_backend { 2 | server 192.168.1.34:8200; 3 | } 4 | 5 | # server { 6 | # listen 80; 7 | # server_name shamir.starbase80.dev; 8 | 9 | # access_log /var/log/nginx/shamir.starbase80.dev.access.logs; 10 | # error_log /var/log/nginx/shamir.starbase80.dev.error.logs; 11 | 12 | # location ^~ /.well-known/acme-challenge { 13 | # allow all; 14 | # root /var/www/certbot; 15 | # } 16 | 17 | # location / { 18 | # proxy_set_header X-Real-IP $remote_addr; 19 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | # proxy_set_header X-Forwarded-Proto $scheme; 21 | # proxy_set_header Host $http_host; 22 | # proxy_set_header X-NginX-Proxy true; 23 | 24 | # # proxy_pass http://shamir_backend; 25 | # return 301 https://$host$request_uri; 26 | # } 27 | # } 28 | 29 | server { 30 | listen 443 ssl http2; 31 | listen [::]:443 ssl http2; 32 | server_name shamir.starbase80.dev; 33 | 34 | access_log /var/log/nginx/shamir.starbase80.dev.access.logs; 35 | error_log /var/log/nginx/shamir.starbase80.dev.error.logs; 36 | 37 | ssl_protocols TLSv1.2 TLSv1.3; 38 | ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; 39 | ssl_prefer_server_ciphers on; 40 | ssl_session_cache shared:SSL:10m; 41 | ssl_session_tickets off; 42 | 43 | ssl_certificate /etc/letsencrypt/live/shamir.starbase80.dev/fullchain.pem; 44 | ssl_certificate_key /etc/letsencrypt/live/shamir.starbase80.dev/privkey.pem; 45 | 46 | include /etc/nginx/snippets/authelia-location.conf; 47 | 48 | location ^~ /.well-known/acme-challenge { 49 | allow all; 50 | root /var/www/certbot; 51 | } 52 | 53 | location / { 54 | include /etc/nginx/snippets/proxy.conf; 55 | include /etc/nginx/snippets/authelia-authrequest.conf; 56 | 57 | proxy_pass http://shamir_backend; 58 | } 59 | } -------------------------------------------------------------------------------- /nginx/sites/gitlab.conf: -------------------------------------------------------------------------------- 1 | upstream gitlab_backend { 2 | server 192.168.1.34:8280; 3 | } 4 | 5 | # server { 6 | # listen 80; 7 | # server_name gitlab.starbase80.dev; 8 | 9 | # access_log /var/log/nginx/gitlab.starbase80.dev.access.logs; 10 | # error_log /var/log/nginx/gitlab.starbase80.dev.error.logs; 11 | 12 | # location ^~ /.well-known/acme-challenge { 13 | # allow all; 14 | # root /var/www/certbot; 15 | # } 16 | 17 | # location / { 18 | # proxy_set_header X-Real-IP $remote_addr; 19 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | # proxy_set_header X-Forwarded-Proto $scheme; 21 | # proxy_set_header Host $http_host; 22 | # proxy_set_header X-NginX-Proxy true; 23 | 24 | # # proxy_pass http://gitlab_backend; 25 | # return 301 https://$host$request_uri; 26 | # } 27 | # } 28 | 29 | server { 30 | listen 443; 31 | listen [::]:443; 32 | http2 on; 33 | 34 | server_name gitlab.starbase80.dev; 35 | 36 | access_log /var/log/nginx/gitlab.starbase80.dev.access.logs; 37 | error_log /var/log/nginx/gitlab.starbase80.dev.error.logs; 38 | 39 | ssl_protocols TLSv1.2 TLSv1.3; 40 | ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; 41 | ssl_prefer_server_ciphers on; 42 | ssl_session_cache shared:SSL:10m; 43 | ssl_session_tickets off; 44 | 45 | ssl_certificate /etc/letsencrypt/live/gitlab.starbase80.dev/fullchain.pem; 46 | ssl_certificate_key /etc/letsencrypt/live/gitlab.starbase80.dev/privkey.pem; 47 | 48 | include /etc/nginx/snippets/authelia-location.conf; 49 | 50 | location ^~ /.well-known/acme-challenge { 51 | allow all; 52 | root /var/www/certbot; 53 | } 54 | 55 | location / { 56 | include /etc/nginx/snippets/proxy.conf; 57 | include /etc/nginx/snippets/authelia-authrequest.conf; 58 | 59 | proxy_pass http://gitlab_backend; 60 | } 61 | } -------------------------------------------------------------------------------- /nginx/sites/miniflux.conf: -------------------------------------------------------------------------------- 1 | upstream miniflux_backend { 2 | server 192.168.1.34:8050; 3 | } 4 | 5 | # server { 6 | # listen 80; 7 | # server_name miniflux.starbase80.dev; 8 | 9 | # access_log /var/log/nginx/miniflux.starbase80.dev.access.logs; 10 | # error_log /var/log/nginx/miniflux.starbase80.dev.error.logs; 11 | 12 | # location ^~ /.well-known/acme-challenge { 13 | # allow all; 14 | # root /var/www/certbot; 15 | # } 16 | 17 | # location / { 18 | # proxy_set_header X-Real-IP $remote_addr; 19 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | # proxy_set_header X-Forwarded-Proto $scheme; 21 | # proxy_set_header Host $http_host; 22 | # proxy_set_header X-NginX-Proxy true; 23 | 24 | # # proxy_pass http://miniflux_backend; 25 | # return 301 https://$host$request_uri; 26 | # } 27 | # } 28 | 29 | server { 30 | listen 443 ssl http2; 31 | listen [::]:443 ssl http2; 32 | server_name miniflux.starbase80.dev; 33 | 34 | access_log /var/log/nginx/miniflux.starbase80.dev.access.logs; 35 | error_log /var/log/nginx/miniflux.starbase80.dev.error.logs; 36 | 37 | ssl_protocols TLSv1.2 TLSv1.3; 38 | ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; 39 | ssl_prefer_server_ciphers on; 40 | ssl_session_cache shared:SSL:10m; 41 | ssl_session_tickets off; 42 | 43 | ssl_certificate /etc/letsencrypt/live/miniflux.starbase80.dev/fullchain.pem; 44 | ssl_certificate_key /etc/letsencrypt/live/miniflux.starbase80.dev/privkey.pem; 45 | 46 | include /etc/nginx/snippets/authelia-location.conf; 47 | 48 | location ^~ /.well-known/acme-challenge { 49 | allow all; 50 | root /var/www/certbot; 51 | } 52 | 53 | location / { 54 | include /etc/nginx/snippets/proxy.conf; 55 | include /etc/nginx/snippets/authelia-authrequest.conf; 56 | 57 | proxy_pass http://miniflux_backend; 58 | } 59 | } -------------------------------------------------------------------------------- /nginx/sites/lemmy.conf: -------------------------------------------------------------------------------- 1 | upstream lemmy_backend { 2 | server 192.168.1.34:8260; 3 | } 4 | 5 | # server { 6 | # listen 80; 7 | # server_name lemmy.starbase80.dev; 8 | 9 | # access_log /var/log/nginx/lemmy.starbase80.dev.access.logs; 10 | # error_log /var/log/nginx/lemmy.starbase80.dev.error.logs; 11 | 12 | # location ^~ /.well-known/acme-challenge { 13 | # allow all; 14 | # root /var/www/certbot; 15 | # } 16 | 17 | # location / { 18 | # proxy_set_header X-Real-IP $remote_addr; 19 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | # proxy_set_header X-Forwarded-Proto $scheme; 21 | # proxy_set_header Host $http_host; 22 | # proxy_set_header X-NginX-Proxy true; 23 | 24 | # # proxy_pass http://lemmy_backend; 25 | # return 301 https://$host$request_uri; 26 | # } 27 | # } 28 | 29 | server { 30 | listen 443 ssl http2; 31 | listen [::]:443 ssl http2; 32 | server_name lemmy.starbase80.dev; 33 | 34 | access_log /var/log/nginx/lemmy.starbase80.dev.access.logs; 35 | error_log /var/log/nginx/lemmy.starbase80.dev.error.logs; 36 | 37 | ssl_protocols TLSv1.2 TLSv1.3; 38 | ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; 39 | ssl_prefer_server_ciphers on; 40 | ssl_session_cache shared:SSL:10m; 41 | ssl_session_tickets off; 42 | 43 | ssl_certificate /etc/letsencrypt/live/lemmy.starbase80.dev/fullchain.pem; 44 | ssl_certificate_key /etc/letsencrypt/live/lemmy.starbase80.dev/privkey.pem; 45 | 46 | include /etc/nginx/snippets/authelia-location.conf; 47 | 48 | location ^~ /.well-known/acme-challenge { 49 | allow all; 50 | root /var/www/certbot; 51 | } 52 | 53 | location / { 54 | # Exposing Lemmy publicly by commenting out Authelia's validation 55 | # include /etc/nginx/snippets/proxy.conf; 56 | # include /etc/nginx/snippets/authelia-authrequest.conf; 57 | 58 | proxy_pass http://lemmy_backend; 59 | } 60 | } -------------------------------------------------------------------------------- /nginx/snippets/ssl.conf: -------------------------------------------------------------------------------- 1 | ## Version 2022/08/20 - Changelog: https://github.com/linuxserver/docker-baseimage-alpine-nginx/commits/master/root/defaults/nginx/ssl.conf.sample 2 | 3 | ### Mozilla Recommendations 4 | # generated 2022-08-05, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1k, intermediate configuration 5 | # https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1k&guideline=5.6 6 | 7 | ssl_certificate /config/keys/cert.crt; 8 | ssl_certificate_key /config/keys/cert.key; 9 | ssl_session_timeout 1d; 10 | ssl_session_cache shared:MozSSL:10m; # about 40000 sessions 11 | ssl_session_tickets off; 12 | 13 | # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam 14 | ssl_dhparam /config/nginx/dhparams.pem; 15 | 16 | # intermediate configuration 17 | ssl_protocols TLSv1.2 TLSv1.3; 18 | ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; 19 | ssl_prefer_server_ciphers off; 20 | 21 | # HSTS (ngx_http_headers_module is required) (63072000 seconds) 22 | #add_header Strict-Transport-Security "max-age=63072000" always; 23 | 24 | # OCSP stapling 25 | #ssl_stapling on; 26 | #ssl_stapling_verify on; 27 | 28 | # verify chain of trust of OCSP response using Root CA and Intermediate certs 29 | #ssl_trusted_certificate /config/keys/cert.crt; 30 | 31 | # Optional additional headers 32 | #add_header Cache-Control "no-transform" always; 33 | #add_header Content-Security-Policy "upgrade-insecure-requests; frame-ancestors 'self'"; 34 | #add_header Permissions-Policy "interest-cohort=()"; 35 | #add_header Referrer-Policy "same-origin" always; 36 | #add_header X-Content-Type-Options "nosniff" always; 37 | #add_header X-Frame-Options "SAMEORIGIN" always; 38 | #add_header X-UA-Compatible "IE=Edge" always; 39 | #add_header X-XSS-Protection "1; mode=block" always; -------------------------------------------------------------------------------- /nginx/sites/jellyfin.conf: -------------------------------------------------------------------------------- 1 | # upstream jellyfin_backend { 2 | # server 192.168.1.34:8030; 3 | # } 4 | 5 | # server { 6 | # listen 80; 7 | # server_name jellyfin.starbase80.dev; 8 | 9 | # access_log /var/log/nginx/jellyfin.starbase80.dev.access.logs; 10 | # error_log /var/log/nginx/jellyfin.starbase80.dev.error.logs; 11 | 12 | # location ^~ /.well-known/acme-challenge { 13 | # allow all; 14 | # root /var/www/certbot; 15 | # } 16 | 17 | # location / { 18 | # proxy_set_header X-Real-IP $remote_addr; 19 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | # proxy_set_header X-Forwarded-Proto $scheme; 21 | # proxy_set_header Host $http_host; 22 | # proxy_set_header X-NginX-Proxy true; 23 | 24 | # # proxy_pass http://jellyfin_backend; 25 | # return 301 https://$host$request_uri; 26 | # } 27 | # } 28 | 29 | # server { 30 | # listen 443 ssl http2; 31 | # listen [::]:443 ssl http2; 32 | # server_name jellyfin.starbase80.dev; 33 | 34 | # access_log /var/log/nginx/jellyfin.starbase80.dev.access.logs; 35 | # error_log /var/log/nginx/jellyfin.starbase80.dev.error.logs; 36 | 37 | # ssl_protocols TLSv1.2 TLSv1.3; 38 | # ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; 39 | # ssl_prefer_server_ciphers on; 40 | # ssl_session_cache shared:SSL:10m; 41 | # ssl_session_tickets off; 42 | 43 | # ssl_certificate /etc/letsencrypt/live/jellyfin.starbase80.dev/fullchain.pem; 44 | # ssl_certificate_key /etc/letsencrypt/live/jellyfin.starbase80.dev/privkey.pem; 45 | 46 | # include /etc/nginx/snippets/authelia-location.conf; 47 | 48 | # location ^~ /.well-known/acme-challenge { 49 | # allow all; 50 | # root /var/www/certbot; 51 | # } 52 | 53 | # location / { 54 | # include /etc/nginx/snippets/proxy.conf; 55 | # include /etc/nginx/snippets/authelia-authrequest.conf; 56 | 57 | # # Websockets 58 | # proxy_set_header Upgrade $http_upgrade; 59 | # proxy_set_header Connection $connection_upgrade; 60 | 61 | # proxy_pass http://jellyfin_backend; 62 | # } 63 | # } -------------------------------------------------------------------------------- /nginx/sites/portainer.conf: -------------------------------------------------------------------------------- 1 | # upstream portainer_backend { 2 | # server 192.168.1.34:8160; 3 | # } 4 | 5 | # server { 6 | # listen 80; 7 | # server_name portainer.starbase80.dev; 8 | 9 | # access_log /var/log/nginx/portainer.starbase80.dev.access.logs; 10 | # error_log /var/log/nginx/portainer.starbase80.dev.error.logs; 11 | 12 | # location ^~ /.well-known/acme-challenge { 13 | # allow all; 14 | # root /var/www/certbot; 15 | # } 16 | 17 | # location / { 18 | # proxy_set_header X-Real-IP $remote_addr; 19 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | # proxy_set_header X-Forwarded-Proto $scheme; 21 | # proxy_set_header Host $http_host; 22 | # proxy_set_header X-NginX-Proxy true; 23 | 24 | # # proxy_pass http://portainer_backend; 25 | # return 301 https://$host$request_uri; 26 | # } 27 | # } 28 | 29 | # server { 30 | # listen 443 ssl http2; 31 | # listen [::]:443 ssl http2; 32 | # server_name portainer.starbase80.dev; 33 | 34 | # access_log /var/log/nginx/portainer.starbase80.dev.access.logs; 35 | # error_log /var/log/nginx/portainer.starbase80.dev.error.logs; 36 | 37 | # ssl_protocols TLSv1.2 TLSv1.3; 38 | # ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; 39 | # ssl_prefer_server_ciphers on; 40 | # ssl_session_cache shared:SSL:10m; 41 | # ssl_session_tickets off; 42 | 43 | # ssl_certificate /etc/letsencrypt/live/portainer.starbase80.dev/fullchain.pem; 44 | # ssl_certificate_key /etc/letsencrypt/live/portainer.starbase80.dev/privkey.pem; 45 | 46 | # include /etc/nginx/snippets/authelia-location.conf; 47 | 48 | # location ^~ /.well-known/acme-challenge { 49 | # allow all; 50 | # root /var/www/certbot; 51 | # } 52 | 53 | # location / { 54 | # include /etc/nginx/snippets/proxy.conf; 55 | # include /etc/nginx/snippets/authelia-authrequest.conf; 56 | 57 | # # Websockets 58 | # proxy_set_header Upgrade $http_upgrade; 59 | # proxy_set_header Connection $connection_upgrade; 60 | 61 | # proxy_pass http://portainer_backend; 62 | # } 63 | # } -------------------------------------------------------------------------------- /homepage/config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "category": "Services", 4 | "services": [ 5 | { 6 | "name": "Authelia", 7 | "uri": "https://auth.starbase80.dev", 8 | "description": "Authentication", 9 | "icon": "/icons/authelia.png" 10 | }, 11 | { 12 | "name": "Calibre", 13 | "uri": "http://starbase-80:8170", 14 | "description": "eBook library", 15 | "icon": "/icons/calibre.jpg" 16 | }, 17 | { 18 | "name": "GitLab", 19 | "uri": "https://gitlab.starbase80.dev", 20 | "description": "Code hosting", 21 | "icon": "/icons/gitlab.jpg" 22 | }, 23 | { 24 | "name": "Jellyfin", 25 | "uri": "http://starbase-80:8030", 26 | "description": "Media server", 27 | "icon": "/icons/jellyfin.svg" 28 | }, 29 | { 30 | "name": "Lemmy", 31 | "uri": "https://lemmy.starbase80.dev", 32 | "description": "Link sharing", 33 | "icon": "/icons/lemmy.jpg" 34 | }, 35 | { 36 | "name": "Mastodon", 37 | "uri": "https://notclickable.social", 38 | "description": "NotClickable.social", 39 | "icon": "/icons/mastodon.jpg" 40 | }, 41 | { 42 | "name": "Miniflux", 43 | "uri": "https://miniflux.starbase80.dev", 44 | "description": "RSS server", 45 | "icon": "/icons/miniflux.jpg" 46 | }, 47 | { 48 | "name": "Portainer", 49 | "uri": "http://starbase-80:8160", 50 | "description": "Docker management", 51 | "icon": "/icons/portainer.png" 52 | }, 53 | { 54 | "name": "Shamir's Secrets", 55 | "uri": "https://shamir.starbase80.dev", 56 | "description": "Secret distribution", 57 | "icon": "/icons/shamir.jpg" 58 | } 59 | ] 60 | }, 61 | { 62 | "category": "Devices", 63 | "services": [ 64 | { 65 | "name": "Router", 66 | "uri": "http://192.168.1.1/", 67 | "description": "Netgear Orbi", 68 | "icon": "/icons/router.png" 69 | }, 70 | { 71 | "name": "Home Assistant", 72 | "uri": "http://homeassistant:8123/", 73 | "description": "Home automation", 74 | "icon": "/icons/home-assistant.svg" 75 | }, 76 | { 77 | "name": "Synology", 78 | "uri": "http://synology:5000", 79 | "description": "Network storage", 80 | "icon": "/icons/synology.png" 81 | }, 82 | { 83 | "name": "Federation", 84 | "uri": "https://federation:8006", 85 | "description": "Proxmox", 86 | "icon": "/icons/proxmox.png", 87 | "iconBubble": false 88 | } 89 | ] 90 | } 91 | ] 92 | -------------------------------------------------------------------------------- /lemmy/compose.yml: -------------------------------------------------------------------------------- 1 | x-logging: &default-logging 2 | driver: "json-file" 3 | options: 4 | max-size: "50m" 5 | max-file: "4" 6 | 7 | services: 8 | backup: 9 | image: alpine:3.17.2 10 | container_name: lemmy_backup 11 | entrypoint: "tail -f /dev/null" 12 | restart: unless-stopped 13 | volumes: 14 | - extra_themes:/app/extra_themes:ro 15 | - pictrs:/mnt:ro 16 | - postgres:/var/lib/postgresql/data:ro 17 | 18 | proxy: 19 | image: nginx:1-alpine 20 | container_name: lemmy_nginx 21 | ports: 22 | - 8260:8536 23 | volumes: 24 | - ./nginx_internal.conf:/etc/nginx/nginx.conf:ro,Z 25 | restart: unless-stopped 26 | logging: *default-logging 27 | depends_on: 28 | - pictrs 29 | - lemmy-ui 30 | 31 | lemmy: 32 | image: dessalines/lemmy:0.19.11 33 | container_name: lemmy 34 | hostname: lemmy 35 | restart: unless-stopped 36 | logging: *default-logging 37 | environment: 38 | - RUST_LOG="warn" 39 | volumes: 40 | - ./lemmy.hjson:/config/config.hjson:Z 41 | depends_on: 42 | - postgres 43 | - pictrs 44 | 45 | lemmy-ui: 46 | image: dessalines/lemmy-ui:0.19.11 47 | container_name: lemmy_ui 48 | env_file: env.lemmy-ui 49 | volumes: 50 | - extra_themes:/app/extra_themes 51 | depends_on: 52 | - lemmy 53 | restart: unless-stopped 54 | logging: *default-logging 55 | 56 | pictrs: 57 | image: asonix/pictrs:0.5.0-rc.2 58 | container_name: lemmy_pictrs 59 | # this needs to match the pictrs url in lemmy.hjson 60 | hostname: pictrs 61 | # we can set options to pictrs like this, here we set max. image size and forced format for conversion 62 | # entrypoint: /sbin/tini -- /usr/local/bin/pict-rs -p /mnt -m 4 --image-format webp 63 | env_file: env.pictrs 64 | user: 991:991 65 | volumes: 66 | - pictrs:/mnt 67 | restart: unless-stopped 68 | logging: *default-logging 69 | deploy: 70 | resources: 71 | limits: 72 | memory: 690m 73 | 74 | postgres: 75 | image: postgres:15-alpine 76 | container_name: lemmy_db 77 | hostname: postgres 78 | env_file: env.postgres 79 | volumes: 80 | - postgres:/var/lib/postgresql/data 81 | - ./customPostgresql.conf:/etc/postgresql.conf 82 | restart: unless-stopped 83 | logging: *default-logging 84 | 85 | postfix: 86 | image: mwader/postfix-relay 87 | container_name: lemmy_postfix 88 | env_file: env.postfix 89 | restart: "always" 90 | logging: *default-logging 91 | 92 | volumes: 93 | extra_themes: 94 | pictrs: 95 | postgres: -------------------------------------------------------------------------------- /mastodon/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | backup: 3 | image: alpine:3.17.2 4 | container_name: mastodon_backup 5 | entrypoint: "tail -f /dev/null" 6 | restart: unless-stopped 7 | volumes: 8 | - web:/mastodon/public/system:ro 9 | - redis:/data:ro 10 | - db:/var/lib/postgresql/data:ro 11 | 12 | db: 13 | image: postgres:14-alpine 14 | container_name: mastodon_db 15 | restart: unless-stopped 16 | env_file: env.postgres 17 | shm_size: 256mb 18 | networks: 19 | - internal_network 20 | healthcheck: 21 | test: [ 'CMD', 'pg_isready', '-U', 'mastodon' ] 22 | volumes: 23 | - db:/var/lib/postgresql/data 24 | 25 | redis: 26 | image: redis:7-alpine 27 | container_name: mastodon_redis 28 | restart: unless-stopped 29 | networks: 30 | - internal_network 31 | healthcheck: 32 | test: [ 'CMD', 'redis-cli', 'ping' ] 33 | volumes: 34 | - redis:/data 35 | 36 | web: 37 | image: ghcr.io/mastodon/mastodon:v4.3.8 38 | container_name: mastodon_web 39 | restart: unless-stopped 40 | env_file: env.production 41 | command: bundle exec puma -C config/puma.rb 42 | networks: 43 | - external_network 44 | - internal_network 45 | healthcheck: 46 | # prettier-ignore 47 | test: ['CMD-SHELL',"curl -s --noproxy localhost localhost:3000/health | grep -q 'OK' || exit 1"] 48 | ports: 49 | - 8012:3000 50 | depends_on: 51 | - db 52 | - redis 53 | volumes: 54 | - web:/mastodon/public/system 55 | extra_hosts: 56 | - "host.docker.internal:host-gateway" 57 | 58 | streaming: 59 | image: ghcr.io/mastodon/mastodon-streaming:v4.3.8 60 | container_name: mastodon_streaming 61 | restart: unless-stopped 62 | env_file: env.production 63 | command: node ./streaming/index.js 64 | networks: 65 | - external_network 66 | - internal_network 67 | healthcheck: 68 | # prettier-ignore 69 | test: ['CMD-SHELL', "curl -s --noproxy localhost localhost:4000/api/v1/streaming/health | grep -q 'OK' || exit 1"] 70 | ports: 71 | - 8013:4000 72 | depends_on: 73 | - db 74 | - redis 75 | extra_hosts: 76 | - "host.docker.internal:host-gateway" 77 | 78 | sidekiq: 79 | image: ghcr.io/mastodon/mastodon:v4.3.8 80 | container_name: mastodon_sidekiq 81 | restart: unless-stopped 82 | env_file: env.production 83 | command: bundle exec sidekiq 84 | depends_on: 85 | - db 86 | - redis 87 | networks: 88 | - external_network 89 | - internal_network 90 | healthcheck: 91 | test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"] 92 | volumes: 93 | - web:/mastodon/public/system 94 | 95 | networks: 96 | external_network: 97 | internal_network: 98 | internal: true 99 | 100 | volumes: 101 | sidekiq: 102 | db: 103 | redis: 104 | web: -------------------------------------------------------------------------------- /nginx/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | backup: 3 | image: alpine:3.17.2 4 | container_name: switchboard_backup 5 | entrypoint: "tail -f /dev/null" 6 | restart: unless-stopped 7 | volumes: 8 | - letsencrypt:/etc/letsencrypt:ro 9 | - authelia_db:/var/lib/postgresql/data:ro 10 | 11 | authelia: 12 | image: authelia/authelia:4.39 13 | container_name: switchboard_authelia 14 | restart: unless-stopped 15 | environment: 16 | - TZ=America/Los_Angeles 17 | expose: 18 | - 9091 19 | volumes: 20 | - ./env.authelia_configuration.yml:/config/configuration.yml 21 | - ./env.authelia_users_database.yml:/config/users_database.yml 22 | - ./env.authelia_notification.txt:/config/notification.txt 23 | - authelia_logs:/logs 24 | network_mode: host 25 | depends_on: 26 | - postgres 27 | - redis 28 | 29 | postgres: 30 | image: postgres:15 31 | container_name: switchboard_authelia_postgres 32 | restart: unless-stopped 33 | env_file: env.db 34 | network_mode: host 35 | expose: 36 | - 5432 37 | volumes: 38 | - authelia_db:/var/lib/postgresql/data 39 | 40 | redis: 41 | image: redis:alpine 42 | container_name: switchboard_authelia_redis 43 | security_opt: 44 | - no-new-privileges:true 45 | expose: 46 | - 6379 47 | restart: unless-stopped 48 | environment: 49 | - TZ=America/Los_Angeles 50 | command: redis-server --appendonly yes 51 | volumes: 52 | - authelia_redis:/data 53 | network_mode: host 54 | 55 | nginx: 56 | image: linuxserver/nginx 57 | container_name: switchboard 58 | volumes: 59 | - ./sites:/config/nginx/site-confs 60 | - ./snippets:/etc/nginx/snippets 61 | - logs:/var/log/nginx 62 | - letsencrypt:/etc/letsencrypt 63 | - certbot:/var/www/certbot 64 | restart: unless-stopped 65 | network_mode: host 66 | 67 | # Get one certificate 68 | # letsencrypt_one: 69 | # image: certbot/certbot 70 | # container_name: switchboard_letsencrypt_one 71 | # entrypoint: "" 72 | # command: > 73 | # sh -c "certbot certonly --reinstall -n -v -d penpot.starbase80.dev --cert-name penpot.starbase80.dev --webroot --webroot-path /var/www/certbot/ --agree-tos --email jordan@notclickable.com" 74 | # depends_on: 75 | # - nginx 76 | # volumes: 77 | # - letsencrypt:/etc/letsencrypt 78 | # - certbot:/var/www/certbot 79 | # environment: 80 | # - TERM=xterm 81 | 82 | # Renew certificates 83 | letsencrypt: 84 | image: certbot/certbot 85 | container_name: switchboard_letsencrypt 86 | entrypoint: "" 87 | command: > 88 | sh -c "certbot renew --keep-until-expiring -n -v" 89 | depends_on: 90 | - nginx 91 | volumes: 92 | - letsencrypt:/etc/letsencrypt 93 | - certbot:/var/www/certbot 94 | environment: 95 | - TERM=xterm 96 | 97 | volumes: 98 | certbot: 99 | letsencrypt: 100 | logs: 101 | authelia_logs: 102 | authelia_redis: 103 | authelia_db: -------------------------------------------------------------------------------- /lemmy/nginx_internal.conf: -------------------------------------------------------------------------------- 1 | worker_processes auto; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | # We construct a string consistent of the "request method" and "http accept header" 9 | # and then apply soem ~simply regexp matches to that combination to decide on the 10 | # HTTP upstream we should proxy the request to. 11 | # 12 | # Example strings: 13 | # 14 | # "GET:application/activity+json" 15 | # "GET:text/html" 16 | # "POST:application/activity+json" 17 | # 18 | # You can see some basic match tests in this regex101 matching this configuration 19 | # https://regex101.com/r/vwMJNc/1 20 | # 21 | # Learn more about nginx maps here http://nginx.org/en/docs/http/ngx_http_map_module.html 22 | map "$request_method:$http_accept" $proxpass { 23 | # If no explicit matches exists below, send traffic to lemmy-ui 24 | default "http://lemmy-ui"; 25 | 26 | # GET/HEAD requests that accepts ActivityPub or Linked Data JSON should go to lemmy. 27 | # 28 | # These requests are used by Mastodon and other fediverse instances to look up profile information, 29 | # discover site information and so on. 30 | "~^(?:GET|HEAD):.*?application\/(?:activity|ld)\+json" "http://lemmy"; 31 | 32 | # All non-GET/HEAD requests should go to lemmy 33 | # 34 | # Rather than calling out POST, PUT, DELETE, PATCH, CONNECT and all the verbs manually 35 | # we simply negate the GET|HEAD pattern from above and accept all possibly $http_accept values 36 | "~^(?!(GET|HEAD)).*:" "http://lemmy"; 37 | } 38 | 39 | upstream lemmy { 40 | # this needs to map to the lemmy (server) docker service hostname 41 | server "lemmy:8536"; 42 | } 43 | 44 | upstream lemmy-ui { 45 | # this needs to map to the lemmy-ui docker service hostname 46 | server "lemmy-ui:1234"; 47 | } 48 | 49 | server { 50 | # this is the port inside docker, not the public one yet 51 | listen 1236; 52 | listen 8536; 53 | 54 | # change if needed, this is facing the public web 55 | server_name localhost; 56 | server_tokens off; 57 | 58 | gzip on; 59 | gzip_types text/css application/javascript image/svg+xml; 60 | gzip_vary on; 61 | 62 | # Upload limit, relevant for pictrs 63 | client_max_body_size 20M; 64 | 65 | add_header X-Frame-Options SAMEORIGIN; 66 | add_header X-Content-Type-Options nosniff; 67 | add_header X-XSS-Protection "1; mode=block"; 68 | 69 | # Send actual client IP upstream 70 | proxy_set_header X-Real-IP $remote_addr; 71 | proxy_set_header Host $host; 72 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 73 | 74 | # frontend general requests 75 | location / { 76 | proxy_pass $proxpass; 77 | rewrite ^(.+)/+$ $1 permanent; 78 | } 79 | 80 | # security.txt 81 | location = /.well-known/security.txt { 82 | proxy_pass "http://lemmy-ui"; 83 | } 84 | 85 | # backend 86 | location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known) { 87 | proxy_pass "http://lemmy"; 88 | 89 | # proxy common stuff 90 | proxy_http_version 1.1; 91 | proxy_set_header Upgrade $http_upgrade; 92 | proxy_set_header Connection "upgrade"; 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | Docker compose files for personal services. Some services are exposed to the Internet, others are served to the local network and any devices using Tailscale. Hosting provided by Cloudflare. 4 | 5 | ## Prerequisites 6 | 7 | - [Tailscale](https://tailscale.com/download/) 8 | - [Docker engine](https://docs.docker.com/engine/install/) 9 | - [Docker compose](https://docs.docker.com/compose/install/) 10 | - [Cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation) 11 | 12 | ## Environment variables 13 | 14 | Many services mention `env_file` in their `compose.yml`. For security reasons these files are not checked in. 15 | 16 | # Services and ports 17 | 18 | - nginx (80, 443) 19 | - Mastodon (8010-8013) 20 | - Jellyfin (8030) 21 | - Calibre (8040) 22 | - Miniflux (8050) 23 | - Homepage (8090) 24 | - Portainer (8160) 25 | - Calibre (8170) 26 | - Shamir's Secret Sharing Scheme (8200) 27 | - Lemmy (8260) 28 | - GitLab (8280) 29 | 30 | # Cloudflare 31 | 32 | All publicly facing websites are served via Cloudflare Tunnels. To edit them, use the [Cloudflare Dashboard](https://dash.cloudflare.com) to enter Zero Trust. Select Access > Tunnels and manage `starbase-80`. Select the "Public Hostname" tab to add a new subdomain. 33 | 34 | Be sure to set the **HTTP Host Header** to `subdomain.starbase80.dev`. When adding SSL sites, set the **Origin Server Name** to the same value and check **No TLS Verify**. 35 | 36 | Run `systemctl restart cloudflared` after updating any Cloudflare config. Not necessary when adding public hostnames. 37 | 38 | # SSL certificates 39 | 40 | Publicly facing websites should get SSL certificates from Let's Encrypt on top of Cloudflare's SSL. 41 | 42 | 1. Create a new public hostname in Cloudflare Zero Trust 43 | 1. Set the service to be http://localhost:80 44 | 1. In `/nginx/sites`, add a new `.conf` for the site 45 | - Fill out the `server listen 80` block and comment out the `server listen 443` block 46 | - Ensure the `server listen 80 location /` block ends with `proxy_pass http://service_name_backend;` 47 | 1. Modify `/nginx/compose.yml` to expose the `letsencrypt_one` service and comment out the `letsencrypt` service 48 | 1. Restart nginx: `docker exec switchboard nginx -s reload` 49 | 1. In `/nginx`, run `docker compose up -d` to start the `letsencrypt_one` service 50 | 1. Check in Portainer that the `letsencrypt_one` service exited after saving the certificate 51 | 1. Modify `/nginx/compose.yml` to expose the `letsencrypt` service and comment out the `letsencrypt_one` service 52 | 1. Modify the `/nginx/sites/service_name.conf` file 53 | - Comment out the `server listen 80` block 54 | - Uncomment the `server listen 443` block 55 | 1. Restart nginx: `docker exec switchboard nginx -s reload` 56 | 1. Go back to Cloudflare Zero Trust and change the service to be https://localhost:443 57 | 1. Set the **Origin Server Name** to the same value as **HTTP Host Header** and check **No TLS Verify** 58 | 59 | # nginx 60 | 61 | ## Error during git pull 62 | If you get an error when pulling changes to nginx's sites/ folder, run this command: 63 | 64 | ``` bash 65 | sudo chown -R $USER:$USER ./nginx/sites 66 | ``` 67 | 68 | ## Restarting to pull new changes 69 | 70 | ``` bash 71 | docker exec switchboard nginx -s reload 72 | ``` 73 | 74 | # File permissions 75 | 76 | When adding .sh files, run `chmod +x ` to make them executable. Or run this from the root: 77 | 78 | ``` bash 79 | sudo find . -name "*.sh" -exec chmod +x {} \; 80 | ``` 81 | 82 | # Cron jobs 83 | 84 | ``` bash 85 | # Run this to edit the crontab 86 | crontab -e -u jordan 87 | 88 | # Add these lines to the crontab 89 | 0 2 * * * /bin/bash /home/jordan/docker-symphony/nginx/renew.sh 90 | 0 3 * * * /bin/bash /home/jordan/docker-symphony/backup-all.sh 91 | ``` 92 | 93 | # Docker entering a container 94 | 95 | ``` bash 96 | docker exec -it container_name bash 97 | ``` 98 | 99 | # Update Cloudflared 100 | 101 | ``` bash 102 | curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb && sudo dpkg -i cloudflared.deb 103 | 104 | sudo systemctl restart cloudflared.service 105 | ``` -------------------------------------------------------------------------------- /nginx/sample.env.authelia_configuration.yml: -------------------------------------------------------------------------------- 1 | --- 2 | server: 3 | host: 0.0.0.0 4 | port: 9091 5 | buffers: 6 | read: 65536 7 | write: 65536 8 | 9 | log: 10 | level: info 11 | file_path: /logs/authelia.log 12 | format: json 13 | keep_stdout: true 14 | 15 | theme: light 16 | 17 | jwt_secret: SECRET 18 | default_redirection_url: https://auth.starbase80.dev 19 | 20 | totp: 21 | issuer: authelia.com 22 | 23 | authentication_backend: 24 | file: 25 | path: /config/users_database.yml 26 | 27 | access_control: 28 | default_policy: deny 29 | networks: 30 | - name: internal 31 | networks: 32 | - 192.168.1.0/24 33 | rules: 34 | - domain: "*.starbase80.dev" 35 | policy: bypass 36 | networks: 37 | - internal 38 | - domain: "*.starbase80.dev" 39 | policy: bypass 40 | resources: 41 | - '^/favicon.ico$' 42 | - '^/apple-touch-icon.png$' 43 | - '^/apple-touch-icon-precomposed.png$' 44 | - domain: metube.starbase80.dev 45 | policy: bypass 46 | resources: 47 | - '^/favicon/.*$' 48 | - domain: jellyfin.starbase80.dev 49 | policy: bypass 50 | resources: 51 | - '^/web/.*$' 52 | - domain: miniflux.starbase80.dev 53 | policy: bypass 54 | resources: 55 | - '^/accounts/ClientLogin$' 56 | - '^/reader/api.*$' 57 | - domain: woodpecker.starbase80.dev 58 | policy: bypass 59 | resources: 60 | - '^/web-config.js$' 61 | - '^/hook.*$' 62 | - domain: git.starbase80.dev 63 | policy: bypass 64 | resources: 65 | - '^/web-config.js$' 66 | - '^/login/oauth/.*$' 67 | - '^/api/.*$' 68 | - '^.*\.git.*$' 69 | - domain: portainer.starbase80.dev 70 | policy: bypass 71 | resources: 72 | - '^/Public/.*$' 73 | - '^/static/.*$' 74 | - domain: standardnotesserver.starbase80.dev 75 | policy: bypass 76 | - domain: standardnotesfiles.starbase80.dev 77 | policy: bypass 78 | - domain: shamir.starbase80.dev 79 | policy: bypass 80 | - domain: outline.starbase80.dev 81 | policy: bypass 82 | - domain: "*.starbase80.dev" 83 | policy: one_factor 84 | 85 | session: 86 | name: authelia_session 87 | secret: SECRET 88 | expiration: 30d # 1 h 89 | inactivity: 5d # 5 day 90 | domain: starbase80.dev # Should match whatever your root protected domain is 91 | remember_me_duration: 30d 92 | redis: 93 | host: localhost 94 | port: 6379 95 | 96 | regulation: 97 | max_retries: 5 98 | find_time: 120m 99 | ban_time: 300m 100 | 101 | storage: 102 | encryption_key: SECRET 103 | local: 104 | path: /config/db.sqlite3 105 | 106 | notifier: 107 | filesystem: 108 | filename: /config/notification.txt 109 | 110 | ntp: 111 | address: "192.168.1.1:123" 112 | version: 3 113 | max_desync: 3s 114 | disable_startup_check: false 115 | disable_failure: false 116 | 117 | # OIDC config for Outline 118 | identity_providers: 119 | oidc: 120 | hmac_secret: SECRET 121 | -----BEGIN CERTIFICATE----- 122 | SECRET 123 | -----END CERTIFICATE----- 124 | -----BEGIN CERTIFICATE----- 125 | SECRET 126 | -----END CERTIFICATE----- 127 | issuer_private_key: | 128 | -----BEGIN RSA PRIVATE KEY----- 129 | SECRET 130 | -----END RSA PRIVATE KEY----- 131 | access_token_lifespan: 1h 132 | authorize_code_lifespan: 1m 133 | id_token_lifespan: 1h 134 | refresh_token_lifespan: 90m 135 | enable_client_debug_messages: false 136 | enforce_pkce: public_clients_only 137 | cors: 138 | endpoints: 139 | - authorization 140 | - token 141 | - revocation 142 | - introspection 143 | allowed_origins: 144 | - https://outline.starbase80.dev 145 | allowed_origins_from_client_redirect_uris: false 146 | clients: 147 | - id: outline 148 | description: Outline 149 | secret: 'SECRETSECRETSECRET' 150 | sector_identifier: '' 151 | public: false 152 | authorization_policy: one_factor 153 | consent_mode: explicit 154 | pre_configured_consent_duration: 1w 155 | audience: [] 156 | scopes: 157 | - openid 158 | - groups 159 | - email 160 | - profile 161 | redirect_uris: 162 | - https://outline.starbase80.dev/auth/oidc.callback 163 | grant_types: 164 | - refresh_token 165 | - authorization_code 166 | response_types: 167 | - code 168 | response_modes: 169 | - form_post 170 | - query 171 | - fragment 172 | userinfo_signing_algorithm: none -------------------------------------------------------------------------------- /nginx/sites/mastodon.conf: -------------------------------------------------------------------------------- 1 | map $http_upgrade $connection_upgrade { 2 | default upgrade; 3 | '' close; 4 | } 5 | 6 | upstream mastodon_backend { 7 | server 192.168.1.34:8012 fail_timeout=0; 8 | } 9 | 10 | upstream mastodon_streaming { 11 | server 192.168.1.34:8013 fail_timeout=0; 12 | } 13 | 14 | proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g; 15 | 16 | # server { 17 | # listen 80; 18 | # listen [::]:80; 19 | # server_name notclickable.social www.notclickable.social; 20 | # root /home/mastodon/live/public; 21 | 22 | # access_log /var/log/nginx/notclickable.social.access.logs; 23 | # error_log /var/log/nginx/notclickable.social.error.logs; 24 | 25 | # location ^~ /.well-known/acme-challenge/ { 26 | # allow all; 27 | # root /var/www/certbot; 28 | # } 29 | 30 | # location / { 31 | # proxy_set_header X-Real-IP $remote_addr; 32 | # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 33 | # proxy_set_header X-Forwarded-Proto $scheme; 34 | # proxy_set_header Host $http_host; 35 | # proxy_set_header X-NginX-Proxy true; 36 | 37 | # return 301 https://$host$request_uri; 38 | # } 39 | # } 40 | 41 | server { 42 | listen 443 ssl http2; 43 | listen [::]:443 ssl http2; 44 | server_name notclickable.social; 45 | 46 | access_log /var/log/nginx/notclickable.social.access.logs; 47 | error_log /var/log/nginx/notclickable.social.error.logs; 48 | 49 | ssl_protocols TLSv1.2 TLSv1.3; 50 | ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; 51 | ssl_prefer_server_ciphers on; 52 | ssl_session_cache shared:SSL:10m; 53 | ssl_session_tickets off; 54 | 55 | ssl_certificate /etc/letsencrypt/live/notclickable.social/fullchain.pem; 56 | ssl_certificate_key /etc/letsencrypt/live/notclickable.social/privkey.pem; 57 | 58 | keepalive_timeout 70; 59 | sendfile on; 60 | client_max_body_size 80m; 61 | 62 | root /home/mastodon/live/public; 63 | 64 | gzip on; 65 | gzip_disable "msie6"; 66 | gzip_vary on; 67 | gzip_proxied any; 68 | gzip_comp_level 6; 69 | gzip_buffers 16 8k; 70 | gzip_http_version 1.1; 71 | gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml image/x-icon; 72 | 73 | location / { 74 | try_files $uri @proxy; 75 | } 76 | 77 | location ^~ /.well-known/acme-challenge/ { 78 | allow all; 79 | root /var/www/certbot; 80 | } 81 | 82 | location = /sw.js { 83 | add_header Cache-Control "public, max-age=604800, must-revalidate"; 84 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; 85 | try_files $uri @proxy; 86 | } 87 | 88 | location ~ ^/assets/ { 89 | add_header Cache-Control "public, max-age=2419200, must-revalidate"; 90 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; 91 | try_files $uri @proxy; 92 | } 93 | 94 | location ~ ^/avatars/ { 95 | add_header Cache-Control "public, max-age=2419200, must-revalidate"; 96 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; 97 | try_files $uri @proxy; 98 | } 99 | 100 | location ~ ^/emoji/ { 101 | add_header Cache-Control "public, max-age=2419200, must-revalidate"; 102 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; 103 | try_files $uri @proxy; 104 | } 105 | 106 | location ~ ^/headers/ { 107 | add_header Cache-Control "public, max-age=2419200, must-revalidate"; 108 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; 109 | try_files $uri @proxy; 110 | } 111 | 112 | location ~ ^/packs/ { 113 | add_header Cache-Control "public, max-age=2419200, must-revalidate"; 114 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; 115 | try_files $uri @proxy; 116 | } 117 | 118 | location ~ ^/shortcuts/ { 119 | add_header Cache-Control "public, max-age=2419200, must-revalidate"; 120 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; 121 | try_files $uri @proxy; 122 | } 123 | 124 | location ~ ^/sounds/ { 125 | add_header Cache-Control "public, max-age=2419200, must-revalidate"; 126 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; 127 | try_files $uri @proxy; 128 | } 129 | 130 | location ~ ^/system/ { 131 | add_header Cache-Control "public, max-age=2419200, immutable"; 132 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; 133 | try_files $uri @proxy; 134 | } 135 | 136 | location ^~ /api/v1/streaming { 137 | proxy_set_header Host $host; 138 | proxy_set_header X-Real-IP $remote_addr; 139 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 140 | proxy_set_header X-Forwarded-Proto $scheme; 141 | proxy_set_header Proxy ""; 142 | 143 | proxy_pass http://mastodon_streaming; 144 | proxy_buffering off; 145 | proxy_redirect off; 146 | proxy_http_version 1.1; 147 | proxy_set_header Upgrade $http_upgrade; 148 | proxy_set_header Connection $connection_upgrade; 149 | 150 | add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; 151 | 152 | tcp_nodelay on; 153 | } 154 | 155 | location @proxy { 156 | proxy_set_header Host $host; 157 | proxy_set_header X-Real-IP $remote_addr; 158 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 159 | proxy_set_header X-Forwarded-Proto $scheme; 160 | proxy_set_header Proxy ""; 161 | proxy_pass_header Server; 162 | 163 | proxy_pass http://mastodon_backend; 164 | proxy_buffering on; 165 | proxy_redirect off; 166 | proxy_http_version 1.1; 167 | proxy_set_header Upgrade $http_upgrade; 168 | proxy_set_header Connection $connection_upgrade; 169 | 170 | proxy_cache CACHE; 171 | proxy_cache_valid 200 7d; 172 | proxy_cache_valid 410 24h; 173 | proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; 174 | add_header X-Cached $upstream_cache_status; 175 | 176 | tcp_nodelay on; 177 | } 178 | 179 | error_page 404 500 501 502 503 504 /500.html; 180 | } 181 | 182 | server { 183 | listen 443 ssl http2; 184 | listen [::]:443 ssl http2; 185 | server_name www.notclickable.social; 186 | 187 | access_log /var/log/nginx/notclickable.social.access.logs; 188 | error_log /var/log/nginx/notclickable.social.error.logs; 189 | 190 | ssl_protocols TLSv1.2 TLSv1.3; 191 | ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; 192 | ssl_prefer_server_ciphers on; 193 | ssl_session_cache shared:SSL:10m; 194 | ssl_session_tickets off; 195 | 196 | ssl_certificate /etc/letsencrypt/live/notclickable.social/fullchain.pem; 197 | ssl_certificate_key /etc/letsencrypt/live/notclickable.social/privkey.pem; 198 | 199 | return 301 https://notclickable.social$request_uri; 200 | } -------------------------------------------------------------------------------- /homepage/public/icons/home-assistant.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | --------------------------------------------------------------------------------