From d97525408e148a44b4f6133909af5b7b96a3c48a Mon Sep 17 00:00:00 2001 From: Dmitry Bikulov Date: Sun, 23 Aug 2026 17:17:37 +0300 Subject: [PATCH] Initial commit --- .gitignore | 5 ++ gitea/docker-compose.yaml | 24 +++++++ gitea/env.example | 1 + glance/data/glance/glance.yml | 109 ++++++++++++++++++++++++++++++++ glance/docker-compose.yaml | 20 ++++++ glance/env.example | 1 + memos/docker-compose.yaml | 24 +++++++ memos/env.example | 1 + miniflux/docker-compose.yaml | 51 +++++++++++++++ miniflux/env.example | 5 ++ outline/docker-compose.yaml | 80 +++++++++++++++++++++++ outline/env.example | 7 ++ traefik/docker-compose.yaml | 29 +++++++++ traefik/env.example | 1 + vaultwarden/docker-compose.yaml | 29 +++++++++ vaultwarden/env.example | 4 ++ 16 files changed, 391 insertions(+) create mode 100644 .gitignore create mode 100644 gitea/docker-compose.yaml create mode 100644 gitea/env.example create mode 100644 glance/data/glance/glance.yml create mode 100644 glance/docker-compose.yaml create mode 100644 glance/env.example create mode 100644 memos/docker-compose.yaml create mode 100644 memos/env.example create mode 100644 miniflux/docker-compose.yaml create mode 100644 miniflux/env.example create mode 100644 outline/docker-compose.yaml create mode 100644 outline/env.example create mode 100644 traefik/docker-compose.yaml create mode 100644 traefik/env.example create mode 100644 vaultwarden/docker-compose.yaml create mode 100644 vaultwarden/env.example diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42c20e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.env + +data/* + +!data/glance/ diff --git a/gitea/docker-compose.yaml b/gitea/docker-compose.yaml new file mode 100644 index 0000000..3d43910 --- /dev/null +++ b/gitea/docker-compose.yaml @@ -0,0 +1,24 @@ +services: + gitea: + image: gitea/gitea + container_name: gitea + restart: unless-stopped + networks: + - proxy + ports: + - "22:22" + volumes: + - ./data/gitea:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + labels: + - "traefik.enable=true" + - "traefik.http.services.gitea.loadbalancer.server.port=3000" + - "traefik.http.routers.gitea.rule=Host(`${GITEA_HOST}`)" + - "traefik.http.routers.gitea.entrypoints=websecure" + - "traefik.http.routers.gitea.tls.certresolver=le" + +networks: + proxy: + name: proxy + external: true diff --git a/gitea/env.example b/gitea/env.example new file mode 100644 index 0000000..b830591 --- /dev/null +++ b/gitea/env.example @@ -0,0 +1 @@ +GITEA_HOST= diff --git a/glance/data/glance/glance.yml b/glance/data/glance/glance.yml new file mode 100644 index 0000000..73e7560 --- /dev/null +++ b/glance/data/glance/glance.yml @@ -0,0 +1,109 @@ +pages: + - name: Home + head-widgets: + - type: monitor + cache: 1m + title: Services + hide-header: true + sites: + - title: Git + url: https://git.ksar.dev + icon: sh:gitea + - title: Wiki + url: https://wiki.ksar.dev + icon: https://cdn.jsdelivr.net/gh/selfhst/icons@main/png/outline.png + - title: Notes + url: https://notes.ksar.dev + icon: https://cdn.jsdelivr.net/gh/selfhst/icons@main/png/memos.png + - title: RSS + url: https://rss.ksar.dev + icon: https://cdn.jsdelivr.net/gh/selfhst/icons@main/png/miniflux-light.png + - title: Vaultwarden + url: https://bw.ksar.dev + icon: https://cdn.jsdelivr.net/gh/selfhst/icons@main/png/vaultwarden-light.png + + columns: + - size: small + widgets: + - type: weather + hide-header: true + location: Moscow, Russia + units: metric + hour-format: 24h + + - type: calendar + hide-header: true + first-day-of-week: monday + + - type: releases + hide-header: true + show-source-icon: true + repositories: + - docmost/docmost + - glanceapp/glance + - traefik/traefik + - usememos/memos + - miniflux/v2 + - MHSanaei/3x-ui + - go-gitea/gitea + - dani-garcia/vaultwarden + - dockerhub:gitlab/gitlab-ce + - dockerhub:jetbrains/youtrack + + - size: full + widgets: + - type: search + search-engine: kagi + hide-header: true + + - type: group + widgets: + - type: hacker-news + limit: 30 + collapse-after: 10 + - type: lobsters + limit: 30 + collapse-after: 10 + - type: reddit + subreddit: technology + show-thumbnails: true + limit: 30 + collapse-after: 10 + top-period: week + sort-by: best + - type: reddit + subreddit: selfhosted + show-thumbnails: true + limit: 30 + collapse-after: 10 + top-period: week + sort-by: best + - type: reddit + subreddit: science + show-thumbnails: true + limit: 30 + collapse-after: 10 + top-period: week + sort-by: best + + - size: small + widgets: + - type: videos + style: vertical-list + hide-header: true + collapse-after: 15 + channels: + - UCDaIW2zPRWhzQ9Hj7a0QP1w # Руслан Усачев + - UCY6zVRa3Km52bsBmpyQnk6A # Vert Dider + - UCJQlWxJziHWs0Bq59D2Qw8A # РЫНДЫЧ + - UC2q4mHrzoR48mwSuAYtVPtQ # Александр Панчин + - UCerK03vbFNIDc8ABS87gHzw # ЛЕСНЫЕ + - UCYulscWJwKgs35FTF9FaNlw # Дмитрий Машков + - UCbS8hyArQ_VWPSBcc56FsLw # ПроВокруг + - UCQwRlx8hVI-CFv_E-v5s84Q # Адвокат Егоров + - UC2Ru64PHqW4FxoP0xhQRvJg # ТОПЛЕС + - UCY1kMZp36IQSyNx_9h4mpCg # Mark Rober + - UCt9SXdrwKnV_4WwRjUmHZsQ # Михаил Лидин + - UC6cqazSR6CnVMClY0bJI0Lg # BadComedian + - UCXUPKJO5MZQN11PqgIvyuvQ # Andrej Karpathy + - UCisCR8RgtPcHGpUXblKxrvQ # Клинический случай diff --git a/glance/docker-compose.yaml b/glance/docker-compose.yaml new file mode 100644 index 0000000..1c459dc --- /dev/null +++ b/glance/docker-compose.yaml @@ -0,0 +1,20 @@ +services: + glance: + image: glanceapp/glance + container_name: glance + restart: unless-stopped + networks: + - proxy + volumes: + - ./data/glance:/app/config + labels: + - "traefik.enable=true" + - "traefik.http.services.glance.loadbalancer.server.port=8080" + - "traefik.http.routers.glance.rule=Host(`${GLANCE_HOST}`)" + - "traefik.http.routers.glance.entrypoints=websecure" + - "traefik.http.routers.glance.tls.certresolver=le" + +networks: + proxy: + name: proxy + external: true diff --git a/glance/env.example b/glance/env.example new file mode 100644 index 0000000..cc4fcb3 --- /dev/null +++ b/glance/env.example @@ -0,0 +1 @@ +GLANCE_HOST= diff --git a/memos/docker-compose.yaml b/memos/docker-compose.yaml new file mode 100644 index 0000000..7a0e2ff --- /dev/null +++ b/memos/docker-compose.yaml @@ -0,0 +1,24 @@ +services: + memos: + image: neosmemo/memos:stable + container_name: memos + restart: unless-stopped + networks: + - proxy + volumes: + - ./data/memos:/var/opt/memos + environment: + MEMOS_PORT: 5230 + MEMOS_DRIVER: sqlite + MEMOS_INSTANCE_URL: https://${MEMOS_HOST}/ + labels: + - "traefik.enable=true" + - "traefik.http.services.memos.loadbalancer.server.port=5230" + - "traefik.http.routers.memos.rule=Host(`${MEMOS_HOST}`)" + - "traefik.http.routers.memos.entrypoints=websecure" + - "traefik.http.routers.memos.tls.certresolver=le" + +networks: + proxy: + name: proxy + external: true diff --git a/memos/env.example b/memos/env.example new file mode 100644 index 0000000..ec0bd44 --- /dev/null +++ b/memos/env.example @@ -0,0 +1 @@ +MEMOS_HOST= diff --git a/miniflux/docker-compose.yaml b/miniflux/docker-compose.yaml new file mode 100644 index 0000000..bded7ca --- /dev/null +++ b/miniflux/docker-compose.yaml @@ -0,0 +1,51 @@ +services: + miniflux: + image: miniflux/miniflux:latest + container_name: miniflux + restart: unless-stopped + depends_on: + miniflux-db: + condition: service_healthy + networks: + - proxy + - miniflux + environment: + - DATABASE_URL=postgres://miniflux:${MINIFLUX_POSTGRES_PASSWORD}@minifluxdb/miniflux?sslmode=disable + - RUN_MIGRATIONS=1 + - OAUTH2_PROVIDER=oidc + - OAUTH2_CLIENT_ID=${MINIFLUX_OAUTH2_CLIENT_ID} + - OAUTH2_CLIENT_SECRET=${MINIFLUX_OAUTH2_CLIENT_SECRET} + - OAUTH2_REDIRECT_URL=https://${MINIFLUX_HOST}/oauth2/oidc/callback + - OAUTH2_OIDC_DISCOVERY_ENDPOINT=https://${MINIFLUX_OAUTH2_OIDC_DISCOVERY_ENDPOINT} + - OAUTH2_USER_CREATION=1 + labels: + - "traefik.enable=true" + - "traefik.http.services.miniflux.loadbalancer.server.port=8080" + - "traefik.http.routers.miniflux.rule=Host(`${MINIFLUX_HOST}`)" + - "traefik.http.routers.miniflux.entrypoints=websecure" + - "traefik.http.routers.miniflux.tls.certresolver=le" + + miniflux-db: + image: postgres:latest + container_name: miniflux-db + restart: unless-stopped + networks: + - miniflux + environment: + - POSTGRES_USER=miniflux + - POSTGRES_PASSWORD=${MINIFLUX_POSTGRES_PASSWORD} + - POSTGRES_DB=miniflux + volumes: + - ./data/miniflux-db:/var/lib/postgresql + healthcheck: + test: ["CMD-SHELL", "pg_isready -U outline -d outline"] + interval: 10s + timeout: 5s + retries: 5 + +networks: + proxy: + name: proxy + external: true + miniflux: + name: miniflux \ No newline at end of file diff --git a/miniflux/env.example b/miniflux/env.example new file mode 100644 index 0000000..bc9f2af --- /dev/null +++ b/miniflux/env.example @@ -0,0 +1,5 @@ +MINIFLUX_HOST= +MINIFLUX_POSTGRES_PASSWORD= +MINIFLUX_OAUTH2_CLIENT_ID= +MINIFLUX_OAUTH2_CLIENT_SECRET= +MINIFLUX_OAUTH2_OIDC_DISCOVERY_ENDPOINT= \ No newline at end of file diff --git a/outline/docker-compose.yaml b/outline/docker-compose.yaml new file mode 100644 index 0000000..17000dc --- /dev/null +++ b/outline/docker-compose.yaml @@ -0,0 +1,80 @@ +services: + outline: + image: outlinewiki/outline:latest + container_name: outline + restart: unless-stopped + networks: + - proxy + - outline + environment: + - NODE_ENV=production + - URL=https://${OUTLINE_HOST} + - PORT=3000 + - FILE_STORAGE_UPLOAD_MAX_SIZE=1024000000 + - SECRET_KEY=${OUTLINE_SECRET_KEY} + - UTILS_SECRET=${OUTLINE_UTILS_SECRET} + - POSTGRES_PASSWORD=${OUTLINE_POSTGRES_PASSWORD} + - DATABASE_URL=postgres://outline:${OUTLINE_POSTGRES_PASSWORD}@outline-db:5432/outline + - PGSSLMODE=disable + - REDIS_URL=redis://outline-redis:6379 + - FILE_STORAGE=local + - FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data + - OIDC_ISSUER_URL=https://${OUTLINE_OIDC_ISSUER_URL} + - OIDC_CLIENT_ID=${OUTLINE_OIDC_CLIENT_ID} + - OIDC_CLIENT_SECRET=${OUTLINE_OIDC_CLIENT_SECRET} + - OIDC_DISPLAY_NAME=Gitea + - OIDC_SCOPES=openid profile email + - OIDC_USERNAME_CLAIM=preferred_username + - OIDC_LOGOUT_URI=https://${OUTLINE_HOST} + volumes: + - ./data/outline:/var/lib/outline/data + depends_on: + outline-db: + condition: service_healthy + outline-redis: + condition: service_healthy + labels: + - "traefik.enable=true" + - "traefik.http.services.outline.loadbalancer.server.port=3000" + - "traefik.http.routers.outline.rule=Host(`${OUTLINE_HOST}`)" + - "traefik.http.routers.outline.entrypoints=websecure" + - "traefik.http.routers.outline.tls.certresolver=le" + + outline-db: + image: postgres:latest + container_name: outline-db + restart: unless-stopped + networks: + - outline + environment: + POSTGRES_USER: outline + POSTGRES_PASSWORD: ${OUTLINE_POSTGRES_PASSWORD} + POSTGRES_DB: outline + volumes: + - ./data/outline-db:/var/lib/postgresql + healthcheck: + test: ["CMD-SHELL", "pg_isready -U outline -d outline"] + interval: 10s + timeout: 5s + retries: 5 + + outline-redis: + image: redis:7-alpine + container_name: outline-redis + restart: unless-stopped + networks: + - outline + volumes: + - ./data/outline-redis:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + +networks: + proxy: + name: proxy + external: true + outline: + name: outline diff --git a/outline/env.example b/outline/env.example new file mode 100644 index 0000000..6116cf3 --- /dev/null +++ b/outline/env.example @@ -0,0 +1,7 @@ +OUTLINE_HOST= +OUTLINE_SECRET_KEY= # openssl rand -hex 32 +OUTLINE_UTILS_SECRET= +OUTLINE_POSTGRES_PASSWORD= +OUTLINE_OIDC_CLIENT_ID= +OUTLINE_OIDC_CLIENT_SECRET= +OUTLINE_OIDC_ISSUER_URL= diff --git a/traefik/docker-compose.yaml b/traefik/docker-compose.yaml new file mode 100644 index 0000000..f94a446 --- /dev/null +++ b/traefik/docker-compose.yaml @@ -0,0 +1,29 @@ +services: + traefik: + image: traefik:latest + container_name: traefik + restart: unless-stopped + networks: + - proxy + command: + - "--api.insecure=false" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entryPoints.web.address=:80" + - "--entryPoints.web.http.redirections.entryPoint.to=websecure" + - "--entryPoints.web.http.redirections.entryPoint.scheme=https" + - "--entryPoints.websecure.address=:443" + - "--certificatesresolvers.le.acme.tlschallenge=true" + - "--certificatesresolvers.le.acme.email=${TRAEFIK_MAIL}" + - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json" + - "--providers.docker.network=proxy" + ports: + - "80:80" + - "443:443" + volumes: + - ./data/traefik:/letsencrypt + - /var/run/docker.sock:/var/run/docker.sock:ro + +networks: + proxy: + name: proxy diff --git a/traefik/env.example b/traefik/env.example new file mode 100644 index 0000000..0577320 --- /dev/null +++ b/traefik/env.example @@ -0,0 +1 @@ +TRAEFIK_MAIL= diff --git a/vaultwarden/docker-compose.yaml b/vaultwarden/docker-compose.yaml new file mode 100644 index 0000000..596ef4f --- /dev/null +++ b/vaultwarden/docker-compose.yaml @@ -0,0 +1,29 @@ +services: + vaultwarden: + image: vaultwarden/server:latest + container_name: vaultwarden + restart: unless-stopped + networks: + - proxy + environment: + DOMAIN: "https://${VAULTWARDEN_HOST}" + SIGNUPS_ALLOWED: "false" + SSO_ENABLED: "true" + SSO_ONLY: "true" + SSO_SIGNUPS_MATCH_EMAIL: "true" + SSO_AUTHORITY: https://${VAULTWARDEN_SSO_AUTHORITY} + SSO_CLIENT_ID: ${VAULTWARDEN_SSO_CLIENT_ID} + SSO_CLIENT_SECRET: ${VAULTWARDEN_SSO_CLIENT_SECRET} + volumes: + - ./data/vaultwarden:/data/ + labels: + - "traefik.enable=true" + - "traefik.http.services.vaultwarden.loadbalancer.server.port=80" + - "traefik.http.routers.vaultwarden.rule=Host(`${VAULTWARDEN_HOST}`)" + - "traefik.http.routers.vaultwarden.entrypoints=websecure" + - "traefik.http.routers.vaultwarden.tls.certresolver=le" + +networks: + proxy: + name: proxy + external: true diff --git a/vaultwarden/env.example b/vaultwarden/env.example new file mode 100644 index 0000000..55ced13 --- /dev/null +++ b/vaultwarden/env.example @@ -0,0 +1,4 @@ +VAULTWARDEN_HOST= +VAULTWARDEN_SSO_AUTHORITY= +VAULTWARDEN_SSO_CLIENT_ID= +VAULTWARDEN_SSO_CLIENT_SECRET=