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
|
||||
proxy:
|
||||
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