added backup script and backed up qnap
This commit is contained in:
0
QNAP/arr-stack/.env
Normal file
0
QNAP/arr-stack/.env
Normal file
230
QNAP/arr-stack/docker-compose.yml
Normal file
230
QNAP/arr-stack/docker-compose.yml
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
|
||||||
|
sabnzbd:
|
||||||
|
image: lscr.io/linuxserver/sabnzbd:latest
|
||||||
|
container_name: sabnzbd
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 8090:8080/tcp
|
||||||
|
environment:
|
||||||
|
- PGID=1000
|
||||||
|
- PUID=1000
|
||||||
|
- TZ=America/New_York
|
||||||
|
volumes:
|
||||||
|
- /share/Media/MovieDL:/downloads-movies
|
||||||
|
- /share/Media/TVDL:/downloads-tv
|
||||||
|
- /share/Media/TempDL:/incomplete-downloads
|
||||||
|
- /share/Media/container-station-data/arr/sabnzbd:/config
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.sabnzbd.rule: Host(`sabnzbd.kaspers.us`)
|
||||||
|
traefik.http.services.sabnzbd.loadbalancer.server.port: '8080'
|
||||||
|
traefik.http.routers.sabnzbd.entrypoints: 'websecure'
|
||||||
|
traefik.http.routers.sabnzbd.tls.certresolver: 'letsencrypt'
|
||||||
|
traefik.http.routers.sabnzbd.tls: 'true'
|
||||||
|
tautulli:
|
||||||
|
image: lscr.io/linuxserver/tautulli:latest
|
||||||
|
container_name: tautulli
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 8181:8181/tcp
|
||||||
|
environment:
|
||||||
|
- PGID=1000
|
||||||
|
- PUID=1000
|
||||||
|
- TZ=America/New_York
|
||||||
|
volumes:
|
||||||
|
- /share/Media/container-station-data/arr/tautulli:/config
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.tautulli.rule: Host(`tautulli.kaspers.us`)
|
||||||
|
traefik.http.services.tautulli.loadbalancer.server.port: '8181'
|
||||||
|
traefik.http.routers.tautulli.tls: 'true'
|
||||||
|
traefik.http.routers.tautulli.tls.certresolver: 'letsencrypt'
|
||||||
|
traefik.http.routers.tautulli.entrypoints: 'websecure'
|
||||||
|
radarr:
|
||||||
|
image: linuxserver/radarr:latest
|
||||||
|
container_name: radarr
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 7878:7878/tcp
|
||||||
|
environment:
|
||||||
|
- PGID=1000
|
||||||
|
- PUID=1000
|
||||||
|
- TZ=America/New_York
|
||||||
|
volumes:
|
||||||
|
- /share/Media/MovieDL:/downloads-movies
|
||||||
|
- /share/Media/Movies:/bignasty-movies
|
||||||
|
- /share/Media/container-station-data/arr/radarr:/config
|
||||||
|
- /share/Media1/Media/Movies:/media1-movies
|
||||||
|
- /share/Media2/volume1/Media/Movies:/media2-movies
|
||||||
|
- /share/Media3-Movies:/media3-movies
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.radarr.rule: Host(`radarr.kaspers.us`)
|
||||||
|
traefik.http.services.radarr.loadbalancer.server.port: '7878'
|
||||||
|
traefik.http.routers.radarr.tls: 'true'
|
||||||
|
traefik.http.routers.radarr.tls.certresolver: 'letsencrypt'
|
||||||
|
traefik.http.routers.radarr.entrypoints: 'websecure'
|
||||||
|
homepage:
|
||||||
|
image: ghcr.io/gethomepage/homepage:latest
|
||||||
|
container_name: homepage
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 3001:3000/tcp
|
||||||
|
environment:
|
||||||
|
- HOMEPAGE_ALLOWED_HOSTS=dashboard.kaspers.us
|
||||||
|
- HOSTNAME=0.0.0.0
|
||||||
|
- PORT=3000
|
||||||
|
volumes:
|
||||||
|
- /share/Media/container-station-data/arr/dashboard/config:/app/config
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.dashboard.rule: Host(`dashboard.kaspers.us`)
|
||||||
|
traefik.http.services.dashboard.loadbalancer.server.port: '3000'
|
||||||
|
traefik.http.routers.dashboard.tls: 'true'
|
||||||
|
traefik.http.routers.dashboard.tls.certresolver: 'letsencrypt'
|
||||||
|
traefik.http.routers.dashboard.entrypoints: 'websecure'
|
||||||
|
bazarr:
|
||||||
|
image: lscr.io/linuxserver/bazarr:latest
|
||||||
|
container_name: bazarr
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 6767:6767/tcp
|
||||||
|
environment:
|
||||||
|
- PGID=1000
|
||||||
|
- PUID=1000
|
||||||
|
- TZ=America/New_York
|
||||||
|
volumes:
|
||||||
|
- /share/Media/Movies:/bignasty-movies
|
||||||
|
- /share/Media/TV:/bignasty-tv
|
||||||
|
- /share/Media/container-station-data/arr/bazarr:/config
|
||||||
|
- /share/Media1/Media/Movies:/media1-movies
|
||||||
|
- /share/Media1/Media/TV:/media1-tv
|
||||||
|
- /share/Media2/volume1/Media/Movies:/media2-movies
|
||||||
|
- /share/Media2/volume1/Media/TV:/media2-tv
|
||||||
|
- /share/Media3-Movies:/media3-movies
|
||||||
|
- /share/Media3-TV:/media3-tv
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.bazarr.rule: Host(`bazarr.kaspers.us`)
|
||||||
|
traefik.http.services.bazarr.loadbalancer.server.port: '6767'
|
||||||
|
traefik.http.routers.bazarr.tls: 'true'
|
||||||
|
traefik.http.routers.bazarr.tls.certresolver: 'letsencrypt'
|
||||||
|
traefik.http.routers.bazarr.entrypoints: 'websecure'
|
||||||
|
qbittorrent:
|
||||||
|
image: linuxserver/qbittorrent:latest
|
||||||
|
container_name: qbittorrent
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 8081:8081/tcp
|
||||||
|
environment:
|
||||||
|
- PGID=1000
|
||||||
|
- PUID=1000
|
||||||
|
- TZ=America/New_York
|
||||||
|
- WEBUI_PORT=8081
|
||||||
|
volumes:
|
||||||
|
- /share/Media/TorrentDL:/config
|
||||||
|
- /share/Media/container-station-data/arr/qbittorrent:/media/downloads
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.qbittorrent.rule: Host(`torrent.kaspers.us`)
|
||||||
|
traefik.http.services.qbittorrent.loadbalancer.server.port: '8081'
|
||||||
|
traefik.http.routers.qbittorrent.tls: 'true'
|
||||||
|
traefik.http.routers.qbittorrent.tls.certresolver: 'letsencrypt'
|
||||||
|
traefik.http.routers.qbittorrent.entrypoints: 'websecure'
|
||||||
|
overseerr:
|
||||||
|
image: lscr.io/linuxserver/overseerr:latest
|
||||||
|
container_name: overseerr
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 5055:5055/tcp
|
||||||
|
environment:
|
||||||
|
- PGID=1000
|
||||||
|
- PUID=1000
|
||||||
|
- TZ=America/New_York
|
||||||
|
volumes:
|
||||||
|
- /share/Media/container-station-data/arr/overseerr:/config
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.overseerr.rule: Host(`requests.kaspers.us`)
|
||||||
|
traefik.http.services.overseerr.loadbalancer.server.port: '5055'
|
||||||
|
traefik.http.routers.overseerr.entrypoints: 'websecure'
|
||||||
|
traefik.http.routers.overseerr.tls.certresolver: 'letsencrypt'
|
||||||
|
traefik.http.routers.overseerr.tls: 'true'
|
||||||
|
traefik.constraint: 'proxy-public'
|
||||||
|
sonarr:
|
||||||
|
image: linuxserver/sonarr:latest
|
||||||
|
container_name: sonarr
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 8989:8989/tcp
|
||||||
|
environment:
|
||||||
|
- PGID=1000
|
||||||
|
- PUID=1000
|
||||||
|
- TZ=America/New_York
|
||||||
|
volumes:
|
||||||
|
- /share/Media/TV:/bignasty-tv
|
||||||
|
- /share/Media/TVDL:/downloads-tv
|
||||||
|
- /share/Media/container-station-data/arr/sonarr:/config
|
||||||
|
- /share/external/.nd/1000/064c2ded3-99f3-4dfd-a65d-32095f668e9b/volume1/Media/TV:/media2-tv
|
||||||
|
- /share/external/.nd/1000/0d23da6e0-8ad7-4fe8-b9d3-657e4d1e8848:/media3-tv
|
||||||
|
- /share/external/.nd/1000/0dde4f8ca-ff7d-4011-8f3b-ceb12fcd6dbb/Media/TV:/media1-tv
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.sonarr.rule: Host(`sonarr.kaspers.us`)
|
||||||
|
traefik.http.services.sonarr.loadbalancer.server.port: '8989'
|
||||||
|
traefik.http.routers.sonarr.tls: 'true'
|
||||||
|
traefik.http.routers.sonarr.tls.certresolver: 'letsencrypt'
|
||||||
|
traefik.http.routers.sonarr.entrypoints: 'websecure'
|
||||||
|
nzbhydra2:
|
||||||
|
image: lscr.io/linuxserver/nzbhydra2:latest
|
||||||
|
container_name: nzbhydra2
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 5076:5076/tcp
|
||||||
|
environment:
|
||||||
|
- PGID=1000
|
||||||
|
- PUID=1000
|
||||||
|
- TZ=America/New_York
|
||||||
|
volumes:
|
||||||
|
- /share/Media/container-station-data/arr/nzbhydra:/config
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.nzbhydra.rule: Host(`nzbhydra.kaspers.us`)
|
||||||
|
traefik.http.services.nzbhydra.loadbalancer.server.port: '5076'
|
||||||
|
traefik.http.routers.nzbhydra.tls: 'true'
|
||||||
|
traefik.http.routers.nzbhydra.tls.certresolver: 'letsencrypt'
|
||||||
|
traefik.http.routers.nzbhydra.entrypoints: 'websecure'
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
|
||||||
1
QNAP/arr-stack/environment-variables.json
Normal file
1
QNAP/arr-stack/environment-variables.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
8
QNAP/arr-stack/metadata.txt
Normal file
8
QNAP/arr-stack/metadata.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Stack Name: arr-stack
|
||||||
|
Stack ID: 2
|
||||||
|
Endpoint ID: 3
|
||||||
|
Creation Date: 1753361662
|
||||||
|
Update Date: 1754656702
|
||||||
|
Status: 1
|
||||||
|
Type: 2
|
||||||
|
Entry Point: docker-compose.yml
|
||||||
32
QNAP/arr-stack/stack-info.json
Normal file
32
QNAP/arr-stack/stack-info.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"Id": 2,
|
||||||
|
"Name": "arr-stack",
|
||||||
|
"Type": 2,
|
||||||
|
"EndpointId": 3,
|
||||||
|
"SwarmId": "",
|
||||||
|
"EntryPoint": "docker-compose.yml",
|
||||||
|
"Env": [],
|
||||||
|
"ResourceControl": {
|
||||||
|
"Id": 2,
|
||||||
|
"ResourceId": "3_arr-stack",
|
||||||
|
"SubResourceIds": [],
|
||||||
|
"Type": 6,
|
||||||
|
"UserAccesses": [],
|
||||||
|
"TeamAccesses": [],
|
||||||
|
"Public": false,
|
||||||
|
"AdministratorsOnly": true,
|
||||||
|
"System": false
|
||||||
|
},
|
||||||
|
"Status": 1,
|
||||||
|
"ProjectPath": "/data/compose/2",
|
||||||
|
"CreationDate": 1753361662,
|
||||||
|
"CreatedBy": "admin",
|
||||||
|
"UpdateDate": 1754656702,
|
||||||
|
"UpdatedBy": "admin",
|
||||||
|
"AdditionalFiles": null,
|
||||||
|
"AutoUpdate": null,
|
||||||
|
"Option": null,
|
||||||
|
"GitConfig": null,
|
||||||
|
"FromAppTemplate": false,
|
||||||
|
"Namespace": ""
|
||||||
|
}
|
||||||
0
QNAP/docuseal/.env
Normal file
0
QNAP/docuseal/.env
Normal file
@@ -56,3 +56,4 @@ networks:
|
|||||||
driver: bridge
|
driver: bridge
|
||||||
proxy:
|
proxy:
|
||||||
external: true
|
external: true
|
||||||
|
|
||||||
1
QNAP/docuseal/environment-variables.json
Normal file
1
QNAP/docuseal/environment-variables.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
8
QNAP/docuseal/metadata.txt
Normal file
8
QNAP/docuseal/metadata.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Stack Name: docuseal
|
||||||
|
Stack ID: 4
|
||||||
|
Endpoint ID: 3
|
||||||
|
Creation Date: 1753362392
|
||||||
|
Update Date: 1754657150
|
||||||
|
Status: 1
|
||||||
|
Type: 2
|
||||||
|
Entry Point: docker-compose.yml
|
||||||
32
QNAP/docuseal/stack-info.json
Normal file
32
QNAP/docuseal/stack-info.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"Id": 4,
|
||||||
|
"Name": "docuseal",
|
||||||
|
"Type": 2,
|
||||||
|
"EndpointId": 3,
|
||||||
|
"SwarmId": "",
|
||||||
|
"EntryPoint": "docker-compose.yml",
|
||||||
|
"Env": [],
|
||||||
|
"ResourceControl": {
|
||||||
|
"Id": 4,
|
||||||
|
"ResourceId": "3_docuseal",
|
||||||
|
"SubResourceIds": [],
|
||||||
|
"Type": 6,
|
||||||
|
"UserAccesses": [],
|
||||||
|
"TeamAccesses": [],
|
||||||
|
"Public": false,
|
||||||
|
"AdministratorsOnly": true,
|
||||||
|
"System": false
|
||||||
|
},
|
||||||
|
"Status": 1,
|
||||||
|
"ProjectPath": "/data/compose/4",
|
||||||
|
"CreationDate": 1753362392,
|
||||||
|
"CreatedBy": "admin",
|
||||||
|
"UpdateDate": 1754657150,
|
||||||
|
"UpdatedBy": "admin",
|
||||||
|
"AdditionalFiles": null,
|
||||||
|
"AutoUpdate": null,
|
||||||
|
"Option": null,
|
||||||
|
"GitConfig": null,
|
||||||
|
"FromAppTemplate": false,
|
||||||
|
"Namespace": ""
|
||||||
|
}
|
||||||
1
QNAP/gitea/.env
Normal file
1
QNAP/gitea/.env
Normal file
@@ -0,0 +1 @@
|
|||||||
|
GITEA_DB_PASSWORD=adt.cfv*ZQE6azm0qvk
|
||||||
51
QNAP/gitea/docker-compose.yml
Normal file
51
QNAP/gitea/docker-compose.yml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
services:
|
||||||
|
|
||||||
|
server:
|
||||||
|
image: gitea/gitea:1.23.7
|
||||||
|
container_name: gitea-server
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- TZ=America/New_York
|
||||||
|
- GITEA__database__DB_TYPE=postgres
|
||||||
|
- GITEA__database__HOST=db:5432
|
||||||
|
- GITEA__database__NAME=gitea
|
||||||
|
- GITEA__database__USER=gitea
|
||||||
|
- GITEA__database__PASSWD=${GITEA_DB_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- /share/Media/gitea/data:/data
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.gitea.rule=Host(`gitea.kaspers.us`)" # ⚠️ UPDATE to your domain
|
||||||
|
- "traefik.http.routers.gitea.entrypoints=websecure" # Assumes your HTTP entrypoint is 'web'
|
||||||
|
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
|
||||||
|
- "traefik.http.routers.gitea.tls=true"
|
||||||
|
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.docker.network=proxy"
|
||||||
|
- "traefik.constraint=proxy-public"
|
||||||
|
networks:
|
||||||
|
- gitea-net
|
||||||
|
- proxy
|
||||||
|
ports:
|
||||||
|
- 3105:3000
|
||||||
|
- 222:22
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:17.4
|
||||||
|
container_name: gitea-db
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- TZ=America/New_York
|
||||||
|
- POSTGRES_DB=gitea
|
||||||
|
- POSTGRES_USER=gitea
|
||||||
|
- POSTGRES_PASSWORD=${GITEA_DB_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- /share/Media/gitea/db:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- gitea-net
|
||||||
|
networks:
|
||||||
|
gitea-net:
|
||||||
|
driver: bridge
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
6
QNAP/gitea/environment-variables.json
Normal file
6
QNAP/gitea/environment-variables.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "GITEA_DB_PASSWORD",
|
||||||
|
"value": "adt.cfv*ZQE6azm0qvk"
|
||||||
|
}
|
||||||
|
]
|
||||||
8
QNAP/gitea/metadata.txt
Normal file
8
QNAP/gitea/metadata.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Stack Name: gitea
|
||||||
|
Stack ID: 17
|
||||||
|
Endpoint ID: 3
|
||||||
|
Creation Date: 1755699243
|
||||||
|
Update Date: 0
|
||||||
|
Status: 1
|
||||||
|
Type: 2
|
||||||
|
Entry Point: docker-compose.yml
|
||||||
37
QNAP/gitea/stack-info.json
Normal file
37
QNAP/gitea/stack-info.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"Id": 17,
|
||||||
|
"Name": "gitea",
|
||||||
|
"Type": 2,
|
||||||
|
"EndpointId": 3,
|
||||||
|
"SwarmId": "",
|
||||||
|
"EntryPoint": "docker-compose.yml",
|
||||||
|
"Env": [
|
||||||
|
{
|
||||||
|
"name": "GITEA_DB_PASSWORD",
|
||||||
|
"value": "adt.cfv*ZQE6azm0qvk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ResourceControl": {
|
||||||
|
"Id": 11,
|
||||||
|
"ResourceId": "3_gitea",
|
||||||
|
"SubResourceIds": [],
|
||||||
|
"Type": 6,
|
||||||
|
"UserAccesses": [],
|
||||||
|
"TeamAccesses": [],
|
||||||
|
"Public": false,
|
||||||
|
"AdministratorsOnly": true,
|
||||||
|
"System": false
|
||||||
|
},
|
||||||
|
"Status": 1,
|
||||||
|
"ProjectPath": "/data/compose/17",
|
||||||
|
"CreationDate": 1755699243,
|
||||||
|
"CreatedBy": "admin",
|
||||||
|
"UpdateDate": 0,
|
||||||
|
"UpdatedBy": "",
|
||||||
|
"AdditionalFiles": null,
|
||||||
|
"AutoUpdate": null,
|
||||||
|
"Option": null,
|
||||||
|
"GitConfig": null,
|
||||||
|
"FromAppTemplate": false,
|
||||||
|
"Namespace": ""
|
||||||
|
}
|
||||||
11
QNAP/immich/.env
Normal file
11
QNAP/immich/.env
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
UPLOAD_LOCATION=/share/Media/Immich
|
||||||
|
DB_DATA_LOCATION=/share/Media/container-station-data/immich/db
|
||||||
|
IMMICH_VERSION=release
|
||||||
|
DB_PASSWORD=postgres
|
||||||
|
DB_USERNAME=postgres
|
||||||
|
DB_DATABASE_NAME=immich
|
||||||
|
TZ=America/New_York
|
||||||
|
OIDC_ENABLED=true
|
||||||
|
OIDC_ISSUER_URL=https://auth.kaspers.us/application/o/immich/
|
||||||
|
OIDC_CLIENT_ID=hbzo7e5qAqIi4eZorZS9bOSjjKz9aBuVVZVHjIlZ
|
||||||
|
OIDC_CLIENT_SECRET=3NuNbX6GHXNC2DmhgOewMJUjoP5xboKPD3BkpTV02W7r2AEHfpNzCUq8DHYi5soJsVoahnbOxFpY24MF3mAaqfGlfbh4doZRWCAG1dUEUCyPE9h1082wcr2EFUEojFFs
|
||||||
99
QNAP/immich/docker-compose.yml
Normal file
99
QNAP/immich/docker-compose.yml
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#
|
||||||
|
# WARNING: To install Immich, follow our guide: https://immich.app/docs/install/docker-compose
|
||||||
|
#
|
||||||
|
# Make sure to use the docker-compose.yml of the current release:
|
||||||
|
#
|
||||||
|
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
|
||||||
|
#
|
||||||
|
# The compose file on main may not be compatible with the latest release.
|
||||||
|
|
||||||
|
name: immich
|
||||||
|
services:
|
||||||
|
immich-server:
|
||||||
|
container_name: immich_server
|
||||||
|
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
|
||||||
|
# extends:
|
||||||
|
# file: hwaccel.transcoding.yml
|
||||||
|
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
|
||||||
|
volumes:
|
||||||
|
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
|
||||||
|
- ${UPLOAD_LOCATION}:/data
|
||||||
|
- /share/Media/container-station-data/owncloud/data/files/kasperj@gmail.com/files/:/owncloud-immich:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
ports:
|
||||||
|
- '2283:2283'
|
||||||
|
environment:
|
||||||
|
OIDC_ENABLED: true
|
||||||
|
OIDC_ISSUER_URL: https://auth.kaspers.us/application/o/immich/
|
||||||
|
OIDC_CLIENT_ID: hbzo7e5qAqIi4eZorZS9bOSjjKz9aBuVVZVHjIlZ
|
||||||
|
OIDC_CLIENT_SECRET: 3NuNbX6GHXNC2DmhgOewMJUjoP5xboKPD3BkpTV02W7r2AEHfpNzCUq8DHYi5soJsVoahnbOxFpY24MF3mAaqfGlfbh4doZRWCAG1dUEUCyPE9h1082wcr2EFUEojFFs
|
||||||
|
#OIDC_BUTTON_TEXT: 'Login with Authentik'
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.immich.rule: Host(`photos.kaspers.us`)
|
||||||
|
traefik.http.services.immich.loadbalancer.server.port: '2283'
|
||||||
|
traefik.http.routers.immich.tls: 'true'
|
||||||
|
traefik.constraint: proxy-public
|
||||||
|
traefik.http.routers.immich.entrypoints: 'websecure'
|
||||||
|
traefik.http.routers.immich.tls.certresolver: 'letsencrypt'
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- database
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
proxy: {}
|
||||||
|
immich-internal: {}
|
||||||
|
healthcheck:
|
||||||
|
disable: false
|
||||||
|
|
||||||
|
immich-machine-learning:
|
||||||
|
container_name: immich_machine_learning
|
||||||
|
# For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
|
||||||
|
# Example tag: ${IMMICH_VERSION:-release}-cuda
|
||||||
|
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
|
||||||
|
# extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
|
||||||
|
# file: hwaccel.ml.yml
|
||||||
|
# service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
|
||||||
|
volumes:
|
||||||
|
- model-cache:/cache
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
disable: false
|
||||||
|
networks:
|
||||||
|
immich-internal: {}
|
||||||
|
|
||||||
|
redis:
|
||||||
|
container_name: immich_redis
|
||||||
|
image: docker.io/valkey/valkey:8-bookworm@sha256:facc1d2c3462975c34e10fccb167bfa92b0e0dbd992fc282c29a61c3243afb11
|
||||||
|
healthcheck:
|
||||||
|
test: redis-cli ping || exit 1
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
immich-internal: {}
|
||||||
|
|
||||||
|
database:
|
||||||
|
container_name: immich_postgres
|
||||||
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||||
|
POSTGRES_USER: ${DB_USERNAME}
|
||||||
|
POSTGRES_DB: ${DB_DATABASE_NAME}
|
||||||
|
POSTGRES_INITDB_ARGS: '--data-checksums'
|
||||||
|
# Uncomment the DB_STORAGE_TYPE: 'HDD' var if your database isn't stored on SSDs
|
||||||
|
# DB_STORAGE_TYPE: 'HDD'
|
||||||
|
volumes:
|
||||||
|
# Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
|
||||||
|
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
||||||
|
shm_size: 128mb
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
immich-internal: {}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
model-cache:
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
immich-internal:
|
||||||
|
driver: bridge
|
||||||
46
QNAP/immich/environment-variables.json
Normal file
46
QNAP/immich/environment-variables.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "UPLOAD_LOCATION",
|
||||||
|
"value": "/share/Media/Immich"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DB_DATA_LOCATION",
|
||||||
|
"value": "/share/Media/container-station-data/immich/db"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "IMMICH_VERSION",
|
||||||
|
"value": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DB_PASSWORD",
|
||||||
|
"value": "postgres"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DB_USERNAME",
|
||||||
|
"value": "postgres"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DB_DATABASE_NAME",
|
||||||
|
"value": "immich"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TZ",
|
||||||
|
"value": "America/New_York"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OIDC_ENABLED",
|
||||||
|
"value": "true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OIDC_ISSUER_URL",
|
||||||
|
"value": "https://auth.kaspers.us/application/o/immich/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OIDC_CLIENT_ID",
|
||||||
|
"value": "hbzo7e5qAqIi4eZorZS9bOSjjKz9aBuVVZVHjIlZ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OIDC_CLIENT_SECRET",
|
||||||
|
"value": "3NuNbX6GHXNC2DmhgOewMJUjoP5xboKPD3BkpTV02W7r2AEHfpNzCUq8DHYi5soJsVoahnbOxFpY24MF3mAaqfGlfbh4doZRWCAG1dUEUCyPE9h1082wcr2EFUEojFFs"
|
||||||
|
}
|
||||||
|
]
|
||||||
8
QNAP/immich/metadata.txt
Normal file
8
QNAP/immich/metadata.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Stack Name: immich
|
||||||
|
Stack ID: 8
|
||||||
|
Endpoint ID: 3
|
||||||
|
Creation Date: 1754055150
|
||||||
|
Update Date: 1755274982
|
||||||
|
Status: 1
|
||||||
|
Type: 2
|
||||||
|
Entry Point: docker-compose.yml
|
||||||
77
QNAP/immich/stack-info.json
Normal file
77
QNAP/immich/stack-info.json
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"Id": 8,
|
||||||
|
"Name": "immich",
|
||||||
|
"Type": 2,
|
||||||
|
"EndpointId": 3,
|
||||||
|
"SwarmId": "",
|
||||||
|
"EntryPoint": "docker-compose.yml",
|
||||||
|
"Env": [
|
||||||
|
{
|
||||||
|
"name": "UPLOAD_LOCATION",
|
||||||
|
"value": "/share/Media/Immich"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DB_DATA_LOCATION",
|
||||||
|
"value": "/share/Media/container-station-data/immich/db"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "IMMICH_VERSION",
|
||||||
|
"value": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DB_PASSWORD",
|
||||||
|
"value": "postgres"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DB_USERNAME",
|
||||||
|
"value": "postgres"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DB_DATABASE_NAME",
|
||||||
|
"value": "immich"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TZ",
|
||||||
|
"value": "America/New_York"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OIDC_ENABLED",
|
||||||
|
"value": "true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OIDC_ISSUER_URL",
|
||||||
|
"value": "https://auth.kaspers.us/application/o/immich/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OIDC_CLIENT_ID",
|
||||||
|
"value": "hbzo7e5qAqIi4eZorZS9bOSjjKz9aBuVVZVHjIlZ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OIDC_CLIENT_SECRET",
|
||||||
|
"value": "3NuNbX6GHXNC2DmhgOewMJUjoP5xboKPD3BkpTV02W7r2AEHfpNzCUq8DHYi5soJsVoahnbOxFpY24MF3mAaqfGlfbh4doZRWCAG1dUEUCyPE9h1082wcr2EFUEojFFs"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ResourceControl": {
|
||||||
|
"Id": 7,
|
||||||
|
"ResourceId": "3_immich",
|
||||||
|
"SubResourceIds": [],
|
||||||
|
"Type": 6,
|
||||||
|
"UserAccesses": [],
|
||||||
|
"TeamAccesses": [],
|
||||||
|
"Public": false,
|
||||||
|
"AdministratorsOnly": true,
|
||||||
|
"System": false
|
||||||
|
},
|
||||||
|
"Status": 1,
|
||||||
|
"ProjectPath": "/data/compose/8",
|
||||||
|
"CreationDate": 1754055150,
|
||||||
|
"CreatedBy": "admin",
|
||||||
|
"UpdateDate": 1755274982,
|
||||||
|
"UpdatedBy": "admin",
|
||||||
|
"AdditionalFiles": null,
|
||||||
|
"AutoUpdate": null,
|
||||||
|
"Option": null,
|
||||||
|
"GitConfig": null,
|
||||||
|
"FromAppTemplate": false,
|
||||||
|
"Namespace": ""
|
||||||
|
}
|
||||||
0
QNAP/owncloud/.env
Normal file
0
QNAP/owncloud/.env
Normal file
59
QNAP/owncloud/docker-compose.yml
Normal file
59
QNAP/owncloud/docker-compose.yml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
owncloud:
|
||||||
|
image: owncloud/server:latest
|
||||||
|
container_name: owncloud
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- owncloud-net
|
||||||
|
- proxy # ⚠️ UPDATE this to your Traefik network name if different
|
||||||
|
depends_on:
|
||||||
|
- mariadb
|
||||||
|
volumes:
|
||||||
|
- /share/Media/container-station-data/owncloud/data:/mnt/data
|
||||||
|
environment:
|
||||||
|
- OWNCLOUD_DOMAIN=owncloud.kaspers.us # ⚠️ UPDATE to your domain
|
||||||
|
- OWNCLOUD_DB_TYPE=mysql
|
||||||
|
- OWNCLOUD_DB_HOST=mariadb
|
||||||
|
- OWNCLOUD_DB_NAME=ownclouddb
|
||||||
|
- OWNCLOUD_DB_USERNAME=oc_db_user
|
||||||
|
- OWNCLOUD_DB_PASSWORD=ybr7tey0pxn1CWA.wfd # ⚠️ SET a strong password
|
||||||
|
- OWNCLOUD_ADMIN_USERNAME=admin # ⚠️ UPDATE admin user (optional)
|
||||||
|
- OWNCLOUD_ADMIN_PASSWORD=johnwayne21 # ⚠️ SET a strong admin password
|
||||||
|
- TZ=America/New_York
|
||||||
|
- OWNCLOUD_MAX_UPLOAD=20G # sets upload_max_filesize & post_max_size
|
||||||
|
- OWNCLOUD_PHP_MEMORY_LIMIT=1G # optional; for big uploads/antivirus apps
|
||||||
|
- OWNCLOUD_MAX_INPUT_TIME=3600
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.owncloud.rule=Host(`owncloud.kaspers.us`)" # ⚠️ UPDATE to your domain
|
||||||
|
- "traefik.http.routers.owncloud.entrypoints=websecure" # Assumes your HTTP entrypoint is 'web'
|
||||||
|
- "traefik.http.services.owncloud.loadbalancer.server.port=8080"
|
||||||
|
- "traefik.docker.network=proxy" # ⚠️ UPDATE this to your Traefik network name if different
|
||||||
|
- "traefik.constraint=proxy-public"
|
||||||
|
- "traefik.http.routers.owncloud.tls=true"
|
||||||
|
- "traefik.http.routers.owncloud.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.owncloud.middlewares=openid-rewrite@docker"
|
||||||
|
- "traefik.http.middlewares.openid-rewrite.replacepathregex.regex=^/.well-known/openid-configuration$$"
|
||||||
|
- "traefik.http.middlewares.openid-rewrite.replacepathregex.replacement=/index.php/apps/openidconnect/config"
|
||||||
|
mariadb:
|
||||||
|
image: mariadb:10.6 # Using a specific version is more stable
|
||||||
|
container_name: owncloud_db
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- owncloud-net
|
||||||
|
volumes:
|
||||||
|
- /share/Media/container-station-data/owncloud/db:/var/lib/mysql
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=FrankAndBeans # ⚠️ SET a strong root password
|
||||||
|
- MYSQL_DATABASE=ownclouddb
|
||||||
|
- MYSQL_USER=oc_db_user
|
||||||
|
- MYSQL_PASSWORD=ybr7tey0pxn1CWA.wfd # ⚠️ MUST MATCH the password above
|
||||||
|
- TZ=America/New_York # ⚠️ UPDATE to your timezone
|
||||||
|
|
||||||
|
networks:
|
||||||
|
owncloud-net:
|
||||||
|
driver: bridge
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
1
QNAP/owncloud/environment-variables.json
Normal file
1
QNAP/owncloud/environment-variables.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
8
QNAP/owncloud/metadata.txt
Normal file
8
QNAP/owncloud/metadata.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Stack Name: owncloud
|
||||||
|
Stack ID: 1
|
||||||
|
Endpoint ID: 3
|
||||||
|
Creation Date: 1753294011
|
||||||
|
Update Date: 1755528476
|
||||||
|
Status: 1
|
||||||
|
Type: 2
|
||||||
|
Entry Point: docker-compose.yml
|
||||||
32
QNAP/owncloud/stack-info.json
Normal file
32
QNAP/owncloud/stack-info.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"Id": 1,
|
||||||
|
"Name": "owncloud",
|
||||||
|
"Type": 2,
|
||||||
|
"EndpointId": 3,
|
||||||
|
"SwarmId": "",
|
||||||
|
"EntryPoint": "docker-compose.yml",
|
||||||
|
"Env": [],
|
||||||
|
"ResourceControl": {
|
||||||
|
"Id": 1,
|
||||||
|
"ResourceId": "3_owncloud",
|
||||||
|
"SubResourceIds": [],
|
||||||
|
"Type": 6,
|
||||||
|
"UserAccesses": [],
|
||||||
|
"TeamAccesses": [],
|
||||||
|
"Public": false,
|
||||||
|
"AdministratorsOnly": true,
|
||||||
|
"System": false
|
||||||
|
},
|
||||||
|
"Status": 1,
|
||||||
|
"ProjectPath": "/data/compose/1",
|
||||||
|
"CreationDate": 1753294011,
|
||||||
|
"CreatedBy": "admin",
|
||||||
|
"UpdateDate": 1755528476,
|
||||||
|
"UpdatedBy": "admin",
|
||||||
|
"AdditionalFiles": null,
|
||||||
|
"AutoUpdate": null,
|
||||||
|
"Option": null,
|
||||||
|
"GitConfig": null,
|
||||||
|
"FromAppTemplate": false,
|
||||||
|
"Namespace": ""
|
||||||
|
}
|
||||||
5
QNAP/paperless/.env
Normal file
5
QNAP/paperless/.env
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
PAPERLESS_URL=https://paperless.kaspers.us
|
||||||
|
PAPERLESS_TIME_ZONE=America/New_York
|
||||||
|
PAPERLESS_OCR_LANGUAGE=eng
|
||||||
|
PAPERLESS_SECRET_KEY=1bU0TS6uOPiJhJxvC7xFrYSplRdsWtPtYXwEKRiB1rofwEYOrcSBeJZOhtNbd1Gs
|
||||||
|
COMPOSE_PROJECT_NAME=paperless
|
||||||
114
QNAP/paperless/docker-compose.yml
Normal file
114
QNAP/paperless/docker-compose.yml
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
# docker-compose file for running paperless from the docker container registry.
|
||||||
|
# This file contains everything paperless needs to run.
|
||||||
|
# Paperless supports amd64, arm and arm64 hardware.
|
||||||
|
#
|
||||||
|
# All compose files of paperless configure paperless in the following way:
|
||||||
|
#
|
||||||
|
# - Paperless is (re)started on system boot, if it was running before shutdown.
|
||||||
|
# - Docker volumes for storing data are managed by Docker.
|
||||||
|
# - Folders for importing and exporting files are created in the same directory
|
||||||
|
# as this file and mounted to the correct folders inside the container.
|
||||||
|
# - Paperless listens on port 8000.
|
||||||
|
#
|
||||||
|
# In addition to that, this docker-compose file adds the following optional
|
||||||
|
# configurations:
|
||||||
|
#
|
||||||
|
# - Instead of SQLite (default), PostgreSQL is used as the database server.
|
||||||
|
# - Apache Tika and Gotenberg servers are started with paperless and paperless
|
||||||
|
# is configured to use these services. These provide support for consuming
|
||||||
|
# Office documents (Word, Excel, Power Point and their LibreOffice counter-
|
||||||
|
# parts.
|
||||||
|
#
|
||||||
|
# To install and update paperless with this file, do the following:
|
||||||
|
#
|
||||||
|
# - Copy this file as 'docker-compose.yml' and the files 'docker-compose.env'
|
||||||
|
# and '.env' into a folder.
|
||||||
|
# - Run 'docker-compose pull'.
|
||||||
|
# - Run 'docker-compose run --rm webserver createsuperuser' to create a user.
|
||||||
|
# - Run 'docker-compose up -d'.
|
||||||
|
#
|
||||||
|
# For more extensive installation and update instructions, refer to the
|
||||||
|
# documentation.
|
||||||
|
|
||||||
|
version: "3.4"
|
||||||
|
services:
|
||||||
|
broker:
|
||||||
|
image: docker.io/library/redis:7
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /share/Media/container-station-data/paperless/redis:/data
|
||||||
|
networks:
|
||||||
|
paperless-internal: {}
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: docker.io/library/postgres:13
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /share/Media/container-station-data/paperless/database:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: paperless
|
||||||
|
POSTGRES_USER: paperless
|
||||||
|
POSTGRES_PASSWORD: paperless
|
||||||
|
networks:
|
||||||
|
paperless-internal: {}
|
||||||
|
|
||||||
|
webserver:
|
||||||
|
image: ghcr.io/paperless-ngx/paperless-ngx:2.17.1
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
- broker
|
||||||
|
- gotenberg
|
||||||
|
- tika
|
||||||
|
ports:
|
||||||
|
- "8888:8000"
|
||||||
|
networks:
|
||||||
|
proxy: {}
|
||||||
|
paperless-internal: {}
|
||||||
|
labels:
|
||||||
|
traefik.docker.network: proxy
|
||||||
|
traefik.enable: 'true'
|
||||||
|
traefik.http.routers.paperless.rule: Host(`paperless.kaspers.us`)
|
||||||
|
traefik.http.services.paperless.loadbalancer.server.port: '8000'
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 5
|
||||||
|
volumes:
|
||||||
|
- /share/Media/container-station-data/paperless/data:/usr/src/paperless/data
|
||||||
|
- /share/Media/container-station-data/paperless/media:/usr/src/paperless/media
|
||||||
|
- /share/Media/container-station-data/paperless/export:/usr/src/paperless/export
|
||||||
|
- /share/Media/container-station-data/paperless/consume:/usr/src/paperless/consume
|
||||||
|
environment:
|
||||||
|
PAPERLESS_REDIS: redis://broker:6379
|
||||||
|
PAPERLESS_DBHOST: db
|
||||||
|
PAPERLESS_TIKA_ENABLED: 1
|
||||||
|
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
|
||||||
|
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
|
||||||
|
PAPERLESS_URL: https://paperless.kaspers.us
|
||||||
|
|
||||||
|
gotenberg:
|
||||||
|
image: docker.io/gotenberg/gotenberg:7.8
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# The gotenberg chromium route is used to convert .eml files. We do not
|
||||||
|
# want to allow external content like tracking pixels or even javascript.
|
||||||
|
command:
|
||||||
|
- "gotenberg"
|
||||||
|
- "--chromium-disable-javascript=true"
|
||||||
|
- "--chromium-allow-list=file:///tmp/.*"
|
||||||
|
networks:
|
||||||
|
paperless-internal: {}
|
||||||
|
|
||||||
|
tika:
|
||||||
|
image: ghcr.io/paperless-ngx/tika:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
paperless-internal: {}
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
paperless-internal:
|
||||||
|
driver: bridge
|
||||||
22
QNAP/paperless/environment-variables.json
Normal file
22
QNAP/paperless/environment-variables.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "PAPERLESS_URL",
|
||||||
|
"value": "https://paperless.kaspers.us"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PAPERLESS_TIME_ZONE",
|
||||||
|
"value": "America/New_York"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PAPERLESS_OCR_LANGUAGE",
|
||||||
|
"value": "eng"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PAPERLESS_SECRET_KEY",
|
||||||
|
"value": "1bU0TS6uOPiJhJxvC7xFrYSplRdsWtPtYXwEKRiB1rofwEYOrcSBeJZOhtNbd1Gs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "COMPOSE_PROJECT_NAME",
|
||||||
|
"value": "paperless"
|
||||||
|
}
|
||||||
|
]
|
||||||
8
QNAP/paperless/metadata.txt
Normal file
8
QNAP/paperless/metadata.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Stack Name: paperless
|
||||||
|
Stack ID: 6
|
||||||
|
Endpoint ID: 3
|
||||||
|
Creation Date: 1753458813
|
||||||
|
Update Date: 1755524126
|
||||||
|
Status: 1
|
||||||
|
Type: 2
|
||||||
|
Entry Point: docker-compose.yml
|
||||||
53
QNAP/paperless/stack-info.json
Normal file
53
QNAP/paperless/stack-info.json
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"Id": 6,
|
||||||
|
"Name": "paperless",
|
||||||
|
"Type": 2,
|
||||||
|
"EndpointId": 3,
|
||||||
|
"SwarmId": "",
|
||||||
|
"EntryPoint": "docker-compose.yml",
|
||||||
|
"Env": [
|
||||||
|
{
|
||||||
|
"name": "PAPERLESS_URL",
|
||||||
|
"value": "https://paperless.kaspers.us"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PAPERLESS_TIME_ZONE",
|
||||||
|
"value": "America/New_York"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PAPERLESS_OCR_LANGUAGE",
|
||||||
|
"value": "eng"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PAPERLESS_SECRET_KEY",
|
||||||
|
"value": "1bU0TS6uOPiJhJxvC7xFrYSplRdsWtPtYXwEKRiB1rofwEYOrcSBeJZOhtNbd1Gs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "COMPOSE_PROJECT_NAME",
|
||||||
|
"value": "paperless"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ResourceControl": {
|
||||||
|
"Id": 6,
|
||||||
|
"ResourceId": "3_paperless",
|
||||||
|
"SubResourceIds": [],
|
||||||
|
"Type": 6,
|
||||||
|
"UserAccesses": [],
|
||||||
|
"TeamAccesses": [],
|
||||||
|
"Public": false,
|
||||||
|
"AdministratorsOnly": true,
|
||||||
|
"System": false
|
||||||
|
},
|
||||||
|
"Status": 1,
|
||||||
|
"ProjectPath": "/data/compose/6",
|
||||||
|
"CreationDate": 1753458813,
|
||||||
|
"CreatedBy": "admin",
|
||||||
|
"UpdateDate": 1755524126,
|
||||||
|
"UpdatedBy": "admin",
|
||||||
|
"AdditionalFiles": null,
|
||||||
|
"AutoUpdate": null,
|
||||||
|
"Option": null,
|
||||||
|
"GitConfig": null,
|
||||||
|
"FromAppTemplate": false,
|
||||||
|
"Namespace": ""
|
||||||
|
}
|
||||||
12
QNAP/traefik/.env
Normal file
12
QNAP/traefik/.env
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
ROOT_DOMAIN=kaspers.us
|
||||||
|
HTTP_TIMEOUT=60
|
||||||
|
POLLING_INTERVAL=10
|
||||||
|
PROPAGATION_TIMEOUT=3600
|
||||||
|
TTL=300
|
||||||
|
PROVIDERS_GOOGLE_CLIENT_ID=<GOOGLE CLIENT ID>
|
||||||
|
PROVIDERS_GOOGLE_CLIENT_SECRET=<GOOGLE CLIENT SECRET>
|
||||||
|
SECRET=RandomTextGoesHere
|
||||||
|
WHITELIST=<YOUR GOOGLE ACCOUNT EMAIL>
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
ZONE_ID=7e2d1b9d7e0f7a5056bfaea28f070ba3
|
||||||
|
TUNNEL_TOKEN=eyJhIjoiNmZkNGQyNGRhNDNiNTgyZDY3NjA4ZmZlZjU1NDljNGEiLCJ0IjoiOGI1MjBiYjUtNjA5My00YzE3LWE1YjEtZjhmYWNiMThkYjQ3IiwicyI6Ik9URTRNekZpWXpJdE1EVm1PUzAwTUROaUxXRTFNamt0WlRrMll6azVOVEV4TURJMyJ9
|
||||||
181
QNAP/traefik/docker-compose.yml
Normal file
181
QNAP/traefik/docker-compose.yml
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
reverse-proxy:
|
||||||
|
image: traefik:latest
|
||||||
|
command:
|
||||||
|
- "--log"
|
||||||
|
- "--log.level=debug"
|
||||||
|
- "--log.format=json"
|
||||||
|
- "--api.insecure=true"
|
||||||
|
- "--providers.docker"
|
||||||
|
- "--providers.docker.exposedbydefault=false"
|
||||||
|
- "--providers.file.directory=/config"
|
||||||
|
- "--providers.file.watch=true"
|
||||||
|
- "--serversTransport.insecureSkipVerify=true" # Allow self-signed certificates for target hosts - https://doc.traefik.io/traefik/routing/overview/#insecureskipverify
|
||||||
|
- "--metrics"
|
||||||
|
- "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0"
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||||
|
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
||||||
|
- "--entrypoints.websecure.address=:443"
|
||||||
|
- "--entrypoints.websecure.transport.respondingTimeouts.readTimeout=0s"
|
||||||
|
- "--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=0s"
|
||||||
|
- "--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=5m"
|
||||||
|
- "--entrypoints.websecure.http.tls=true"
|
||||||
|
- "--entrypoints.websecure.http.tls.certresolver=letsencrypt"
|
||||||
|
- "--entrypoints.webinternal.address=:82"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.email=kasperj@gmail.com"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/letsencrypt.json"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=300"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.resolvers=8.8.8.8:53"
|
||||||
|
|
||||||
|
environment:
|
||||||
|
- CLOUDFLARE_DNS_API_TOKEN=n-iAlyJaGKcJwUcbxiIYA6kmxTVPBF_ez-g0fglW
|
||||||
|
- CLOUDFLARE_API_KEY=n-iAlyJaGKcJwUcbxiIYA6kmxTVPBF_ez-g0fglW
|
||||||
|
- CLOUDFLARE_HTTP_TIMEOUT=${HTTP_TIMEOUT}
|
||||||
|
- CLOUDFLARE_POLLING_INTERVAL=${POLLING_INTERVAL}
|
||||||
|
- CLOUDFLARE_PROPAGATION_TIMEOUT=${PROPAGATION_TIMEOUT}
|
||||||
|
- CLOUDFLARE_TTL=${TTL}
|
||||||
|
deploy:
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.api.rule=Host(`traefik-api.kaspers.us`)
|
||||||
|
- traefik.http.routers.api.service=api@internal
|
||||||
|
- traefik.http.routers.api.entrypoints=websecure
|
||||||
|
- traefik.http.routers.api.tls=true
|
||||||
|
- traefik.http.services.api.loadbalancer.server.port=8080
|
||||||
|
- traefik.docker.network=proxy
|
||||||
|
- traefik.http.routers.api.tls.certresolver=letsencrypt
|
||||||
|
- traefik.http.routers.dashboard.rule=Host(`traefik.kaspers.us`)
|
||||||
|
- traefik.http.routers.dashboard.entrypoints=web
|
||||||
|
- traefik.http.routers.dashboard.service=api@internal
|
||||||
|
- traefik.http.routers.dashboard.tls=true
|
||||||
|
- traefik.http.routers.dashboard.tls.certresolver=myresolver
|
||||||
|
ports:
|
||||||
|
# HTTP
|
||||||
|
- target: 80
|
||||||
|
published: 80
|
||||||
|
# HTTPS
|
||||||
|
- target: 443
|
||||||
|
published: 443
|
||||||
|
# Web UI (enabled by --api.insecure=true)
|
||||||
|
- target: 8080
|
||||||
|
published: 8182
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
- internal
|
||||||
|
volumes:
|
||||||
|
# So that Traefik can listen to the Docker events
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- /share/Media/container-station-data/traefik/acme:/etc/traefik/acme/
|
||||||
|
- /share/Media/container-station-data/traefik/origcerts:/etc/traefik/certs/
|
||||||
|
- /share/Media/container-station-data/traefik:/config
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- /share/Media/container-station-data/traefik/cloudflare:/cloudflare
|
||||||
|
|
||||||
|
# traefik-forward-auth:
|
||||||
|
# image: thomseddon/traefik-forward-auth:2.1.0
|
||||||
|
# networks:
|
||||||
|
# - traefik
|
||||||
|
# environment:
|
||||||
|
# - PROVIDERS_GOOGLE_CLIENT_ID=${PROVIDERS_GOOGLE_CLIENT_ID}
|
||||||
|
# - PROVIDERS_GOOGLE_CLIENT_SECRET=${PROVIDERS_GOOGLE_CLIENT_SECRET}
|
||||||
|
# - SECRET=${SECRET}
|
||||||
|
# - AUTH_HOST=auth.${ROOT_DOMAIN}
|
||||||
|
# - COOKIE_DOMAIN=${ROOT_DOMAIN}
|
||||||
|
# - WHITELIST=${WHITELIST}
|
||||||
|
# deploy:
|
||||||
|
# labels:
|
||||||
|
# - traefik.enable=true
|
||||||
|
# - traefik.docker.network=traefik
|
||||||
|
#
|
||||||
|
# - traefik.http.routers.auth.rule=Host(`auth.${ROOT_DOMAIN}`)
|
||||||
|
# - traefik.http.routers.auth.entrypoints=websecure
|
||||||
|
# - traefik.http.routers.auth.tls=true
|
||||||
|
# - traefik.http.routers.auth.tls.domains[0].main=${ROOT_DOMAIN}
|
||||||
|
# - traefik.http.routers.auth.tls.domains[0].sans=*.${ROOT_DOMAIN}
|
||||||
|
# - traefik.http.routers.auth.tls.certresolver=letsencrypt
|
||||||
|
# - traefik.http.routers.auth.service=auth@docker
|
||||||
|
#
|
||||||
|
# - traefik.http.services.auth.loadbalancer.server.port=4181
|
||||||
|
#
|
||||||
|
# - traefik.http.middlewares.forward-auth.forwardauth.address=http://traefik-forward-auth:4181
|
||||||
|
# - traefik.http.middlewares.forward-auth.forwardauth.trustForwardHeader=true
|
||||||
|
# - traefik.http.middlewares.forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User
|
||||||
|
#
|
||||||
|
# - traefik.http.routers.auth.middlewares=forward-auth
|
||||||
|
#
|
||||||
|
# - traefik.constraint=proxy-public
|
||||||
|
|
||||||
|
tunnel:
|
||||||
|
container_name: cloudflared-tunnel
|
||||||
|
image: cloudflare/cloudflared
|
||||||
|
restart: unless-stopped
|
||||||
|
command: tunnel run
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
environment:
|
||||||
|
- TUNNEL_TOKEN=${TUNNEL_TOKEN}
|
||||||
|
|
||||||
|
error-pages:
|
||||||
|
image: tarampampam/error-pages:2.26.0
|
||||||
|
environment:
|
||||||
|
TEMPLATE_NAME: l7-dark
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
deploy:
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.docker.network=traefik
|
||||||
|
|
||||||
|
# use as "fallback" for any non-registered services (with priority below normal)
|
||||||
|
- traefik.http.routers.error-pages.rule=HostRegexp(`{host:.+}`)
|
||||||
|
- traefik.http.routers.error-pages.priority=10
|
||||||
|
|
||||||
|
# should say that all of your services work on https
|
||||||
|
- traefik.http.routers.error-pages.tls='true'
|
||||||
|
- traefik.http.routers.error-pages.entrypoints=websecure
|
||||||
|
- traefik.http.routers.error-pages.middlewares=error-pages
|
||||||
|
- traefik.http.services.error-pages.loadbalancer.server.port=8080
|
||||||
|
|
||||||
|
# "errors" middleware settings
|
||||||
|
- traefik.http.middlewares.error-pages.errors.status=400-599
|
||||||
|
- traefik.http.middlewares.error-pages.errors.service=error-pages
|
||||||
|
- traefik.http.middlewares.error-pages.errors.query=/{status}.html
|
||||||
|
|
||||||
|
cloudflare-companion:
|
||||||
|
image: ghcr.io/tiredofit/docker-traefik-cloudflare-companion:latest
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
environment:
|
||||||
|
- TIMEZONE=America/New_York
|
||||||
|
- LOG_TYPE=CONSOLE
|
||||||
|
- LOG_LEVEL=INFO
|
||||||
|
- TRAEFIK_VERSION=2
|
||||||
|
- RC_TYPE=CNAME
|
||||||
|
- TARGET_DOMAIN=8b520bb5-6093-4c17-a5b1-f8facb18db47.cfargotunnel.com
|
||||||
|
- DOMAIN1_TARGET_DOMAIN=8b520bb5-6093-4c17-a5b1-f8facb18db47.cfargotunnel.com
|
||||||
|
- REFRESH_ENTRIES=TRUE
|
||||||
|
- TRAEFIK_DEFAULT_RULE=FALSE
|
||||||
|
- TRAEFIK_ENABLE_LABEL_ONLY=TRUE
|
||||||
|
- DEFAULT_MODE=SKIP
|
||||||
|
- PURGE_ON_DELETE=TRUE
|
||||||
|
- ENABLE_TRAEFIK_POLL=TRUE
|
||||||
|
- TRAEFIK_POLL_URL=http://reverse-proxy:8080/
|
||||||
|
- TRAEFIK_FILTER_LABEL=traefik.constraint
|
||||||
|
- TRAEFIK_FILTER=proxy-public
|
||||||
|
- DOMAIN1=${ROOT_DOMAIN}
|
||||||
|
- DOMAIN1_ZONE_ID=${ZONE_ID}
|
||||||
|
- DOMAIN1_PROXIED=TRUE
|
||||||
|
- TRAEFIK_EXCLUDED_HOST1=.*
|
||||||
|
- CF_TOKEN=n-iAlyJaGKcJwUcbxiIYA6kmxTVPBF_ez-g0fglW
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
internal:
|
||||||
50
QNAP/traefik/environment-variables.json
Normal file
50
QNAP/traefik/environment-variables.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "ROOT_DOMAIN",
|
||||||
|
"value": "kaspers.us"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HTTP_TIMEOUT",
|
||||||
|
"value": "60"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "POLLING_INTERVAL",
|
||||||
|
"value": "10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PROPAGATION_TIMEOUT",
|
||||||
|
"value": "3600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TTL",
|
||||||
|
"value": "300"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PROVIDERS_GOOGLE_CLIENT_ID",
|
||||||
|
"value": "<GOOGLE CLIENT ID>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PROVIDERS_GOOGLE_CLIENT_SECRET",
|
||||||
|
"value": "<GOOGLE CLIENT SECRET>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SECRET",
|
||||||
|
"value": "RandomTextGoesHere"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "WHITELIST",
|
||||||
|
"value": "<YOUR GOOGLE ACCOUNT EMAIL>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LOG_LEVEL",
|
||||||
|
"value": "INFO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZONE_ID",
|
||||||
|
"value": "7e2d1b9d7e0f7a5056bfaea28f070ba3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TUNNEL_TOKEN",
|
||||||
|
"value": "eyJhIjoiNmZkNGQyNGRhNDNiNTgyZDY3NjA4ZmZlZjU1NDljNGEiLCJ0IjoiOGI1MjBiYjUtNjA5My00YzE3LWE1YjEtZjhmYWNiMThkYjQ3IiwicyI6Ik9URTRNekZpWXpJdE1EVm1PUzAwTUROaUxXRTFNamt0WlRrMll6azVOVEV4TURJMyJ9"
|
||||||
|
}
|
||||||
|
]
|
||||||
8
QNAP/traefik/metadata.txt
Normal file
8
QNAP/traefik/metadata.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Stack Name: traefik
|
||||||
|
Stack ID: 13
|
||||||
|
Endpoint ID: 3
|
||||||
|
Creation Date: 1754418005
|
||||||
|
Update Date: 1755528537
|
||||||
|
Status: 1
|
||||||
|
Type: 2
|
||||||
|
Entry Point: docker-compose.yml
|
||||||
81
QNAP/traefik/stack-info.json
Normal file
81
QNAP/traefik/stack-info.json
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
{
|
||||||
|
"Id": 13,
|
||||||
|
"Name": "traefik",
|
||||||
|
"Type": 2,
|
||||||
|
"EndpointId": 3,
|
||||||
|
"SwarmId": "",
|
||||||
|
"EntryPoint": "docker-compose.yml",
|
||||||
|
"Env": [
|
||||||
|
{
|
||||||
|
"name": "ROOT_DOMAIN",
|
||||||
|
"value": "kaspers.us"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HTTP_TIMEOUT",
|
||||||
|
"value": "60"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "POLLING_INTERVAL",
|
||||||
|
"value": "10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PROPAGATION_TIMEOUT",
|
||||||
|
"value": "3600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TTL",
|
||||||
|
"value": "300"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PROVIDERS_GOOGLE_CLIENT_ID",
|
||||||
|
"value": "<GOOGLE CLIENT ID>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PROVIDERS_GOOGLE_CLIENT_SECRET",
|
||||||
|
"value": "<GOOGLE CLIENT SECRET>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SECRET",
|
||||||
|
"value": "RandomTextGoesHere"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "WHITELIST",
|
||||||
|
"value": "<YOUR GOOGLE ACCOUNT EMAIL>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LOG_LEVEL",
|
||||||
|
"value": "INFO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ZONE_ID",
|
||||||
|
"value": "7e2d1b9d7e0f7a5056bfaea28f070ba3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TUNNEL_TOKEN",
|
||||||
|
"value": "eyJhIjoiNmZkNGQyNGRhNDNiNTgyZDY3NjA4ZmZlZjU1NDljNGEiLCJ0IjoiOGI1MjBiYjUtNjA5My00YzE3LWE1YjEtZjhmYWNiMThkYjQ3IiwicyI6Ik9URTRNekZpWXpJdE1EVm1PUzAwTUROaUxXRTFNamt0WlRrMll6azVOVEV4TURJMyJ9"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ResourceControl": {
|
||||||
|
"Id": 8,
|
||||||
|
"ResourceId": "3_traefik",
|
||||||
|
"SubResourceIds": [],
|
||||||
|
"Type": 6,
|
||||||
|
"UserAccesses": [],
|
||||||
|
"TeamAccesses": [],
|
||||||
|
"Public": false,
|
||||||
|
"AdministratorsOnly": true,
|
||||||
|
"System": false
|
||||||
|
},
|
||||||
|
"Status": 1,
|
||||||
|
"ProjectPath": "/data/compose/13",
|
||||||
|
"CreationDate": 1754418005,
|
||||||
|
"CreatedBy": "admin",
|
||||||
|
"UpdateDate": 1755528537,
|
||||||
|
"UpdatedBy": "admin",
|
||||||
|
"AdditionalFiles": null,
|
||||||
|
"AutoUpdate": null,
|
||||||
|
"Option": null,
|
||||||
|
"GitConfig": null,
|
||||||
|
"FromAppTemplate": false,
|
||||||
|
"Namespace": ""
|
||||||
|
}
|
||||||
68
README-portainer-backup.md
Normal file
68
README-portainer-backup.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# Portainer Stack Backup Script
|
||||||
|
|
||||||
|
This script connects to a Portainer instance and exports all stacks with their configurations, environment variables, and docker-compose files.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- `curl` (usually pre-installed on macOS)
|
||||||
|
- `jq` for JSON processing: `brew install jq`
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Make sure the script is executable:
|
||||||
|
```bash
|
||||||
|
chmod +x portainer-backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Run the script:
|
||||||
|
```bash
|
||||||
|
./portainer-backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
3. When prompted, enter:
|
||||||
|
- Portainer URL (e.g., `http://localhost:9000`)
|
||||||
|
- Username
|
||||||
|
- Password
|
||||||
|
|
||||||
|
Alternatively, you can edit the script and set these variables at the top:
|
||||||
|
```bash
|
||||||
|
PORTAINER_URL="http://your-portainer-url:9000"
|
||||||
|
USERNAME="your-username"
|
||||||
|
PASSWORD="your-password"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
The script creates a `portainer-stacks-backup` directory containing:
|
||||||
|
|
||||||
|
```
|
||||||
|
portainer-stacks-backup/
|
||||||
|
├── stack-name-1/
|
||||||
|
│ ├── stack-info.json # Complete stack information
|
||||||
|
│ ├── environment-variables.json # Environment variables as JSON
|
||||||
|
│ ├── .env # Environment variables in .env format
|
||||||
|
│ ├── docker-compose.yml # Stack's compose file
|
||||||
|
│ └── metadata.txt # Human-readable metadata
|
||||||
|
├── stack-name-2/
|
||||||
|
│ └── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## What gets backed up
|
||||||
|
|
||||||
|
For each stack:
|
||||||
|
- Complete stack configuration (JSON format)
|
||||||
|
- Environment variables (both JSON and .env formats)
|
||||||
|
- Docker Compose file content
|
||||||
|
- Metadata (creation date, status, type, etc.)
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The script includes error handling for:
|
||||||
|
- Missing dependencies
|
||||||
|
- Authentication failures
|
||||||
|
- Network connectivity issues
|
||||||
|
- API errors
|
||||||
|
|
||||||
|
## Security Note
|
||||||
|
|
||||||
|
The script handles authentication via JWT tokens. Passwords are prompted securely (hidden input) if not set in the script.
|
||||||
232
portainer-backup.sh
Executable file
232
portainer-backup.sh
Executable file
@@ -0,0 +1,232 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Portainer Stack Backup Script
|
||||||
|
# This script connects to a Portainer instance and exports all stacks with their configurations
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration - Update these variables
|
||||||
|
PORTAINER_URL="http://192.168.11.12:9000" # Change this to your Portainer URL
|
||||||
|
USERNAME="admin" # Change this to your username
|
||||||
|
PASSWORD="JohnWayne#21" # Change this to your password or leave empty for prompt
|
||||||
|
OUTPUT_DIR="portainer-stacks-backup"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Function to print colored output
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if required tools are installed
|
||||||
|
check_dependencies() {
|
||||||
|
print_status "Checking dependencies..."
|
||||||
|
|
||||||
|
if ! command -v curl &> /dev/null; then
|
||||||
|
print_error "curl is required but not installed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v jq &> /dev/null; then
|
||||||
|
print_error "jq is required but not installed. Please install it with: brew install jq"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "All dependencies are available."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to prompt for configuration if not set
|
||||||
|
get_config() {
|
||||||
|
if [ -z "$PORTAINER_URL" ]; then
|
||||||
|
read -p "Enter Portainer URL (e.g., http://localhost:9000): " PORTAINER_URL
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$USERNAME" ]; then
|
||||||
|
read -p "Enter Portainer username: " USERNAME
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$PASSWORD" ]; then
|
||||||
|
read -s -p "Enter Portainer password: " PASSWORD
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove trailing slash from URL if present
|
||||||
|
PORTAINER_URL=$(echo "$PORTAINER_URL" | sed 's/\/$//g')
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to authenticate with Portainer
|
||||||
|
authenticate() {
|
||||||
|
print_status "Authenticating with Portainer..."
|
||||||
|
|
||||||
|
AUTH_RESPONSE=$(curl -s -X POST \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\"}" \
|
||||||
|
"$PORTAINER_URL/api/auth")
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
print_error "Failed to connect to Portainer at $PORTAINER_URL"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
JWT_TOKEN=$(echo "$AUTH_RESPONSE" | jq -r '.jwt // empty')
|
||||||
|
|
||||||
|
if [ -z "$JWT_TOKEN" ] || [ "$JWT_TOKEN" = "null" ]; then
|
||||||
|
print_error "Authentication failed. Please check your credentials."
|
||||||
|
print_error "Response: $AUTH_RESPONSE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Authentication successful."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get all environments (endpoints)
|
||||||
|
get_environments() {
|
||||||
|
print_status "Getting environments..."
|
||||||
|
|
||||||
|
ENVIRONMENTS_RESPONSE=$(curl -s -X GET \
|
||||||
|
-H "Authorization: Bearer $JWT_TOKEN" \
|
||||||
|
"$PORTAINER_URL/api/endpoints")
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
print_error "Failed to get environments"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$ENVIRONMENTS_RESPONSE" | jq -r '.[].Id' 2>/dev/null || echo "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get all stacks
|
||||||
|
get_stacks() {
|
||||||
|
print_status "Getting list of stacks..." >&2
|
||||||
|
|
||||||
|
STACKS_RESPONSE=$(curl -s -X GET \
|
||||||
|
-H "Authorization: Bearer $JWT_TOKEN" \
|
||||||
|
"$PORTAINER_URL/api/stacks")
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
print_error "Failed to get stacks" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$STACKS_RESPONSE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get detailed stack information
|
||||||
|
get_stack_details() {
|
||||||
|
local stack_id=$1
|
||||||
|
local endpoint_id=$2
|
||||||
|
|
||||||
|
curl -s -X GET \
|
||||||
|
-H "Authorization: Bearer $JWT_TOKEN" \
|
||||||
|
"$PORTAINER_URL/api/stacks/$stack_id?endpointId=$endpoint_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get stack file content
|
||||||
|
get_stack_file() {
|
||||||
|
local stack_id=$1
|
||||||
|
|
||||||
|
curl -s -X GET \
|
||||||
|
-H "Authorization: Bearer $JWT_TOKEN" \
|
||||||
|
"$PORTAINER_URL/api/stacks/$stack_id/file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to save stack data
|
||||||
|
save_stack_data() {
|
||||||
|
local stack_info=$1
|
||||||
|
local stack_name=$(echo "$stack_info" | jq -r '.Name')
|
||||||
|
local stack_id=$(echo "$stack_info" | jq -r '.Id')
|
||||||
|
local endpoint_id=$(echo "$stack_info" | jq -r '.EndpointId')
|
||||||
|
|
||||||
|
print_status "Processing stack: $stack_name (ID: $stack_id)"
|
||||||
|
|
||||||
|
# Create directory for this stack
|
||||||
|
local stack_dir="$OUTPUT_DIR/$stack_name"
|
||||||
|
mkdir -p "$stack_dir"
|
||||||
|
|
||||||
|
# Save basic stack information
|
||||||
|
echo "$stack_info" | jq '.' > "$stack_dir/stack-info.json"
|
||||||
|
|
||||||
|
# Extract and save environment variables
|
||||||
|
echo "$stack_info" | jq '.Env // []' > "$stack_dir/environment-variables.json"
|
||||||
|
|
||||||
|
# Save environment variables in .env format
|
||||||
|
echo "$stack_info" | jq -r '.Env[]? | select(.name != null and .value != null) | "\(.name)=\(.value)"' > "$stack_dir/.env"
|
||||||
|
|
||||||
|
# Get and save stack file content (docker-compose.yml)
|
||||||
|
print_status "Getting stack file for: $stack_name"
|
||||||
|
STACK_FILE_RESPONSE=$(get_stack_file "$stack_id")
|
||||||
|
|
||||||
|
if [ $? -eq 0 ] && [ "$STACK_FILE_RESPONSE" != "null" ]; then
|
||||||
|
echo "$STACK_FILE_RESPONSE" | jq -r '.StackFileContent // empty' > "$stack_dir/docker-compose.yml"
|
||||||
|
else
|
||||||
|
print_warning "Could not retrieve stack file for: $stack_name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save additional metadata
|
||||||
|
cat > "$stack_dir/metadata.txt" << EOF
|
||||||
|
Stack Name: $stack_name
|
||||||
|
Stack ID: $stack_id
|
||||||
|
Endpoint ID: $endpoint_id
|
||||||
|
Creation Date: $(echo "$stack_info" | jq -r '.CreationDate // "N/A"')
|
||||||
|
Update Date: $(echo "$stack_info" | jq -r '.UpdateDate // "N/A"')
|
||||||
|
Status: $(echo "$stack_info" | jq -r '.Status // "N/A"')
|
||||||
|
Type: $(echo "$stack_info" | jq -r '.Type // "N/A"')
|
||||||
|
Entry Point: $(echo "$stack_info" | jq -r '.EntryPoint // "N/A"')
|
||||||
|
EOF
|
||||||
|
|
||||||
|
print_status "Stack $stack_name saved to $stack_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
main() {
|
||||||
|
print_status "Starting Portainer stack backup..."
|
||||||
|
|
||||||
|
check_dependencies
|
||||||
|
get_config
|
||||||
|
authenticate
|
||||||
|
|
||||||
|
# Create output directory
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
# Get all stacks
|
||||||
|
STACKS_JSON=$(get_stacks)
|
||||||
|
|
||||||
|
if [ -z "$STACKS_JSON" ] || [ "$STACKS_JSON" = "null" ]; then
|
||||||
|
print_warning "No stacks found or unable to retrieve stacks."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Count stacks
|
||||||
|
STACK_COUNT=$(echo "$STACKS_JSON" | jq '. | length')
|
||||||
|
print_status "Found $STACK_COUNT stack(s)"
|
||||||
|
|
||||||
|
if [ "$STACK_COUNT" -eq 0 ]; then
|
||||||
|
print_warning "No stacks to backup."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Process each stack
|
||||||
|
echo "$STACKS_JSON" | jq -c '.[]' | while read -r stack; do
|
||||||
|
save_stack_data "$stack"
|
||||||
|
echo "---"
|
||||||
|
done
|
||||||
|
|
||||||
|
print_status "Backup completed! All stacks saved to: $OUTPUT_DIR"
|
||||||
|
print_status "Summary:"
|
||||||
|
ls -la "$OUTPUT_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user