From b4bce043d91e51e712a96d08ca672271e72506b4 Mon Sep 17 00:00:00 2001 From: Rishi Ghan Date: Mon, 29 Dec 2025 17:55:42 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=9B=20First=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 99 +++++++++++++++ stacks/backup/docker-compose.yml | 20 +++ stacks/backup/stack.env | 1 + stacks/documents/docker-compose.yml | 78 ++++++++++++ stacks/documents/stack.env | 5 + stacks/outline/README.md | 68 +++++++++++ stacks/outline/docker-compose.yml | 31 +++++ stacks/outline/redis.conf | 2 + stacks/outline/stack.env | 31 +++++ stacks/portainer/docker-compose.yml | 10 ++ stacks/productivity/README.md | 63 ++++++++++ stacks/productivity/docker-compose.yml | 80 ++++++++++++ stacks/productivity/feeds.opml | 31 +++++ stacks/productivity/stack.env | 1 + stacks/proxy/docker-compose.yml | 15 +++ stacks/seafile/README.md | 107 ++++++++++++++++ stacks/seafile/docker-compose.yml | 163 +++++++++++++++++++++++++ stacks/seafile/seafile.conf | 11 ++ stacks/seafile/seahub_settings.py | 29 +++++ stacks/seafile/stack.env | 7 ++ 20 files changed, 852 insertions(+) create mode 100644 stacks/backup/docker-compose.yml create mode 100644 stacks/backup/stack.env create mode 100644 stacks/documents/docker-compose.yml create mode 100644 stacks/documents/stack.env create mode 100644 stacks/outline/README.md create mode 100644 stacks/outline/docker-compose.yml create mode 100644 stacks/outline/redis.conf create mode 100644 stacks/outline/stack.env create mode 100644 stacks/portainer/docker-compose.yml create mode 100644 stacks/productivity/README.md create mode 100644 stacks/productivity/docker-compose.yml create mode 100644 stacks/productivity/feeds.opml create mode 100644 stacks/productivity/stack.env create mode 100644 stacks/proxy/docker-compose.yml create mode 100644 stacks/seafile/README.md create mode 100644 stacks/seafile/docker-compose.yml create mode 100644 stacks/seafile/seafile.conf create mode 100644 stacks/seafile/seahub_settings.py create mode 100644 stacks/seafile/stack.env diff --git a/README.md b/README.md index c8e2ad5..22c15f6 100644 --- a/README.md +++ b/README.md @@ -1 +1,100 @@ # Flook Stacks + +Docker Compose stacks for Flook (192.168.1.75) managed via Portainer. + +## Stacks + +| Stack | Services | Port(s) | Description | +|-------|----------|---------|-------------| +| portainer | portainer | 9000 | Stack management | +| proxy | npm | 1880, 18443, 81 | Nginx Proxy Manager (CRITICAL) | +| documents | paperless, paperless-db, paperless-redis, paperless-tika, paperless-gotenberg, onlyoffice | 8777, 8089, 4430 | Document management | +| productivity | gitlab, vaultwarden, memos, mortis, freshrss | 8929, 4743, 5230, 5231, 8054 | Personal tools | +| backup | borgmatic | - | Borg backup to chook | +| seafile | seafile, seadoc, mysql, redis, notification, md-server, seasearch | 8098, 8888, 8083, 8084, 4080 | File sync (migrated from VM) | +| outline | outline, postgres, redis | 3000 | Wiki (migrated from VM) | + +## Deployment Order + +1. `portainer` - Deploy first, manually +2. `productivity` - GitLab, Vaultwarden, Memos, FreshRSS, Mortis +3. `documents` - Paperless, OnlyOffice +4. `backup` - Borgmatic +5. `proxy` - CRITICAL - deploy carefully, brief downtime expected +6. `seafile` - After migrating data from VM +7. `outline` - After migrating data from VM + +## Migration Notes + +### Seafile Migration (from VM 192.168.1.112) + +1. **Stop Seafile on VM:** +```bash +ssh rishi@192.168.1.112 +cd /opt/seafile && docker compose down +``` + +2. **Create directories on Flook:** +```bash +mkdir -p /mnt/user/appdata/seafile/{data,db-data,seadoc-data,seasearch-data} +``` + +3. **Copy data:** +```bash +rsync -avP rishi@192.168.1.112:~/seafile/data/ /mnt/user/appdata/seafile/data/ +rsync -avP rishi@192.168.1.112:~/seafile/db-data/ /mnt/user/appdata/seafile/db-data/ +``` + +4. **Copy seahub_settings.py:** +```bash +cp /mnt/user/data/flook-stacks/stacks/seafile/seahub_settings.py /mnt/user/appdata/seafile/ +``` + +5. **Deploy stack via Portainer** + +### Outline Migration (from VM 192.168.1.112) + +1. **Create directories on Flook:** +```bash +mkdir -p /mnt/user/appdata/outline/{postgres-data,redis} +``` + +2. **Export Postgres from VM:** +```bash +ssh rishi@192.168.1.112 +docker exec outline-postgres-1 pg_dump -U rishi outline > ~/outline_backup.sql +``` + +3. **Copy backup to Flook:** +```bash +scp rishi@192.168.1.112:~/outline_backup.sql /mnt/user/appdata/outline/ +``` + +4. **Deploy stack via Portainer** (this creates empty DB) + +5. **Stop outline container temporarily:** +```bash +docker stop outline +``` + +6. **Import data:** +```bash +docker exec -i outline-postgres psql -U rishi outline < /mnt/user/appdata/outline/outline_backup.sql +``` + +7. **Start outline:** +```bash +docker start outline +``` + +8. **Stop VM services after verification:** +```bash +ssh rishi@192.168.1.112 +cd ~/outline && docker compose down +``` + +## Repository + +``` +https://git.rishighan.com/root/flook-stacks.git +``` diff --git a/stacks/backup/docker-compose.yml b/stacks/backup/docker-compose.yml new file mode 100644 index 0000000..b6c51c6 --- /dev/null +++ b/stacks/backup/docker-compose.yml @@ -0,0 +1,20 @@ +services: + borgmatic: + image: ghcr.io/borgmatic-collective/borgmatic:latest + container_name: borgmatic + restart: unless-stopped + privileged: true + environment: + - PUID=99 + - PGID=100 + - TZ=America/New_York + - BORG_PASSPHRASE=${BORG_PASSPHRASE} + volumes: + - /mnt/user/appdata/borgmatic/config:/etc/borgmatic.d + - /mnt/user/appdata/borgmatic/borg_keys:/root/.config/borg + - /mnt/user/appdata/borgmatic/state:/root/.local/state/borgmatic + - /mnt/user/appdata/borgmatic/ssh_keys:/root/.ssh + - /mnt/disks/borg_backup/cache:/root/.cache/borg + - /mnt/disks/borg_backup/repo:/mnt/borg-repository + - /mnt/user:/mnt/user:ro + - /boot:/boot:ro diff --git a/stacks/backup/stack.env b/stacks/backup/stack.env new file mode 100644 index 0000000..59c771e --- /dev/null +++ b/stacks/backup/stack.env @@ -0,0 +1 @@ +BORG_PASSPHRASE=Titu@1588 diff --git a/stacks/documents/docker-compose.yml b/stacks/documents/docker-compose.yml new file mode 100644 index 0000000..013f95a --- /dev/null +++ b/stacks/documents/docker-compose.yml @@ -0,0 +1,78 @@ +services: + paperless: + image: ghcr.io/paperless-ngx/paperless-ngx:latest + container_name: paperless + restart: unless-stopped + depends_on: + - paperless-db + - paperless-redis + - paperless-tika + - paperless-gotenberg + ports: + - 8777:8000 + environment: + - USERMAP_UID=99 + - USERMAP_GID=100 + - PAPERLESS_REDIS=redis://paperless-redis:6379 + - PAPERLESS_DBHOST=paperless-db + - PAPERLESS_TIKA_ENABLED=1 + - PAPERLESS_TIKA_GOTENBERG_ENDPOINT=http://paperless-gotenberg:3000 + - PAPERLESS_TIKA_ENDPOINT=http://paperless-tika:9998 + - PAPERLESS_SECRET_KEY=${PAPERLESS_SECRET_KEY} + - PAPERLESS_URL=https://paperless.rishighan.com + - PAPERLESS_TIME_ZONE=America/Chicago + - PAPERLESS_OCR_LANGUAGE=eng + - PAPERLESS_ADMIN_USER=${PAPERLESS_ADMIN_USER} + - PAPERLESS_ADMIN_PASSWORD=${PAPERLESS_ADMIN_PASSWORD} + volumes: + - /mnt/user/data/paperless/data:/usr/src/paperless/data + - /mnt/user/data/paperless/media:/usr/src/paperless/media + - /mnt/user/data/paperless/export:/usr/src/paperless/export + - /mnt/user/data/paperless/consume:/usr/src/paperless/consume + + paperless-db: + image: postgres:16 + container_name: paperless-db + restart: unless-stopped + environment: + - POSTGRES_DB=paperless + - POSTGRES_USER=paperless + - POSTGRES_PASSWORD=${PAPERLESS_DB_PASSWORD} + volumes: + - /mnt/user/data/paperless/pgdata:/var/lib/postgresql/data + + paperless-redis: + image: redis:7 + container_name: paperless-redis + restart: unless-stopped + volumes: + - /mnt/user/data/paperless/redis:/data + + paperless-tika: + image: apache/tika:latest + container_name: paperless-tika + restart: unless-stopped + + paperless-gotenberg: + image: gotenberg/gotenberg:8 + container_name: paperless-gotenberg + restart: unless-stopped + command: + - "gotenberg" + - "--chromium-disable-javascript=true" + - "--chromium-allow-list=file:///tmp/.*" + + onlyoffice: + image: onlyoffice/documentserver:latest + container_name: onlyoffice + restart: unless-stopped + ports: + - 8089:80 + - 4430:443 + environment: + - TZ=America/Los_Angeles + - JWT_SECRET=${ONLYOFFICE_JWT_SECRET} + volumes: + - /mnt/user/appdata/onlyofficeds/Data:/var/www/onlyoffice/Data + - /mnt/user/appdata/onlyofficeds/logs:/var/log/onlyoffice + - /mnt/user/appdata/onlyofficeds/fonts:/usr/share/fonts diff --git a/stacks/documents/stack.env b/stacks/documents/stack.env new file mode 100644 index 0000000..fcf8b93 --- /dev/null +++ b/stacks/documents/stack.env @@ -0,0 +1,5 @@ +PAPERLESS_SECRET_KEY=FD8w8IuzpQkOsrwMyHz35e5qH4ujRJ5fGQWKghAGQIQ= +PAPERLESS_ADMIN_USER=frishi +PAPERLESS_ADMIN_PASSWORD=Titu@1588 +PAPERLESS_DB_PASSWORD=paperless +ONLYOFFICE_JWT_SECRET=secret123 diff --git a/stacks/outline/README.md b/stacks/outline/README.md new file mode 100644 index 0000000..8e535a3 --- /dev/null +++ b/stacks/outline/README.md @@ -0,0 +1,68 @@ +# Outline Stack + +Outline Wiki with Postgres and Redis. + +## Services + +| Service | Port | Description | +|---------|------|-------------| +| outline | 3000:3000 | Wiki application | +| outline-postgres | - | PostgreSQL database | +| outline-redis | - | Redis cache | + +## Configuration Files + +Copy `redis.conf` to `/mnt/user/appdata/outline/` before deploying. + +## Dependencies + +- S3 bucket for uploads: `outline-wiki-data-bucket` +- Slack app for authentication: https://api.slack.com/apps/A041B5BSXD2 + +## NGINX Proxy Manager + +Create HTTPS proxy for `wiki.rishighan.com` pointing to `192.168.1.75:3000` + +## Migration from VM + +1. Create directories: +```bash +mkdir -p /mnt/user/appdata/outline/{postgres-data,redis} +cp redis.conf /mnt/user/appdata/outline/ +``` + +2. Export Postgres from VM: +```bash +ssh rishi@192.168.1.112 +docker exec outline-postgres-1 pg_dump -U rishi outline > ~/outline_backup.sql +``` + +3. Copy backup to Flook: +```bash +scp rishi@192.168.1.112:~/outline_backup.sql /mnt/user/appdata/outline/ +``` + +4. Deploy stack via Portainer (creates empty DB) + +5. Stop outline temporarily: +```bash +docker stop outline +``` + +6. Import data: +```bash +docker exec -i outline-postgres psql -U rishi outline < /mnt/user/appdata/outline/outline_backup.sql +``` + +7. Start outline: +```bash +docker start outline +``` + +8. Update NPM proxy to point to 192.168.1.75:3000 + +9. Stop VM services after verification: +```bash +ssh rishi@192.168.1.112 +cd ~/outline && docker compose down +``` diff --git a/stacks/outline/docker-compose.yml b/stacks/outline/docker-compose.yml new file mode 100644 index 0000000..3b4be0a --- /dev/null +++ b/stacks/outline/docker-compose.yml @@ -0,0 +1,31 @@ +services: + outline: + image: outlinewiki/outline:latest + container_name: outline + restart: unless-stopped + command: sh -c "yarn db:migrate --env=production-ssl-disabled && yarn start --env=production-ssl-disabled" + ports: + - 3000:3000 + env_file: + - stack.env + depends_on: + - outline-redis + - outline-postgres + + outline-redis: + image: redis:latest + container_name: outline-redis + restart: unless-stopped + volumes: + - /mnt/user/appdata/outline/redis.conf:/redis.conf + - /mnt/user/appdata/outline/redis:/data + command: ["redis-server", "/redis.conf"] + + outline-postgres: + image: postgres:15 + container_name: outline-postgres + restart: unless-stopped + env_file: + - stack.env + volumes: + - /mnt/user/appdata/outline/postgres-data:/var/lib/postgresql/data diff --git a/stacks/outline/redis.conf b/stacks/outline/redis.conf new file mode 100644 index 0000000..4a14201 --- /dev/null +++ b/stacks/outline/redis.conf @@ -0,0 +1,2 @@ +bind 0.0.0.0 +port 6379 diff --git a/stacks/outline/stack.env b/stacks/outline/stack.env new file mode 100644 index 0000000..f6c6209 --- /dev/null +++ b/stacks/outline/stack.env @@ -0,0 +1,31 @@ +# –––––––––––––––– REQUIRED –––––––––––––––– +SECRET_KEY=ce86b161b3e7e8ce75136060afd462673363b1b0d027aff8a2bfc097b20bb39a +UTILS_SECRET=a9e89560aad956988f53949ab354dbff63bd5c75e08e560b2cbfcee71d2fae30 +POSTGRES_USER=rishi +POSTGRES_PASSWORD=dexter +POSTGRES_DB=outline +DATABASE_URL=postgres://rishi:dexter@outline-postgres:5432/outline +DATABASE_URL_TEST=postgres://rishi:dexter@outline-postgres:5432/outline-test +PGSSLMODE=disable +REDIS_URL=redis://outline-redis:6379 +URL=https://wiki.rishighan.com +PORT=3000 +AWS_ACCESS_KEY_ID=AKIAQP5UUFQPKWAILLJK +AWS_SECRET_ACCESS_KEY=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 +AWS_REGION=us-east-1 +AWS_S3_UPLOAD_BUCKET_URL=https://outline-wiki-data-bucket.s3.us-east-1.amazonaws.com +AWS_S3_UPLOAD_BUCKET_NAME=outline-wiki-data-bucket +AWS_S3_UPLOAD_MAX_SIZE=26214400 +AWS_S3_FORCE_PATH_STYLE=false + +# –––––––––––––– AUTHENTICATION –––––––––––––– +SLACK_KEY=11934097441.4045181915444 +SLACK_SECRET=740d1d0b375d7609cd1fa18de2b1e8d4 + +# –––––––––––––––– OPTIONAL –––––––––––––––– +SLACK_VERIFICATION_TOKEN=StwRrYvcGHCDME4a5x2jU9zq +SLACK_APP_ID=A041B5BSXD2 +SLACK_MESSAGE_ACTIONS=true +FORCE_HTTPS=false +ENABLE_UPDATES=true +WEB_CONCURRENCY=2 diff --git a/stacks/portainer/docker-compose.yml b/stacks/portainer/docker-compose.yml new file mode 100644 index 0000000..644aab2 --- /dev/null +++ b/stacks/portainer/docker-compose.yml @@ -0,0 +1,10 @@ +services: + portainer: + image: portainer/portainer-ce:latest + container_name: portainer + restart: unless-stopped + ports: + - 9000:9000 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /mnt/user/appdata/portainer:/data diff --git a/stacks/productivity/README.md b/stacks/productivity/README.md new file mode 100644 index 0000000..f1b1c7c --- /dev/null +++ b/stacks/productivity/README.md @@ -0,0 +1,63 @@ +# Productivity Stack + +GitLab, Vaultwarden, Memos, Mortis, and FreshRSS. + +## Services + +| Service | Port | Description | +|---------|------|-------------| +| gitlab | 8929:80, 2222:22 | Git repository | +| vaultwarden | 4743:80 | Password manager | +| memos | 5230:5230 | Note-taking | +| mortis | 5231:5231 | Memos iOS companion | +| freshrss | 8054:80 | RSS reader | + +## GitLab + +### Initial Setup + +GitLab runs migrations on first start - takes 15-20 minutes. Be patient. + +### Get Root Password + +```bash +docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password +``` + +### NGINX Proxy Manager + +Create HTTPS proxy for `git.rishighan.com` pointing to `192.168.1.75:8929` + +GitLab recommends SSL, so use HTTPS. + +## Vaultwarden + +### NGINX Proxy Manager + +Create HTTPS proxy for `vault.rishighan.com` pointing to `192.168.1.75:4743` + +### Admin Panel + +Access at `https://vault.rishighan.com/admin` with the `ADMIN_TOKEN` from stack.env + +## Memos + Mortis + +Mortis is the iOS companion for Memos. It connects via gRPC to memos:5230. + +### NGINX Proxy Manager + +Create HTTPS proxy for `memos.rishighan.com` pointing to `192.168.1.75:5230` + +## FreshRSS + +### NGINX Proxy Manager + +Create HTTPS proxy for `rss.rishighan.com` pointing to `192.168.1.75:8054` + +### Import Feeds + +1. Copy `feeds.opml` to `/mnt/user/appdata/freshrss/` +2. In FreshRSS: Settings → Import/Export → Import OPML +3. Enable `af_readability` extension to bypass paywalls + +The OPML contains curated feeds for Gaming, Tech, Politics, Weather, and World News - free from paywalled bullshit. diff --git a/stacks/productivity/docker-compose.yml b/stacks/productivity/docker-compose.yml new file mode 100644 index 0000000..524283b --- /dev/null +++ b/stacks/productivity/docker-compose.yml @@ -0,0 +1,80 @@ +services: + gitlab: + image: gitlab/gitlab-ce:latest + container_name: gitlab + restart: unless-stopped + hostname: git.rishighan.com + environment: + GITLAB_OMNIBUS_CONFIG: | + external_url 'https://git.rishighan.com' + nginx['listen_port'] = 80 + nginx['listen_https'] = false + gitlab_rails['time_zone'] = 'America/Chicago' + ports: + - 8929:80 + - 2222:22 + volumes: + - /mnt/user/data/gitlab/config:/etc/gitlab + - /mnt/user/data/gitlab/logs:/var/log/gitlab + - /mnt/user/data/gitlab/data:/var/opt/gitlab + shm_size: '256m' + + vaultwarden: + image: vaultwarden/server:latest + container_name: vaultwarden + restart: unless-stopped + ports: + - 4743:80 + environment: + - TZ=America/Los_Angeles + - SIGNUPS_ALLOWED=true + - INVITATIONS_ALLOWED=true + - WEBSOCKET_ENABLED=false + - ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN} + volumes: + - /mnt/user/appdata/vaultwarden:/data + + memos: + image: neosmemo/memos:stable + container_name: memos + restart: unless-stopped + ports: + - 5230:5230 + environment: + - TZ=UTC + - MEMOS_MODE=prod + - MEMOS_PORT=5230 + volumes: + - /mnt/user/appdata/memos:/var/opt/memos + healthcheck: + test: wget --quiet --tries=1 --spider http://localhost:5230 || exit 1 + start_period: 1m + start_interval: 10s + interval: 1m + timeout: 5s + retries: 3 + + mortis: + image: ghcr.io/mudkipme/mortis:0.25.2 + container_name: mortis + restart: unless-stopped + ports: + - 5231:5231 + command: ["-grpc-addr=memos:5230"] + depends_on: + - memos + + freshrss: + image: lscr.io/linuxserver/freshrss:latest + container_name: freshrss + restart: unless-stopped + environment: + - PUID=99 + - PGID=100 + - UMASK=022 + - TZ=America/Los_Angeles + - CRON_MIN=*/30 + ports: + - 8054:80 + volumes: + - /mnt/user/appdata/freshrss:/config diff --git a/stacks/productivity/feeds.opml b/stacks/productivity/feeds.opml new file mode 100644 index 0000000..2867a54 --- /dev/null +++ b/stacks/productivity/feeds.opml @@ -0,0 +1,31 @@ + + + + Rishi's Feeds + 2024 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stacks/productivity/stack.env b/stacks/productivity/stack.env new file mode 100644 index 0000000..5f28b46 --- /dev/null +++ b/stacks/productivity/stack.env @@ -0,0 +1 @@ +VAULTWARDEN_ADMIN_TOKEN=emNPS8DJtzKaLDG3i+braZik2xuPYWHIZeyfoI6dRmP++0JyE7NtC3L5dv0w2yM4 diff --git a/stacks/proxy/docker-compose.yml b/stacks/proxy/docker-compose.yml new file mode 100644 index 0000000..78e1eea --- /dev/null +++ b/stacks/proxy/docker-compose.yml @@ -0,0 +1,15 @@ +services: + npm: + image: jc21/nginx-proxy-manager:latest + container_name: npm + restart: unless-stopped + environment: + - TZ=America/Los_Angeles + - DB_SQLITE_FILE=/data/database.sqlite + ports: + - 1880:80 + - 18443:443 + - 81:81 + volumes: + - /mnt/user/appdata/Nginx-Proxy-Manager-Official/data:/data + - /mnt/user/appdata/Nginx-Proxy-Manager-Official/letsencrypt:/etc/letsencrypt diff --git a/stacks/seafile/README.md b/stacks/seafile/README.md new file mode 100644 index 0000000..091bf44 --- /dev/null +++ b/stacks/seafile/README.md @@ -0,0 +1,107 @@ +# Seafile Stack + +Seafile 13 Pro with SeaDoc, SeaSearch, Notification Server, and Metadata Server. + +## Services + +| Service | Port | Description | +|---------|------|-------------| +| seafile | 8098:80 | Main Seafile server | +| seadoc | 8888:80 | Document collaboration | +| notification-server | 8083:8083 | Real-time notifications | +| seafile-md-server | 8084:8084 | Metadata server | +| seasearch | 4080:4080 | Full-text search | +| seafile-mysql | - | MariaDB database | +| seafile-redis | - | Redis cache | + +## Configuration Files + +Copy these to `/mnt/user/appdata/seafile/` before deploying: + +- `seahub_settings.py` - Seahub configuration +- `seafile.conf` - Seafile server configuration + +## NGINX Proxy Manager Setup + +### fileserver.rishighan.com + +Create HTTPS proxy with this Advanced config: + +```nginx +location / { + proxy_pass http://192.168.1.75:8098; + proxy_read_timeout 310s; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Connection "upgrade"; + client_max_body_size 0; +} + +rewrite ^/seafdav$ /seafdav/ permanent; + +location /sdoc-server/ { + proxy_pass http://192.168.1.75:8888/; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + client_max_body_size 100m; +} + +location /socket.io { + proxy_pass http://192.168.1.75:8888; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_redirect off; + proxy_buffers 8 32k; + proxy_buffer_size 64k; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_set_header X-NginX-Proxy true; +} +``` + +### notification.rishighan.com + +Create separate HTTPS proxy pointing to `192.168.1.75:8083` + +## Migration from VM + +1. Stop Seafile on VM: +```bash +ssh rishi@192.168.1.112 +cd /opt/seafile && docker compose down +``` + +2. Create directories: +```bash +mkdir -p /mnt/user/appdata/seafile/{data,db-data,seadoc-data,seasearch-data} +``` + +3. Copy data: +```bash +rsync -avP rishi@192.168.1.112:~/seafile/data/ /mnt/user/appdata/seafile/data/ +rsync -avP rishi@192.168.1.112:~/seafile/db-data/ /mnt/user/appdata/seafile/db-data/ +``` + +4. Copy config files: +```bash +cp seahub_settings.py /mnt/user/appdata/seafile/ +cp seafile.conf /mnt/user/appdata/seafile/ +``` + +5. Update NPM proxies to point to 192.168.1.75 instead of 192.168.1.112 + +6. Deploy stack via Portainer + +## Notes + +- Notifications only work for shared library events between users +- SeaDoc requires the `/sdoc-server/` and `/socket.io` proxy locations +- WebDAV is enabled on port 8080 at `/seafdav` diff --git a/stacks/seafile/docker-compose.yml b/stacks/seafile/docker-compose.yml new file mode 100644 index 0000000..317e735 --- /dev/null +++ b/stacks/seafile/docker-compose.yml @@ -0,0 +1,163 @@ +networks: + seafile-net: + name: seafile-net + driver: bridge + +services: + db: + image: mariadb:10.11 + container_name: seafile-mysql + restart: unless-stopped + environment: + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + - MYSQL_LOG_CONSOLE=true + - MARIADB_AUTO_UPGRADE=1 + volumes: + - /mnt/user/appdata/seafile/db-data:/var/lib/mysql + networks: + - seafile-net + healthcheck: + test: ["CMD", "sh", "-c", "mysqladmin ping -h localhost -u root -p$$MYSQL_ROOT_PASSWORD"] + interval: 20s + start_period: 30s + timeout: 5s + retries: 10 + + redis: + image: redis:latest + container_name: seafile-redis + restart: unless-stopped + networks: + - seafile-net + + seafile: + image: seafileltd/seafile-pro-mc:13.0.6-testing + container_name: seafile + restart: unless-stopped + ports: + - 8098:80 + environment: + - SEAFILE_MYSQL_DB_HOST=db + - SEAFILE_MYSQL_DB_PORT=3306 + - SEAFILE_MYSQL_DB_USER=seafile + - SEAFILE_MYSQL_DB_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD} + - SEAFILE_MYSQL_DB_CCNET_DB_NAME=ccnet_db + - SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=seafile_db + - SEAFILE_MYSQL_DB_SEAHUB_DB_NAME=seahub_db + - TIME_ZONE=Etc/UTC + - SEAFILE_SERVER_HOSTNAME=${SEAFILE_SERVER_HOSTNAME} + - SEAFILE_SERVER_PROTOCOL=https + - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY} + - ENABLE_SEADOC=true + - SEADOC_SERVER_URL=https://${SEAFILE_SERVER_HOSTNAME}/sdoc-server + - CACHE_PROVIDER=redis + - REDIS_HOST=redis + - REDIS_PORT=6379 + - INNER_NOTIFICATION_SERVER_URL=http://notification-server:8083 + - NOTIFICATION_SERVER_URL=${NOTIFICATION_SERVER_URL} + volumes: + - /mnt/user/appdata/seafile/data:/shared + - /mnt/user/appdata/seafile/seahub_settings.py:/shared/seafile/conf/seahub_settings.py + - /mnt/user/appdata/seafile/seafile.conf:/shared/seafile/conf/seafile.conf + depends_on: + db: + condition: service_healthy + redis: + condition: service_started + networks: + - seafile-net + + seadoc: + image: seafileltd/sdoc-server:2.0.3-testing + container_name: seadoc + restart: unless-stopped + ports: + - 8888:80 + environment: + - DB_HOST=db + - DB_PORT=3306 + - DB_USER=seafile + - DB_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD} + - DB_NAME=seahub_db + - TIME_ZONE=Etc/UTC + - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY} + - SEAHUB_SERVICE_URL=https://${SEAFILE_SERVER_HOSTNAME} + volumes: + - /mnt/user/appdata/seafile/seadoc-data:/shared + depends_on: + db: + condition: service_healthy + networks: + - seafile-net + + notification-server: + image: seafileltd/notification-server:13.0.0-testing + container_name: notification-server + restart: unless-stopped + ports: + - 8083:8083 + environment: + - SEAFILE_MYSQL_DB_HOST=db + - SEAFILE_MYSQL_DB_PORT=3306 + - SEAFILE_MYSQL_DB_USER=seafile + - SEAFILE_MYSQL_DB_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD} + - SEAFILE_MYSQL_DB_CCNET_DB_NAME=ccnet_db + - SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=seafile_db + - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY} + - SEAFILE_LOG_TO_STDOUT=true + volumes: + - /mnt/user/appdata/seafile/data/seafile/logs:/shared/seafile/logs + depends_on: + db: + condition: service_healthy + networks: + - seafile-net + + seafile-md-server: + image: seafileltd/seafile-md-server:13.0.6-testing + container_name: seafile-md-server + restart: unless-stopped + ports: + - 8084:8084 + environment: + - JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY} + - SEAFILE_MYSQL_DB_HOST=db + - SEAFILE_MYSQL_DB_PORT=3306 + - SEAFILE_MYSQL_DB_USER=seafile + - SEAFILE_MYSQL_DB_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD} + - SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=seafile_db + - MD_PORT=8084 + - MD_STORAGE_TYPE=s3 + - S3_MD_BUCKET=seafile-md + - S3_KEY_ID=${S3_KEY_ID} + - S3_SECRET_KEY=${S3_SECRET_KEY} + - S3_AWS_REGION=us-east-1 + - S3_HOST=s3.amazonaws.com + - S3_USE_HTTPS=true + - S3_USE_V4_SIGNATURE=true + - CACHE_PROVIDER=redis + - REDIS_HOST=redis + - REDIS_PORT=6379 + volumes: + - /mnt/user/appdata/seafile/data:/shared + depends_on: + db: + condition: service_healthy + networks: + - seafile-net + + seasearch: + image: seafileltd/seasearch:1.0.1-testing + container_name: seafile-seasearch + restart: unless-stopped + ports: + - 4080:4080 + environment: + - SS_MAX_OBJ_CACHE_SIZE=10GB + - SS_STORAGE_TYPE=disk + - SS_LOG_TO_STDOUT=true + - SS_LOG_LEVEL=info + volumes: + - /mnt/user/appdata/seafile/seasearch-data:/opt/seasearch/data + networks: + - seafile-net diff --git a/stacks/seafile/seafile.conf b/stacks/seafile/seafile.conf new file mode 100644 index 0000000..05ce757 --- /dev/null +++ b/stacks/seafile/seafile.conf @@ -0,0 +1,11 @@ +[metadata] +enabled = true +metadata_server_url = http://seafile-md-server:8084 + +[fileserver] +port=8082 + +[webdav] +enabled = true +port = 8080 +share_name = /seafdav diff --git a/stacks/seafile/seahub_settings.py b/stacks/seafile/seahub_settings.py new file mode 100644 index 0000000..1330d9a --- /dev/null +++ b/stacks/seafile/seahub_settings.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +SECRET_KEY = "4m!e0kb5yabjx50h@)wg^96wt$m^9d(=%zs_y%c@vwtn#vz6ob" +TIME_ZONE = 'America/Chicago' + +# Seafile URLs +FILE_SERVER_ROOT = 'https://fileserver.rishighan.com/seafhttp' +CSRF_TRUSTED_ORIGINS = ['https://fileserver.rishighan.com'] +SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') + +# SeaDoc +DOC_PREVIEW_SERVER = 'https://fileserver.rishighan.com/sdoc-server' + +# Notifications +NOTIFICATION_SERVER_URL = 'https://notification.rishighan.com' +ENABLE_NOTIFICATIONS = True + +# Metadata Server (Extended Properties) +ENABLE_METADATA_MANAGEMENT = True +METADATA_SERVER_URL = 'http://seafile-md-server:8084' + +# OnlyOffice +ENABLE_ONLYOFFICE = True +VERIFY_ONLYOFFICE_CERTIFICATE = True +ONLYOFFICE_APIJS_URL = 'https://office.rishighan.com/web-apps/apps/api/documents/api.js' +ONLYOFFICE_JWT_SECRET = 'secret123' +ONLYOFFICE_FILE_EXTENSION = ('doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'odt', 'fodt', 'odp', 'fodp', 'ods', 'fods', 'csv') +ONLYOFFICE_EDIT_FILE_EXTENSION = ('docx', 'pptx', 'xlsx') +ONLYOFFICE_FORCE_SAVE = True +OFFICE_PREVIEW_MAX_SIZE = 30 * 1024 * 1024 diff --git a/stacks/seafile/stack.env b/stacks/seafile/stack.env new file mode 100644 index 0000000..f837c68 --- /dev/null +++ b/stacks/seafile/stack.env @@ -0,0 +1,7 @@ +MYSQL_ROOT_PASSWORD=dexter +SEAFILE_MYSQL_DB_PASSWORD=dexter +SEAFILE_SERVER_HOSTNAME=fileserver.rishighan.com +JWT_PRIVATE_KEY=Qo4s8XissWnJx6gIORcggOaU69ObAa3W84jC05yv +NOTIFICATION_SERVER_URL=https://notification.rishighan.com +S3_KEY_ID=AKIAQP5UUFQPMDXWPW4O +S3_SECRET_KEY=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