Compare commits
7 Commits
v0.1.2
...
copilot/sc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0052fa4ddc | ||
|
|
300d870a2b | ||
|
|
94b4906a6a | ||
|
|
10aee3b3b1 | ||
|
|
4803d2c856 | ||
|
|
d4c9516e00 | ||
|
|
a554d00fd3 |
@@ -11,12 +11,12 @@ log:
|
|||||||
|
|
||||||
theme: dark
|
theme: dark
|
||||||
|
|
||||||
jwt_secret: 4f263cdfa9929d007551fd5a5a6b552f7e17127cc4bb425b375a8532631d527b6b591a560a784552a33767699391973799e7472b679e7f94fcf4aca2ce5b2efc
|
jwt_secret: ${AUTHELIA_JWT_SECRET}
|
||||||
|
|
||||||
default_redirection_url: https://auth.kelinreij.duckdns.org
|
default_redirection_url: https://auth.${DOMAIN}
|
||||||
|
|
||||||
totp:
|
totp:
|
||||||
issuer: kelinreij.duckdns.org
|
issuer: ${DOMAIN}
|
||||||
period: 30
|
period: 30
|
||||||
skew: 1
|
skew: 1
|
||||||
|
|
||||||
@@ -36,34 +36,34 @@ access_control:
|
|||||||
|
|
||||||
rules:
|
rules:
|
||||||
# Bypass Authelia for Jellyfin (allow app access)
|
# Bypass Authelia for Jellyfin (allow app access)
|
||||||
- domain: jellyfin.kelinreij.duckdns.org
|
- domain: jellyfin.${DOMAIN}
|
||||||
policy: bypass
|
policy: bypass
|
||||||
|
|
||||||
# Bypass for Plex (allow app access)
|
# Bypass for Plex (allow app access)
|
||||||
- domain: plex.kelinreij.duckdns.org
|
- domain: plex.${DOMAIN}
|
||||||
policy: bypass
|
policy: bypass
|
||||||
|
|
||||||
# Bypass for Home Assistant (has its own auth)
|
# Bypass for Home Assistant (has its own auth)
|
||||||
- domain: ha.kelinreij.duckdns.org
|
- domain: ha.${DOMAIN}
|
||||||
policy: bypass
|
policy: bypass
|
||||||
|
|
||||||
# Protected: All other services require authentication
|
# Protected: All other services require authentication
|
||||||
- domain: "*.kelinreij.duckdns.org"
|
- domain: "*.${DOMAIN}"
|
||||||
policy: one_factor
|
policy: one_factor
|
||||||
|
|
||||||
# Two-factor for admin services (optional)
|
# Two-factor for admin services (optional)
|
||||||
# - domain:
|
# - domain:
|
||||||
# - "admin.kelinreij.duckdns.org"
|
# - "admin.${DOMAIN}"
|
||||||
# - "portainer.kelinreij.duckdns.org"
|
# - "portainer.${DOMAIN}"
|
||||||
# policy: two_factor
|
# policy: two_factor
|
||||||
|
|
||||||
session:
|
session:
|
||||||
name: authelia_session
|
name: authelia_session
|
||||||
secret: 3ba018547a24dfd49ae55f23b5b75377ec93f5957707e2a669b0a49966df745a5b062eee3f7356e0abae21452915bdd30a32f404ec0a2a7a957c93a2fa2a94c8
|
secret: ${AUTHELIA_SESSION_SECRET}
|
||||||
expiration: 24h # Session expires after 24 hours
|
expiration: 24h # Session expires after 24 hours
|
||||||
inactivity: 24h # Session expires after 24 hours of inactivity
|
inactivity: 24h # Session expires after 24 hours of inactivity
|
||||||
remember_me_duration: 1M
|
remember_me_duration: 1M
|
||||||
domain: kelinreij.duckdns.org
|
domain: ${DOMAIN}
|
||||||
|
|
||||||
regulation:
|
regulation:
|
||||||
max_retries: 3
|
max_retries: 3
|
||||||
@@ -71,7 +71,7 @@ regulation:
|
|||||||
ban_time: 5m
|
ban_time: 5m
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
encryption_key: dd23db430500eb630e469d5cf0f77dd597649bd4d1a90c02ad673286d8eb9aa8f55435655435d40033751003fc764a173944dbc3ad89d57330e185269792a4b7
|
encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
|
||||||
local:
|
local:
|
||||||
path: /config/db.sqlite3
|
path: /config/db.sqlite3
|
||||||
|
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
# Authelia Configuration
|
|
||||||
# Copy to /opt/stacks/authelia/configuration.yml
|
|
||||||
# IMPORTANT: Replace '${DOMAIN}' with your actual DuckDNS domain
|
|
||||||
|
|
||||||
server:
|
|
||||||
host: 0.0.0.0
|
|
||||||
port: 9091
|
|
||||||
|
|
||||||
log:
|
|
||||||
level: info
|
|
||||||
|
|
||||||
theme: dark
|
|
||||||
|
|
||||||
jwt_secret: ${AUTHELIA_JWT_SECRET}
|
|
||||||
|
|
||||||
default_redirection_url: https://auth.${DOMAIN}
|
|
||||||
|
|
||||||
totp:
|
|
||||||
issuer: ${DOMAIN}
|
|
||||||
period: 30
|
|
||||||
skew: 1
|
|
||||||
|
|
||||||
authentication_backend:
|
|
||||||
file:
|
|
||||||
path: /config/users_database.yml
|
|
||||||
password:
|
|
||||||
algorithm: argon2id
|
|
||||||
iterations: 1
|
|
||||||
key_length: 32
|
|
||||||
salt_length: 16
|
|
||||||
memory: 1024
|
|
||||||
parallelism: 8
|
|
||||||
|
|
||||||
access_control:
|
|
||||||
default_policy: deny
|
|
||||||
|
|
||||||
rules:
|
|
||||||
# Bypass Authelia for Jellyfin (allow app access)
|
|
||||||
- domain: jellyfin.${DOMAIN}
|
|
||||||
policy: bypass
|
|
||||||
|
|
||||||
# Bypass for Plex (allow app access)
|
|
||||||
- domain: plex.${DOMAIN}
|
|
||||||
policy: bypass
|
|
||||||
|
|
||||||
# Bypass for Home Assistant (has its own auth)
|
|
||||||
- domain: ha.${DOMAIN}
|
|
||||||
policy: bypass
|
|
||||||
|
|
||||||
# Bypass for development services (they have their own auth or setup)
|
|
||||||
- domain: pgadmin.${DOMAIN}
|
|
||||||
policy: bypass
|
|
||||||
- domain: gitlab.${DOMAIN}
|
|
||||||
policy: bypass
|
|
||||||
|
|
||||||
# Protected: All other services require authentication
|
|
||||||
- domain: "*.${DOMAIN}"
|
|
||||||
policy: one_factor
|
|
||||||
|
|
||||||
# Two-factor for admin services (optional)
|
|
||||||
# - domain:
|
|
||||||
# - "admin.${DOMAIN}"
|
|
||||||
# - "portainer.${DOMAIN}"
|
|
||||||
# policy: two_factor
|
|
||||||
|
|
||||||
session:
|
|
||||||
name: authelia_session
|
|
||||||
secret: ${AUTHELIA_SESSION_SECRET}
|
|
||||||
expiration: 24h # Session expires after 24 hours
|
|
||||||
inactivity: 24h # Session expires after 24 hours of inactivity
|
|
||||||
remember_me_duration: 1M
|
|
||||||
domain: ${DOMAIN}
|
|
||||||
|
|
||||||
regulation:
|
|
||||||
max_retries: 3
|
|
||||||
find_time: 2m
|
|
||||||
ban_time: 5m
|
|
||||||
|
|
||||||
storage:
|
|
||||||
encryption_key: ${AUTHELIA_STORAGE_ENCRYPTION_KEY}
|
|
||||||
local:
|
|
||||||
path: /data/db.sqlite3
|
|
||||||
|
|
||||||
notifier:
|
|
||||||
# File-based notifications (for development/testing)
|
|
||||||
filesystem:
|
|
||||||
filename: /data/notification.txt
|
|
||||||
Binary file not shown.
@@ -1,12 +0,0 @@
|
|||||||
###############################################################
|
|
||||||
# Users Database #
|
|
||||||
###############################################################
|
|
||||||
|
|
||||||
users:
|
|
||||||
admin:
|
|
||||||
displayname: "admin"
|
|
||||||
password: "generate-with-openssl-rand-hex-64"
|
|
||||||
email: admin@example.com
|
|
||||||
groups:
|
|
||||||
- admins
|
|
||||||
- users
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
###############################################################
|
|
||||||
# Users Database #
|
|
||||||
###############################################################
|
|
||||||
|
|
||||||
users:
|
|
||||||
${AUTHELIA_ADMIN_USER}:
|
|
||||||
displayname: "${AUTHELIA_ADMIN_USER}"
|
|
||||||
password: "${AUTHELIA_ADMIN_PASSWORD_HASH}"
|
|
||||||
email: ${AUTHELIA_ADMIN_EMAIL}
|
|
||||||
groups:
|
|
||||||
- admins
|
|
||||||
- users
|
|
||||||
@@ -1,19 +1,12 @@
|
|||||||
# yamllint disable rule:line-length
|
|
||||||
---
|
|
||||||
###############################################################
|
###############################################################
|
||||||
# Users Database #
|
# Users Database #
|
||||||
###############################################################
|
###############################################################
|
||||||
|
|
||||||
# This file can be used if you do not have an LDAP set up.
|
|
||||||
|
|
||||||
users:
|
users:
|
||||||
authelia:
|
${AUTHELIA_ADMIN_USER}:
|
||||||
disabled: false
|
displayname: "${AUTHELIA_ADMIN_USER}"
|
||||||
displayname: "Test User"
|
password: "${AUTHELIA_ADMIN_PASSWORD_HASH}"
|
||||||
password: "$argon2id$v=19$m=32768,t=1,p=8$eUhVT1dQa082YVk2VUhDMQ$E8QI4jHbUBt3EdsU1NFDu4Bq5jObKNx7nBKSn1EYQxk" # Password is 'authelia'
|
email: ${AUTHELIA_ADMIN_EMAIL}
|
||||||
email: authelia@authelia.com
|
|
||||||
groups:
|
groups:
|
||||||
- admins
|
- admins
|
||||||
- dev
|
- users
|
||||||
...
|
|
||||||
# yamllint enable rule:line-length
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ services:
|
|||||||
- PUID=1000
|
- PUID=1000
|
||||||
- PGID=1000
|
- PGID=1000
|
||||||
- TZ=America/New_York
|
- TZ=America/New_York
|
||||||
- SUBDOMAINS=yourdomain
|
- SUBDOMAINS=${DUCKDNS_SUBDOMAINS}
|
||||||
- TOKEN=your-duckdns-token
|
- TOKEN=${DUCKDNS_TOKEN}
|
||||||
volumes:
|
volumes:
|
||||||
- ./duckdns/config:/config
|
- ./duckdns/config:/config
|
||||||
networks:
|
networks:
|
||||||
@@ -29,7 +29,7 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: ['--configFile=/config/traefik.yml']
|
command: ['--configFile=/config/traefik.yml']
|
||||||
environment:
|
environment:
|
||||||
- DUCKDNS_TOKEN=your-duckdns-token
|
- DUCKDNS_TOKEN=${DUCKDNS_TOKEN}
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- 80:80
|
||||||
- 443:443
|
- 443:443
|
||||||
@@ -48,7 +48,7 @@ services:
|
|||||||
- 'homelab.category=core'
|
- 'homelab.category=core'
|
||||||
- 'homelab.description=Reverse proxy and SSL termination'
|
- 'homelab.description=Reverse proxy and SSL termination'
|
||||||
- 'traefik.enable=true'
|
- 'traefik.enable=true'
|
||||||
- 'traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.duckdns.org`)'
|
- 'traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)'
|
||||||
- 'traefik.http.routers.traefik.entrypoints=websecure'
|
- 'traefik.http.routers.traefik.entrypoints=websecure'
|
||||||
- 'traefik.http.routers.traefik.tls.certresolver=letsencrypt'
|
- 'traefik.http.routers.traefik.tls.certresolver=letsencrypt'
|
||||||
- 'traefik.http.routers.traefik.middlewares=authelia@docker'
|
- 'traefik.http.routers.traefik.middlewares=authelia@docker'
|
||||||
@@ -80,13 +80,13 @@ services:
|
|||||||
# If Traefik is on a remote server: these labels are NOT USED;
|
# If Traefik is on a remote server: these labels are NOT USED;
|
||||||
# configure external yml files in /traefik/dynamic folder instead.
|
# configure external yml files in /traefik/dynamic folder instead.
|
||||||
- 'traefik.enable=true'
|
- 'traefik.enable=true'
|
||||||
- 'traefik.http.routers.authelia.rule=Host(`auth.yourdomain.duckdns.org`)'
|
- 'traefik.http.routers.authelia.rule=Host(`auth.${DOMAIN}`)'
|
||||||
- 'traefik.http.routers.authelia.entrypoints=websecure'
|
- 'traefik.http.routers.authelia.entrypoints=websecure'
|
||||||
- 'traefik.http.routers.authelia.tls.certresolver=letsencrypt'
|
- 'traefik.http.routers.authelia.tls.certresolver=letsencrypt'
|
||||||
- 'traefik.http.routers.authelia.service=authelia'
|
- 'traefik.http.routers.authelia.service=authelia'
|
||||||
- 'traefik.http.services.authelia.loadbalancer.server.port=9091'
|
- 'traefik.http.services.authelia.loadbalancer.server.port=9091'
|
||||||
# Authelia forward auth middleware configuration
|
# Authelia forward auth middleware configuration
|
||||||
- 'traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.yourdomain.duckdns.org/'
|
- 'traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.${DOMAIN}/'
|
||||||
- 'traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=X-Secret'
|
- 'traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=X-Secret'
|
||||||
- 'traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true'
|
- 'traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true'
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ networks:
|
|||||||
|
|
||||||
x-dockge:
|
x-dockge:
|
||||||
urls:
|
urls:
|
||||||
- https://auth.yourdomain.duckdns.org
|
- https://auth.${DOMAIN}
|
||||||
- http://192.168.1.100:9091
|
- http://${SERVER_IP}:9091
|
||||||
- https://traefik.yourdomain.duckdns.org
|
- https://traefik.${DOMAIN}
|
||||||
- http://192.168.1.100:8080
|
- http://${SERVER_IP}:8080
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ http:
|
|||||||
routers:
|
routers:
|
||||||
# Individual Services
|
# Individual Services
|
||||||
homeassistant:
|
homeassistant:
|
||||||
rule: "Host(`hass.kelinreij.duckdns.org`)"
|
rule: "Host(`hass.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: homeassistant
|
service: homeassistant
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ http:
|
|||||||
routers:
|
routers:
|
||||||
# Remote Server Services (your-remote-server)
|
# Remote Server Services (your-remote-server)
|
||||||
dockge-your-remote-server:
|
dockge-your-remote-server:
|
||||||
rule: "Host(`dockge.your-remote-server.kelinreij.duckdns.org`)"
|
rule: "Host(`dockge.your-remote-server.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: dockge-your-remote-server
|
service: dockge-your-remote-server
|
||||||
@@ -12,7 +12,7 @@ http:
|
|||||||
- authelia@docker
|
- authelia@docker
|
||||||
|
|
||||||
dozzle-your-remote-server:
|
dozzle-your-remote-server:
|
||||||
rule: "Host(`dozzle.your-remote-server.kelinreij.duckdns.org`)"
|
rule: "Host(`dozzle.your-remote-server.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: dozzle-your-remote-server
|
service: dozzle-your-remote-server
|
||||||
@@ -22,7 +22,7 @@ http:
|
|||||||
- authelia@docker
|
- authelia@docker
|
||||||
|
|
||||||
glances-your-remote-server:
|
glances-your-remote-server:
|
||||||
rule: "Host(`glances.your-remote-server.kelinreij.duckdns.org`)"
|
rule: "Host(`glances.your-remote-server.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: glances-your-remote-server
|
service: glances-your-remote-server
|
||||||
@@ -32,7 +32,7 @@ http:
|
|||||||
- authelia@docker
|
- authelia@docker
|
||||||
|
|
||||||
backrest-your-remote-server:
|
backrest-your-remote-server:
|
||||||
rule: "Host(`backrest.your-remote-server.kelinreij.duckdns.org`)"
|
rule: "Host(`backrest.your-remote-server.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: backrest-your-remote-server
|
service: backrest-your-remote-server
|
||||||
@@ -42,7 +42,7 @@ http:
|
|||||||
- authelia@docker
|
- authelia@docker
|
||||||
|
|
||||||
duplicati-your-remote-server:
|
duplicati-your-remote-server:
|
||||||
rule: "Host(`duplicati.your-remote-server.kelinreij.duckdns.org`)"
|
rule: "Host(`duplicati.your-remote-server.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: duplicati-your-remote-server
|
service: duplicati-your-remote-server
|
||||||
@@ -52,7 +52,7 @@ http:
|
|||||||
- authelia@docker
|
- authelia@docker
|
||||||
|
|
||||||
homepage-your-remote-server:
|
homepage-your-remote-server:
|
||||||
rule: "Host(`homepage.your-remote-server.kelinreij.duckdns.org`)"
|
rule: "Host(`homepage.your-remote-server.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: homepage-your-remote-server
|
service: homepage-your-remote-server
|
||||||
@@ -62,7 +62,7 @@ http:
|
|||||||
- authelia@docker
|
- authelia@docker
|
||||||
|
|
||||||
homarr-your-remote-server:
|
homarr-your-remote-server:
|
||||||
rule: "Host(`homarr.your-remote-server.kelinreij.duckdns.org`)"
|
rule: "Host(`homarr.your-remote-server.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: homarr-your-remote-server
|
service: homarr-your-remote-server
|
||||||
@@ -72,7 +72,7 @@ http:
|
|||||||
- authelia@docker
|
- authelia@docker
|
||||||
|
|
||||||
grafana-your-remote-server:
|
grafana-your-remote-server:
|
||||||
rule: "Host(`grafana.your-remote-server.kelinreij.duckdns.org`)"
|
rule: "Host(`grafana.your-remote-server.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: grafana-your-remote-server
|
service: grafana-your-remote-server
|
||||||
@@ -82,7 +82,7 @@ http:
|
|||||||
- authelia@docker
|
- authelia@docker
|
||||||
|
|
||||||
prometheus-your-remote-server:
|
prometheus-your-remote-server:
|
||||||
rule: "Host(`prometheus.your-remote-server.kelinreij.duckdns.org`)"
|
rule: "Host(`prometheus.your-remote-server.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: prometheus-your-remote-server
|
service: prometheus-your-remote-server
|
||||||
@@ -92,7 +92,7 @@ http:
|
|||||||
- authelia@docker
|
- authelia@docker
|
||||||
|
|
||||||
uptime-kuma-your-remote-server:
|
uptime-kuma-your-remote-server:
|
||||||
rule: "Host(`status.your-remote-server.kelinreij.duckdns.org`)"
|
rule: "Host(`status.your-remote-server.yourdomain.duckdns.org`)"
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
service: uptime-kuma-your-remote-server
|
service: uptime-kuma-your-remote-server
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ http:
|
|||||||
middlewares:
|
middlewares:
|
||||||
authelia:
|
authelia:
|
||||||
forwardauth:
|
forwardauth:
|
||||||
address: http://authelia:9091/api/verify?rd=https://auth.kelinreij.duckdns.org/
|
address: http://authelia:9091/api/verify?rd=https://auth.yourdomain.duckdns.org/
|
||||||
authResponseHeaders:
|
authResponseHeaders:
|
||||||
- X-Secret
|
- X-Secret
|
||||||
trustForwardHeader: true
|
trustForwardHeader: true
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ entryPoints:
|
|||||||
certificatesResolvers:
|
certificatesResolvers:
|
||||||
letsencrypt:
|
letsencrypt:
|
||||||
acme:
|
acme:
|
||||||
email: admin@example.com # Your email for Let's Encrypt notifications
|
email: ${DEFAULT_EMAIL} # Your email for Let's Encrypt notifications
|
||||||
caServer: https://acme-v02.api.letsencrypt.org/directory # Use staging for testing
|
caServer: https://acme-v02.api.letsencrypt.org/directory # Use staging for testing
|
||||||
storage: /letsencrypt/acme.json
|
storage: /letsencrypt/acme.json
|
||||||
# DNS challenge - For wildcard certificates (*.yourdomain.duckdns.org)
|
# DNS challenge - For wildcard certificates (*.yourdomain.duckdns.org)
|
||||||
|
|||||||
@@ -4,253 +4,253 @@
|
|||||||
- Dashboards:
|
- Dashboards:
|
||||||
- Homepage:
|
- Homepage:
|
||||||
icon: homepage.png
|
icon: homepage.png
|
||||||
href: https://homepage.kelinreij.duckdns.org
|
href: https://homepage.yourdomain.duckdns.org
|
||||||
description: Hosted on Raspberry Pi
|
description: Hosted on Raspberry Pi
|
||||||
|
|
||||||
- Homarr:
|
- Homarr:
|
||||||
icon: homarr.png
|
icon: homarr.png
|
||||||
href: https://homarr.kelinreij.duckdns.org
|
href: https://homarr.yourdomain.duckdns.org
|
||||||
description: Alternative Dashboard
|
description: Alternative Dashboard
|
||||||
|
|
||||||
- Dockge - jasper:
|
- Dockge - jasper:
|
||||||
icon: dockge.png
|
icon: dockge.png
|
||||||
href: https://jasper.kelinreij.duckdns.org
|
href: https://jasper.yourdomain.duckdns.org
|
||||||
description: Main Server
|
description: Main Server
|
||||||
|
|
||||||
- Dockge - your-remote-server :
|
- Dockge - your-remote-server :
|
||||||
icon: dockge.png
|
icon: dockge.png
|
||||||
href: https://your-remote-server .kelinreij.duckdns.org
|
href: https://your-remote-server .yourdomain.duckdns.org
|
||||||
description: Raspberry Pi Authentication Server
|
description: Raspberry Pi Authentication Server
|
||||||
|
|
||||||
- Core:
|
- Core:
|
||||||
- Traefik:
|
- Traefik:
|
||||||
icon: traefik.png
|
icon: traefik.png
|
||||||
href: https://traefik.kelinreij.duckdns.org
|
href: https://traefik.yourdomain.duckdns.org
|
||||||
description: Reverse Proxy & SSL
|
description: Reverse Proxy & SSL
|
||||||
|
|
||||||
- Authelia:
|
- Authelia:
|
||||||
icon: authelia.png
|
icon: authelia.png
|
||||||
href: https://auth.kelinreij.duckdns.org
|
href: https://auth.yourdomain.duckdns.org
|
||||||
description: Authentication SSO Portal
|
description: Authentication SSO Portal
|
||||||
|
|
||||||
- Pi-hole:
|
- Pi-hole:
|
||||||
icon: pi-hole.png
|
icon: pi-hole.png
|
||||||
href: https://pihole.kelinreij.duckdns.org
|
href: https://pihole.yourdomain.duckdns.org
|
||||||
description: Network-wide Ad Blocking
|
description: Network-wide Ad Blocking
|
||||||
|
|
||||||
- Monitoring Stack:
|
- Monitoring Stack:
|
||||||
- Dozzle:
|
- Dozzle:
|
||||||
icon: dozzle.png
|
icon: dozzle.png
|
||||||
href: https://dozzle.jasper.kelinreij.duckdns.org
|
href: https://dozzle.jasper.yourdomain.duckdns.org
|
||||||
description: jasper - Real-time Log Viewer
|
description: jasper - Real-time Log Viewer
|
||||||
|
|
||||||
- Dozzle:
|
- Dozzle:
|
||||||
icon: dozzle.png
|
icon: dozzle.png
|
||||||
href: https://dozzle.your-remote-server .kelinreij.duckdns.org
|
href: https://dozzle.your-remote-server .yourdomain.duckdns.org
|
||||||
description: your-remote-server - Real-time Log Viewer
|
description: your-remote-server - Real-time Log Viewer
|
||||||
|
|
||||||
- Glances - jasper:
|
- Glances - jasper:
|
||||||
icon: glances.png
|
icon: glances.png
|
||||||
href: https://glances.jasper.kelinreij.duckdns.org
|
href: https://glances.jasper.yourdomain.duckdns.org
|
||||||
description: jasper - System Monitoring
|
description: jasper - System Monitoring
|
||||||
|
|
||||||
- Glances - your-remote-server :
|
- Glances - your-remote-server :
|
||||||
icon: glances.png
|
icon: glances.png
|
||||||
href: https://glances.your-remote-server .kelinreij.duckdns.org
|
href: https://glances.your-remote-server .yourdomain.duckdns.org
|
||||||
description: your-remote-server - System Monitoring
|
description: your-remote-server - System Monitoring
|
||||||
|
|
||||||
- Uptime Kuma:
|
- Uptime Kuma:
|
||||||
icon: uptime-kuma.png
|
icon: uptime-kuma.png
|
||||||
href: https://uptime-kuma.kelinreij.duckdns.org
|
href: https://uptime-kuma.yourdomain.duckdns.org
|
||||||
description: Uptime Monitoring
|
description: Uptime Monitoring
|
||||||
|
|
||||||
- Media:
|
- Media:
|
||||||
- Jellyfin:
|
- Jellyfin:
|
||||||
icon: jellyfin.png
|
icon: jellyfin.png
|
||||||
href: https://jellyfin.kelinreij.duckdns.org
|
href: https://jellyfin.yourdomain.duckdns.org
|
||||||
description: Open Source Media Server
|
description: Open Source Media Server
|
||||||
|
|
||||||
- Jellyseerr:
|
- Jellyseerr:
|
||||||
icon: jellyseerr.png
|
icon: jellyseerr.png
|
||||||
href: https://jellyseerr.kelinreij.duckdns.org
|
href: https://jellyseerr.yourdomain.duckdns.org
|
||||||
description: Media Request Manager
|
description: Media Request Manager
|
||||||
|
|
||||||
- Calibre-Web:
|
- Calibre-Web:
|
||||||
icon: calibre-web.png
|
icon: calibre-web.png
|
||||||
href: https://calibre.kelinreij.duckdns.org
|
href: https://calibre.yourdomain.duckdns.org
|
||||||
description: Ebook Library
|
description: Ebook Library
|
||||||
|
|
||||||
- Media Management:
|
- Media Management:
|
||||||
- Sonarr:
|
- Sonarr:
|
||||||
icon: sonarr.png
|
icon: sonarr.png
|
||||||
href: https://sonarr.kelinreij.duckdns.org
|
href: https://sonarr.yourdomain.duckdns.org
|
||||||
description: TV Shows Automation
|
description: TV Shows Automation
|
||||||
|
|
||||||
- Radarr:
|
- Radarr:
|
||||||
icon: radarr.png
|
icon: radarr.png
|
||||||
href: https://radarr.kelinreij.duckdns.org
|
href: https://radarr.yourdomain.duckdns.org
|
||||||
description: Movies Automation
|
description: Movies Automation
|
||||||
|
|
||||||
- Prowlarr:
|
- Prowlarr:
|
||||||
icon: prowlarr.png
|
icon: prowlarr.png
|
||||||
href: https://prowlarr.kelinreij.duckdns.org
|
href: https://prowlarr.yourdomain.duckdns.org
|
||||||
description: Indexer Manager
|
description: Indexer Manager
|
||||||
|
|
||||||
- Readarr:
|
- Readarr:
|
||||||
icon: readarr.png
|
icon: readarr.png
|
||||||
href: https://readarr.kelinreij.duckdns.org
|
href: https://readarr.yourdomain.duckdns.org
|
||||||
description: Books Automation
|
description: Books Automation
|
||||||
|
|
||||||
- Lidarr:
|
- Lidarr:
|
||||||
icon: lidarr.png
|
icon: lidarr.png
|
||||||
href: https://lidarr.kelinreij.duckdns.org
|
href: https://lidarr.yourdomain.duckdns.org
|
||||||
description: Music Automation
|
description: Music Automation
|
||||||
|
|
||||||
- Mylar3:
|
- Mylar3:
|
||||||
icon: mylar.png
|
icon: mylar.png
|
||||||
href: https://mylar.kelinreij.duckdns.org
|
href: https://mylar.yourdomain.duckdns.org
|
||||||
description: Comics Manager
|
description: Comics Manager
|
||||||
|
|
||||||
- Home Automation:
|
- Home Automation:
|
||||||
- Home Assistant:
|
- Home Assistant:
|
||||||
icon: home-assistant.png
|
icon: home-assistant.png
|
||||||
href: https://hass.kelinreij.duckdns.org
|
href: https://hass.yourdomain.duckdns.org
|
||||||
description: Home Automation Platform
|
description: Home Automation Platform
|
||||||
|
|
||||||
- ESPHome:
|
- ESPHome:
|
||||||
icon: esphome.png
|
icon: esphome.png
|
||||||
href: https://esphome.kelinreij.duckdns.org
|
href: https://esphome.yourdomain.duckdns.org
|
||||||
description: ESP Device Manager
|
description: ESP Device Manager
|
||||||
|
|
||||||
- Node-RED:
|
- Node-RED:
|
||||||
icon: node-red.png
|
icon: node-red.png
|
||||||
href: https://nodered.kelinreij.duckdns.org
|
href: https://nodered.yourdomain.duckdns.org
|
||||||
description: Flow-based Automation
|
description: Flow-based Automation
|
||||||
|
|
||||||
- Zigbee2MQTT:
|
- Zigbee2MQTT:
|
||||||
icon: zigbee2mqtt.png
|
icon: zigbee2mqtt.png
|
||||||
href: https://zigbee.kelinreij.duckdns.org
|
href: https://zigbee.yourdomain.duckdns.org
|
||||||
description: Zigbee Bridge
|
description: Zigbee Bridge
|
||||||
|
|
||||||
- Mosquitto:
|
- Mosquitto:
|
||||||
icon: mosquitto.png
|
icon: mosquitto.png
|
||||||
href: https://mqtt.kelinreij.duckdns.org
|
href: https://mqtt.yourdomain.duckdns.org
|
||||||
description: MQTT Broker
|
description: MQTT Broker
|
||||||
|
|
||||||
- Productivity:
|
- Productivity:
|
||||||
- Nextcloud:
|
- Nextcloud:
|
||||||
icon: nextcloud.png
|
icon: nextcloud.png
|
||||||
href: https://nextcloud.kelinreij.duckdns.org
|
href: https://nextcloud.yourdomain.duckdns.org
|
||||||
description: Cloud Storage & Collaboration
|
description: Cloud Storage & Collaboration
|
||||||
|
|
||||||
- Gitea:
|
- Gitea:
|
||||||
icon: gitea.png
|
icon: gitea.png
|
||||||
href: https://gitea.kelinreij.duckdns.org
|
href: https://gitea.yourdomain.duckdns.org
|
||||||
description: Git Repository
|
description: Git Repository
|
||||||
|
|
||||||
- Mealie:
|
- Mealie:
|
||||||
icon: mealie.png
|
icon: mealie.png
|
||||||
href: https://mealie.kelinreij.duckdns.org
|
href: https://mealie.yourdomain.duckdns.org
|
||||||
description: Recipe Manager
|
description: Recipe Manager
|
||||||
|
|
||||||
- WordPress:
|
- WordPress:
|
||||||
icon: wordpress.png
|
icon: wordpress.png
|
||||||
href: https://wordpress.kelinreij.duckdns.org
|
href: https://wordpress.yourdomain.duckdns.org
|
||||||
description: CMS Platform
|
description: CMS Platform
|
||||||
|
|
||||||
- Wikis:
|
- Wikis:
|
||||||
- BookStack:
|
- BookStack:
|
||||||
icon: bookstack.png
|
icon: bookstack.png
|
||||||
href: https://bookstack.kelinreij.duckdns.org
|
href: https://bookstack.yourdomain.duckdns.org
|
||||||
description: Wiki Platform
|
description: Wiki Platform
|
||||||
|
|
||||||
- DokuWiki:
|
- DokuWiki:
|
||||||
icon: dokuwiki.png
|
icon: dokuwiki.png
|
||||||
href: https://dokuwiki.kelinreij.duckdns.org
|
href: https://dokuwiki.yourdomain.duckdns.org
|
||||||
description: Simple Wiki
|
description: Simple Wiki
|
||||||
|
|
||||||
- Mediawiki:
|
- Mediawiki:
|
||||||
icon: mediawiki.png
|
icon: mediawiki.png
|
||||||
href: https://mediawiki.kelinreij.duckdns.org
|
href: https://mediawiki.yourdomain.duckdns.org
|
||||||
description: Collaborative Wiki
|
description: Collaborative Wiki
|
||||||
|
|
||||||
- Development:
|
- Development:
|
||||||
- VS Code Server:
|
- VS Code Server:
|
||||||
icon: vscode.png
|
icon: vscode.png
|
||||||
href: https://code.kelinreij.duckdns.org
|
href: https://code.yourdomain.duckdns.org
|
||||||
description: Browser-based IDE
|
description: Browser-based IDE
|
||||||
|
|
||||||
- Jupyter:
|
- Jupyter:
|
||||||
icon: jupyter.png
|
icon: jupyter.png
|
||||||
href: https://jupyter.kelinreij.duckdns.org
|
href: https://jupyter.yourdomain.duckdns.org
|
||||||
description: Data Science Notebooks
|
description: Data Science Notebooks
|
||||||
|
|
||||||
- Downloaders:
|
- Downloaders:
|
||||||
- qBittorrent:
|
- qBittorrent:
|
||||||
icon: qbittorrent.png
|
icon: qbittorrent.png
|
||||||
href: https://qbit.kelinreij.duckdns.org
|
href: https://qbit.yourdomain.duckdns.org
|
||||||
description: Torrent Client
|
description: Torrent Client
|
||||||
- Transcoders:
|
- Transcoders:
|
||||||
- Tdarr:
|
- Tdarr:
|
||||||
icon: tdarr.png
|
icon: tdarr.png
|
||||||
href: https://tdarr.kelinreij.duckdns.org
|
href: https://tdarr.yourdomain.duckdns.org
|
||||||
description: Media Transcoding
|
description: Media Transcoding
|
||||||
|
|
||||||
- Unmanic:
|
- Unmanic:
|
||||||
icon: unmanic.png
|
icon: unmanic.png
|
||||||
href: https://unmanic.kelinreij.duckdns.org
|
href: https://unmanic.yourdomain.duckdns.org
|
||||||
description: Media Transcoder
|
description: Media Transcoder
|
||||||
|
|
||||||
- Utilities:
|
- Utilities:
|
||||||
- Vaultwarden:
|
- Vaultwarden:
|
||||||
icon: vaultwarden.png
|
icon: vaultwarden.png
|
||||||
href: https://vault.kelinreij.duckdns.org
|
href: https://vault.yourdomain.duckdns.org
|
||||||
description: Password Manager
|
description: Password Manager
|
||||||
|
|
||||||
- Formio:
|
- Formio:
|
||||||
icon: mdi-form-select
|
icon: mdi-form-select
|
||||||
href: https://formio.kelinreij.duckdns.org
|
href: https://formio.yourdomain.duckdns.org
|
||||||
description: Form Builder
|
description: Form Builder
|
||||||
|
|
||||||
- Backup:
|
- Backup:
|
||||||
- Backrest:
|
- Backrest:
|
||||||
icon: mdi-backup-restore
|
icon: mdi-backup-restore
|
||||||
href: https://backrest.kelinreij.duckdns.org
|
href: https://backrest.yourdomain.duckdns.org
|
||||||
description: Backup Solution
|
description: Backup Solution
|
||||||
|
|
||||||
- Duplicati:
|
- Duplicati:
|
||||||
icon: duplicati.png
|
icon: duplicati.png
|
||||||
href: https://duplicati.kelinreij.duckdns.org
|
href: https://duplicati.yourdomain.duckdns.org
|
||||||
description: Backup Software
|
description: Backup Software
|
||||||
|
|
||||||
- Metrics:
|
- Metrics:
|
||||||
- Grafana:
|
- Grafana:
|
||||||
icon: grafana.png
|
icon: grafana.png
|
||||||
href: https://grafana.kelinreij.duckdns.org
|
href: https://grafana.yourdomain.duckdns.org
|
||||||
description: Metrics Dashboard
|
description: Metrics Dashboard
|
||||||
|
|
||||||
- Prometheus:
|
- Prometheus:
|
||||||
icon: prometheus.png
|
icon: prometheus.png
|
||||||
href: https://prometheus.kelinreij.duckdns.org
|
href: https://prometheus.yourdomain.duckdns.org
|
||||||
description: Metrics Collection
|
description: Metrics Collection
|
||||||
|
|
||||||
- cAdvisor:
|
- cAdvisor:
|
||||||
icon: cadvisor.png
|
icon: cadvisor.png
|
||||||
href: https://cadvisor.kelinreij.duckdns.org
|
href: https://cadvisor.yourdomain.duckdns.org
|
||||||
description: Container Metrics
|
description: Container Metrics
|
||||||
|
|
||||||
- Alternatives:
|
- Alternatives:
|
||||||
- Portainer:
|
- Portainer:
|
||||||
icon: portainer.png
|
icon: portainer.png
|
||||||
href: https://portainer.kelinreij.duckdns.org
|
href: https://portainer.yourdomain.duckdns.org
|
||||||
description: Container Management UI
|
description: Container Management UI
|
||||||
|
|
||||||
- Authentik:
|
- Authentik:
|
||||||
icon: authentik.png
|
icon: authentik.png
|
||||||
href: https://authentik.kelinreij.duckdns.org
|
href: https://authentik.yourdomain.duckdns.org
|
||||||
description: Alternative Auth Provider
|
description: Alternative Auth Provider
|
||||||
|
|
||||||
- Plex:
|
- Plex:
|
||||||
icon: plex.png
|
icon: plex.png
|
||||||
href: https://plex.kelinreij.duckdns.org
|
href: https://plex.yourdomain.duckdns.org
|
||||||
description: Media Server
|
description: Media Server
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
bind-addr: 127.0.0.1:8080
|
bind-addr: 127.0.0.1:8080
|
||||||
auth: password
|
auth: password
|
||||||
password: 4d6c2b20e8d2c62be2512281
|
password: ${CODE_SERVER_PASSWORD}
|
||||||
cert: false
|
cert: false
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ services:
|
|||||||
- 'traefik.http.routers.dozzle.tls=true'
|
- 'traefik.http.routers.dozzle.tls=true'
|
||||||
- 'traefik.http.routers.dozzle.middlewares=authelia@docker'
|
- 'traefik.http.routers.dozzle.middlewares=authelia@docker'
|
||||||
# Service configuration
|
# Service configuration
|
||||||
- 'traefik.http.services.dozzle.loadbalancer.server.port=8085'
|
- 'traefik.http.services.dozzle.loadbalancer.server.port=8080'
|
||||||
# Sablier configuration
|
# Sablier configuration
|
||||||
- 'sablier.enable=true'
|
- 'sablier.enable=true'
|
||||||
- 'sablier.group=jasper-dozzle'
|
- 'sablier.group=jasper-dozzle'
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ services:
|
|||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.sablier.rule=Host(`sablier.{{DUCKDNS_DOMAIN}}`)"
|
- "traefik.http.routers.sablier.rule=Host(`sablier.${DOMAIN}`)"
|
||||||
- "traefik.http.routers.sablier.entrypoints=websecure"
|
- "traefik.http.routers.sablier.entrypoints=websecure"
|
||||||
- "traefik.http.routers.sablier.tls=true"
|
- "traefik.http.routers.sablier.tls=true"
|
||||||
- "traefik.http.routers.sablier.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.sablier.tls.certresolver=letsencrypt"
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ Services were showing "not secure" warnings in browsers despite Traefik being co
|
|||||||
### 1. **Multiple Simultaneous Certificate Requests**
|
### 1. **Multiple Simultaneous Certificate Requests**
|
||||||
- **Issue:** Each service (dockge, dozzle, glances, pihole, authelia) had `traefik.http.routers.*.tls.certresolver=letsencrypt` labels
|
- **Issue:** Each service (dockge, dozzle, glances, pihole, authelia) had `traefik.http.routers.*.tls.certresolver=letsencrypt` labels
|
||||||
- **Impact:** Traefik attempted to request individual certificates for each subdomain simultaneously
|
- **Impact:** Traefik attempted to request individual certificates for each subdomain simultaneously
|
||||||
- **Consequence:** DuckDNS DNS challenge can only handle ONE TXT record at `_acme-challenge.kelin-hass.duckdns.org` at a time
|
- **Consequence:** DuckDNS DNS challenge can only handle ONE TXT record at `_acme-challenge.yourdomain.duckdns.org` at a time
|
||||||
- **Result:** All certificate requests failed with "Incorrect TXT record" errors
|
- **Result:** All certificate requests failed with "Incorrect TXT record" errors
|
||||||
|
|
||||||
### 2. **DNS TXT Record Conflicts**
|
### 2. **DNS TXT Record Conflicts**
|
||||||
- **Issue:** Multiple services tried to create different TXT records at the same DNS location
|
- **Issue:** Multiple services tried to create different TXT records at the same DNS location
|
||||||
- **Example:**
|
- **Example:**
|
||||||
- Service A creates: `_acme-challenge.kelin-hass.duckdns.org` = "token1"
|
- Service A creates: `_acme-challenge.yourdomain.duckdns.org` = "token1"
|
||||||
- Service B overwrites: `_acme-challenge.kelin-hass.duckdns.org` = "token2"
|
- Service B overwrites: `_acme-challenge.yourdomain.duckdns.org` = "token2"
|
||||||
- Let's Encrypt validates Service A but finds "token2" → validation fails
|
- Let's Encrypt validates Service A but finds "token2" → validation fails
|
||||||
- **DuckDNS Limitation:** Can only maintain ONE TXT record per domain
|
- **DuckDNS Limitation:** Can only maintain ONE TXT record per domain
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ pihole:
|
|||||||
certificatesResolvers:
|
certificatesResolvers:
|
||||||
letsencrypt:
|
letsencrypt:
|
||||||
acme:
|
acme:
|
||||||
email: kelinfoxy@gmail.com
|
email: your-email@example.com
|
||||||
storage: /acme.json
|
storage: /acme.json
|
||||||
dnsChallenge:
|
dnsChallenge:
|
||||||
provider: duckdns
|
provider: duckdns
|
||||||
@@ -129,7 +129,7 @@ chown kelin:kelin /opt/stacks/core/traefik/acme.json
|
|||||||
|
|
||||||
# Wait for DNS to clear
|
# Wait for DNS to clear
|
||||||
sleep 60
|
sleep 60
|
||||||
dig +short TXT _acme-challenge.kelin-hass.duckdns.org # Verified empty
|
dig +short TXT _acme-challenge.yourdomain.duckdns.org # Verified empty
|
||||||
|
|
||||||
# Deploy updated configuration
|
# Deploy updated configuration
|
||||||
cp /home/kelin/AI-Homelab/docker-compose/core.yml /opt/stacks/core/docker-compose.yml
|
cp /home/kelin/AI-Homelab/docker-compose/core.yml /opt/stacks/core/docker-compose.yml
|
||||||
@@ -189,21 +189,21 @@ cd /opt/stacks/infrastructure && docker compose -f infrastructure.yml up -d
|
|||||||
{
|
{
|
||||||
"letsencrypt": {
|
"letsencrypt": {
|
||||||
"Account": {
|
"Account": {
|
||||||
"Email": "kelinfoxy@gmail.com",
|
"Email": "your-email@example.com",
|
||||||
"Registration": {
|
"Registration": {
|
||||||
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/2958966636"
|
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/XXXXXXXXXX"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Certificates": [
|
"Certificates": [
|
||||||
{
|
{
|
||||||
"domain": {
|
"domain": {
|
||||||
"main": "dockge.kelin-hass.duckdns.org"
|
"main": "dockge.yourdomain.duckdns.org"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"domain": {
|
"domain": {
|
||||||
"main": "kelin-hass.duckdns.org",
|
"main": "yourdomain.duckdns.org",
|
||||||
"sans": ["*.kelin-hass.duckdns.org"]
|
"sans": ["*.yourdomain.duckdns.org"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -212,7 +212,7 @@ cd /opt/stacks/infrastructure && docker compose -f infrastructure.yml up -d
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Certificate Details:**
|
**Certificate Details:**
|
||||||
- **Subject:** CN=kelin-hass.duckdns.org
|
- **Subject:** CN=yourdomain.duckdns.org
|
||||||
- **Issuer:** C=US, O=Let's Encrypt, CN=R12
|
- **Issuer:** C=US, O=Let's Encrypt, CN=R12
|
||||||
- **Coverage:** Wildcard certificate covering all subdomains
|
- **Coverage:** Wildcard certificate covering all subdomains
|
||||||
- **File Size:** 23KB (up from 0 bytes)
|
- **File Size:** 23KB (up from 0 bytes)
|
||||||
@@ -223,12 +223,12 @@ All services running with valid SSL certificates:
|
|||||||
|
|
||||||
| Service | Status | URL | Certificate |
|
| Service | Status | URL | Certificate |
|
||||||
|---------|--------|-----|-------------|
|
|---------|--------|-----|-------------|
|
||||||
| Traefik | ✅ Up | https://traefik.kelin-hass.duckdns.org | Valid |
|
| Traefik | ✅ Up | https://traefik.yourdomain.duckdns.org | Valid |
|
||||||
| Authelia | ✅ Up | https://auth.kelin-hass.duckdns.org | Valid |
|
| Authelia | ✅ Up | https://auth.yourdomain.duckdns.org | Valid |
|
||||||
| Dockge | ✅ Up | https://dockge.kelin-hass.duckdns.org | Valid |
|
| Dockge | ✅ Up | https://dockge.yourdomain.duckdns.org | Valid |
|
||||||
| Dozzle | ✅ Up | https://dozzle.kelin-hass.duckdns.org | Valid |
|
| Dozzle | ✅ Up | https://dozzle.yourdomain.duckdns.org | Valid |
|
||||||
| Glances | ✅ Up | https://glances.kelin-hass.duckdns.org | Valid |
|
| Glances | ✅ Up | https://glances.yourdomain.duckdns.org | Valid |
|
||||||
| Pi-hole | ✅ Up | https://pihole.kelin-hass.duckdns.org | Valid |
|
| Pi-hole | ✅ Up | https://pihole.yourdomain.duckdns.org | Valid |
|
||||||
|
|
||||||
## Best Practices & Prevention
|
## Best Practices & Prevention
|
||||||
|
|
||||||
@@ -259,7 +259,7 @@ other-service:
|
|||||||
### 2. ✅ DuckDNS DNS Challenge Limitations
|
### 2. ✅ DuckDNS DNS Challenge Limitations
|
||||||
|
|
||||||
**Understand the Constraint:**
|
**Understand the Constraint:**
|
||||||
- DuckDNS can only maintain ONE TXT record at `_acme-challenge.kelin-hass.duckdns.org`
|
- DuckDNS can only maintain ONE TXT record at `_acme-challenge.yourdomain.duckdns.org`
|
||||||
- Multiple simultaneous challenges WILL fail
|
- Multiple simultaneous challenges WILL fail
|
||||||
- Use wildcard certificate to avoid this limitation
|
- Use wildcard certificate to avoid this limitation
|
||||||
|
|
||||||
@@ -292,7 +292,7 @@ docker exec traefik tail -f /var/log/traefik/traefik.log | grep -E "acme|certifi
|
|||||||
docker exec traefik tail -100 /var/log/traefik/traefik.log | grep -E "error|Unable"
|
docker exec traefik tail -100 /var/log/traefik/traefik.log | grep -E "error|Unable"
|
||||||
|
|
||||||
# View specific domain
|
# View specific domain
|
||||||
docker exec traefik tail -200 /var/log/traefik/traefik.log | grep "kelin-hass.duckdns.org"
|
docker exec traefik tail -200 /var/log/traefik/traefik.log | grep "yourdomain.duckdns.org"
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. ✅ Certificate Troubleshooting Workflow
|
### 4. ✅ Certificate Troubleshooting Workflow
|
||||||
@@ -307,10 +307,10 @@ cat /opt/stacks/core/traefik/acme.json | python3 -m json.tool | grep -A5 "Certif
|
|||||||
python3 -c "import json; d=json.load(open('/opt/stacks/core/traefik/acme.json')); print(f'Certificates: {len(d[\"letsencrypt\"][\"Certificates\"])}')"
|
python3 -c "import json; d=json.load(open('/opt/stacks/core/traefik/acme.json')); print(f'Certificates: {len(d[\"letsencrypt\"][\"Certificates\"])}')"
|
||||||
|
|
||||||
# 3. Test certificate being served
|
# 3. Test certificate being served
|
||||||
echo | openssl s_client -connect auth.kelin-hass.duckdns.org:443 -servername auth.kelin-hass.duckdns.org 2>/dev/null | openssl x509 -noout -subject -issuer
|
echo | openssl s_client -connect auth.yourdomain.duckdns.org:443 -servername auth.yourdomain.duckdns.org 2>/dev/null | openssl x509 -noout -subject -issuer
|
||||||
|
|
||||||
# 4. Check DNS TXT records
|
# 4. Check DNS TXT records
|
||||||
dig +short TXT _acme-challenge.kelin-hass.duckdns.org
|
dig +short TXT _acme-challenge.yourdomain.duckdns.org
|
||||||
|
|
||||||
# 5. Check Traefik logs
|
# 5. Check Traefik logs
|
||||||
docker exec traefik tail -50 /var/log/traefik/traefik.log
|
docker exec traefik tail -50 /var/log/traefik/traefik.log
|
||||||
@@ -457,15 +457,15 @@ docker exec traefik tail -f /var/log/traefik/traefik.log
|
|||||||
### Verify Certificate Command
|
### Verify Certificate Command
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo | openssl s_client -connect ${SUBDOMAIN}.kelin-hass.duckdns.org:443 -servername ${SUBDOMAIN}.kelin-hass.duckdns.org 2>/dev/null | openssl x509 -noout -subject -issuer -dates
|
echo | openssl s_client -connect ${SUBDOMAIN}.yourdomain.duckdns.org:443 -servername ${SUBDOMAIN}.yourdomain.duckdns.org 2>/dev/null | openssl x509 -noout -subject -issuer -dates
|
||||||
```
|
```
|
||||||
|
|
||||||
### Check All Service Certificates
|
### Check All Service Certificates
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
for subdomain in auth traefik dockge dozzle glances pihole; do
|
for subdomain in auth traefik dockge dozzle glances pihole; do
|
||||||
echo "=== $subdomain.kelin-hass.duckdns.org ==="
|
echo "=== $subdomain.yourdomain.duckdns.org ==="
|
||||||
echo | openssl s_client -connect $subdomain.kelin-hass.duckdns.org:443 -servername $subdomain.kelin-hass.duckdns.org 2>/dev/null | openssl x509 -noout -subject -issuer
|
echo | openssl s_client -connect $subdomain.yourdomain.duckdns.org:443 -servername $subdomain.yourdomain.duckdns.org 2>/dev/null | openssl x509 -noout -subject -issuer
|
||||||
echo
|
echo
|
||||||
done
|
done
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1402,7 +1402,7 @@ Homepage configuration must be kept synchronized with deployed services. The AI
|
|||||||
|
|
||||||
1. **Hard-Coded URLs Required**: Homepage does NOT support variables in href links
|
1. **Hard-Coded URLs Required**: Homepage does NOT support variables in href links
|
||||||
- Template uses `{{HOMEPAGE_VAR_DOMAIN}}` as placeholder
|
- Template uses `{{HOMEPAGE_VAR_DOMAIN}}` as placeholder
|
||||||
- Active config uses `kelin-hass.duckdns.org` hard-coded
|
- Active config uses `yourdomain.duckdns.org` hard-coded
|
||||||
- AI must replace placeholders when deploying configs
|
- AI must replace placeholders when deploying configs
|
||||||
|
|
||||||
2. **No Container Restart Needed**: Homepage picks up config changes instantly
|
2. **No Container Restart Needed**: Homepage picks up config changes instantly
|
||||||
@@ -1427,7 +1427,7 @@ Homepage configuration must be kept synchronized with deployed services. The AI
|
|||||||
- Stack Name (compose-file.yml):
|
- Stack Name (compose-file.yml):
|
||||||
- Service Name:
|
- Service Name:
|
||||||
icon: service.png
|
icon: service.png
|
||||||
href: https://subdomain.kelin-hass.duckdns.org # Hard-coded!
|
href: https://subdomain.yourdomain.duckdns.org # Hard-coded!
|
||||||
description: Service description
|
description: Service description
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1436,7 +1436,7 @@ Homepage configuration must be kept synchronized with deployed services. The AI
|
|||||||
```bash
|
```bash
|
||||||
# When deploying from template:
|
# When deploying from template:
|
||||||
cp /home/kelin/AI-Homelab/config-templates/homepage/*.yaml /opt/stacks/homepage/config/
|
cp /home/kelin/AI-Homelab/config-templates/homepage/*.yaml /opt/stacks/homepage/config/
|
||||||
sed -i 's/{{HOMEPAGE_VAR_DOMAIN}}/kelin-hass.duckdns.org/g' /opt/stacks/homepage/config/services.yaml
|
sed -i 's/{{HOMEPAGE_VAR_DOMAIN}}/yourdomain.duckdns.org/g' /opt/stacks/homepage/config/services.yaml
|
||||||
|
|
||||||
# No restart needed - configs load instantly
|
# No restart needed - configs load instantly
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ Wildcard SSL certificate acquisition via DuckDNS DNS-01 challenge consistently f
|
|||||||
|
|
||||||
### Why Both Domain and Wildcard are Required
|
### Why Both Domain and Wildcard are Required
|
||||||
Let's Encrypt requires validation of BOTH domains when using SAN (Subject Alternative Name) certificates:
|
Let's Encrypt requires validation of BOTH domains when using SAN (Subject Alternative Name) certificates:
|
||||||
- `kelin-hass.duckdns.org` (apex domain)
|
- `yourdomain.duckdns.org` (apex domain)
|
||||||
- `*.kelin-hass.duckdns.org` (wildcard)
|
- `*.yourdomain.duckdns.org` (wildcard)
|
||||||
|
|
||||||
This is a Let's Encrypt policy - you cannot obtain just the wildcard certificate. Both must be validated simultaneously.
|
This is a Let's Encrypt policy - you cannot obtain just the wildcard certificate. Both must be validated simultaneously.
|
||||||
|
|
||||||
@@ -23,13 +23,13 @@ ping -c 2 ns1.duckdns.org # FAIL: 100% packet loss
|
|||||||
ping -c 2 99.79.143.35 # FAIL: 100% packet loss (direct IP)
|
ping -c 2 99.79.143.35 # FAIL: 100% packet loss (direct IP)
|
||||||
|
|
||||||
# DNS queries to authoritative servers - timeout
|
# DNS queries to authoritative servers - timeout
|
||||||
dig @99.79.143.35 kelin-hass.duckdns.org # FAIL: timeout
|
dig @99.79.143.35 yourdomain.duckdns.org # FAIL: timeout
|
||||||
dig @35.182.183.211 kelin-hass.duckdns.org # FAIL: timeout
|
dig @35.182.183.211 yourdomain.duckdns.org # FAIL: timeout
|
||||||
dig @3.97.58.28 kelin-hass.duckdns.org # FAIL: timeout
|
dig @3.97.58.28 yourdomain.duckdns.org # FAIL: timeout
|
||||||
|
|
||||||
# Queries to recursive resolvers - SUCCESS
|
# Queries to recursive resolvers - SUCCESS
|
||||||
dig @8.8.8.8 kelin-hass.duckdns.org # SUCCESS
|
dig @8.8.8.8 yourdomain.duckdns.org # SUCCESS
|
||||||
dig @1.1.1.1 kelin-hass.duckdns.org # SUCCESS
|
dig @1.1.1.1 yourdomain.duckdns.org # SUCCESS
|
||||||
|
|
||||||
# Traceroute analysis
|
# Traceroute analysis
|
||||||
traceroute 99.79.143.35
|
traceroute 99.79.143.35
|
||||||
@@ -83,15 +83,15 @@ The lego library **must** also query the authoritative nameservers directly to v
|
|||||||
```
|
```
|
||||||
propagation: time limit exceeded: last error: authoritative nameservers:
|
propagation: time limit exceeded: last error: authoritative nameservers:
|
||||||
DNS call error: read udp 172.19.0.2:53666->3.97.58.28:53: i/o timeout
|
DNS call error: read udp 172.19.0.2:53666->3.97.58.28:53: i/o timeout
|
||||||
[ns=ns6.duckdns.org.:53, question='_acme-challenge.kelin-hass.duckdns.org. IN TXT']
|
[ns=ns6.duckdns.org.:53, question='_acme-challenge.yourdomain.duckdns.org. IN TXT']
|
||||||
```
|
```
|
||||||
|
|
||||||
**Phase 2: SOA record query failure**
|
**Phase 2: SOA record query failure**
|
||||||
```
|
```
|
||||||
propagation: time limit exceeded: last error: could not find zone:
|
propagation: time limit exceeded: last error: could not find zone:
|
||||||
[fqdn=_acme-challenge.kelin-hass.duckdns.org.]
|
[fqdn=_acme-challenge.yourdomain.duckdns.org.]
|
||||||
unexpected response for 'kelin-hass.duckdns.org.'
|
unexpected response for 'yourdomain.duckdns.org.'
|
||||||
[question='kelin-hass.duckdns.org. IN SOA', code=SERVFAIL]
|
[question='yourdomain.duckdns.org. IN SOA', code=SERVFAIL]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Working Configuration (Self-Signed Certificates)
|
## Working Configuration (Self-Signed Certificates)
|
||||||
|
|||||||
764
get-docker.sh
Normal file
764
get-docker.sh
Normal file
@@ -0,0 +1,764 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
# Docker Engine for Linux installation script.
|
||||||
|
#
|
||||||
|
# This script is intended as a convenient way to configure docker's package
|
||||||
|
# repositories and to install Docker Engine, This script is not recommended
|
||||||
|
# for production environments. Before running this script, make yourself familiar
|
||||||
|
# with potential risks and limitations, and refer to the installation manual
|
||||||
|
# at https://docs.docker.com/engine/install/ for alternative installation methods.
|
||||||
|
#
|
||||||
|
# The script:
|
||||||
|
#
|
||||||
|
# - Requires `root` or `sudo` privileges to run.
|
||||||
|
# - Attempts to detect your Linux distribution and version and configure your
|
||||||
|
# package management system for you.
|
||||||
|
# - Doesn't allow you to customize most installation parameters.
|
||||||
|
# - Installs dependencies and recommendations without asking for confirmation.
|
||||||
|
# - Installs the latest stable release (by default) of Docker CLI, Docker Engine,
|
||||||
|
# Docker Buildx, Docker Compose, containerd, and runc. When using this script
|
||||||
|
# to provision a machine, this may result in unexpected major version upgrades
|
||||||
|
# of these packages. Always test upgrades in a test environment before
|
||||||
|
# deploying to your production systems.
|
||||||
|
# - Isn't designed to upgrade an existing Docker installation. When using the
|
||||||
|
# script to update an existing installation, dependencies may not be updated
|
||||||
|
# to the expected version, resulting in outdated versions.
|
||||||
|
#
|
||||||
|
# Source code is available at https://github.com/docker/docker-install/
|
||||||
|
#
|
||||||
|
# Usage
|
||||||
|
# ==============================================================================
|
||||||
|
#
|
||||||
|
# To install the latest stable versions of Docker CLI, Docker Engine, and their
|
||||||
|
# dependencies:
|
||||||
|
#
|
||||||
|
# 1. download the script
|
||||||
|
#
|
||||||
|
# $ curl -fsSL https://get.docker.com -o install-docker.sh
|
||||||
|
#
|
||||||
|
# 2. verify the script's content
|
||||||
|
#
|
||||||
|
# $ cat install-docker.sh
|
||||||
|
#
|
||||||
|
# 3. run the script with --dry-run to verify the steps it executes
|
||||||
|
#
|
||||||
|
# $ sh install-docker.sh --dry-run
|
||||||
|
#
|
||||||
|
# 4. run the script either as root, or using sudo to perform the installation.
|
||||||
|
#
|
||||||
|
# $ sudo sh install-docker.sh
|
||||||
|
#
|
||||||
|
# Command-line options
|
||||||
|
# ==============================================================================
|
||||||
|
#
|
||||||
|
# --version <VERSION>
|
||||||
|
# Use the --version option to install a specific version, for example:
|
||||||
|
#
|
||||||
|
# $ sudo sh install-docker.sh --version 23.0
|
||||||
|
#
|
||||||
|
# --channel <stable|test>
|
||||||
|
#
|
||||||
|
# Use the --channel option to install from an alternative installation channel.
|
||||||
|
# The following example installs the latest versions from the "test" channel,
|
||||||
|
# which includes pre-releases (alpha, beta, rc):
|
||||||
|
#
|
||||||
|
# $ sudo sh install-docker.sh --channel test
|
||||||
|
#
|
||||||
|
# Alternatively, use the script at https://test.docker.com, which uses the test
|
||||||
|
# channel as default.
|
||||||
|
#
|
||||||
|
# --mirror <Aliyun|AzureChinaCloud>
|
||||||
|
#
|
||||||
|
# Use the --mirror option to install from a mirror supported by this script.
|
||||||
|
# Available mirrors are "Aliyun" (https://mirrors.aliyun.com/docker-ce), and
|
||||||
|
# "AzureChinaCloud" (https://mirror.azure.cn/docker-ce), for example:
|
||||||
|
#
|
||||||
|
# $ sudo sh install-docker.sh --mirror AzureChinaCloud
|
||||||
|
#
|
||||||
|
# --setup-repo
|
||||||
|
#
|
||||||
|
# Use the --setup-repo option to configure Docker's package repositories without
|
||||||
|
# installing Docker packages. This is useful when you want to add the repository
|
||||||
|
# but install packages separately:
|
||||||
|
#
|
||||||
|
# $ sudo sh install-docker.sh --setup-repo
|
||||||
|
#
|
||||||
|
# Automatic Service Start
|
||||||
|
#
|
||||||
|
# By default, this script automatically starts the Docker daemon and enables the docker
|
||||||
|
# service after installation if systemd is used as init.
|
||||||
|
#
|
||||||
|
# If you prefer to start the service manually, use the --no-autostart option:
|
||||||
|
#
|
||||||
|
# $ sudo sh install-docker.sh --no-autostart
|
||||||
|
#
|
||||||
|
# Note: Starting the service requires appropriate privileges to manage system services.
|
||||||
|
#
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# Git commit from https://github.com/docker/docker-install when
|
||||||
|
# the script was uploaded (Should only be modified by upload job):
|
||||||
|
SCRIPT_COMMIT_SHA="f381ee68b32e515bb4dc034b339266aff1fbc460"
|
||||||
|
|
||||||
|
# strip "v" prefix if present
|
||||||
|
VERSION="${VERSION#v}"
|
||||||
|
|
||||||
|
# The channel to install from:
|
||||||
|
# * stable
|
||||||
|
# * test
|
||||||
|
DEFAULT_CHANNEL_VALUE="stable"
|
||||||
|
if [ -z "$CHANNEL" ]; then
|
||||||
|
CHANNEL=$DEFAULT_CHANNEL_VALUE
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEFAULT_DOWNLOAD_URL="https://download.docker.com"
|
||||||
|
if [ -z "$DOWNLOAD_URL" ]; then
|
||||||
|
DOWNLOAD_URL=$DEFAULT_DOWNLOAD_URL
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEFAULT_REPO_FILE="docker-ce.repo"
|
||||||
|
if [ -z "$REPO_FILE" ]; then
|
||||||
|
REPO_FILE="$DEFAULT_REPO_FILE"
|
||||||
|
# Automatically default to a staging repo fora
|
||||||
|
# a staging download url (download-stage.docker.com)
|
||||||
|
case "$DOWNLOAD_URL" in
|
||||||
|
*-stage*) REPO_FILE="docker-ce-staging.repo";;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
mirror=''
|
||||||
|
DRY_RUN=${DRY_RUN:-}
|
||||||
|
REPO_ONLY=${REPO_ONLY:-0}
|
||||||
|
NO_AUTOSTART=${NO_AUTOSTART:-0}
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--channel)
|
||||||
|
CHANNEL="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--dry-run)
|
||||||
|
DRY_RUN=1
|
||||||
|
;;
|
||||||
|
--mirror)
|
||||||
|
mirror="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--version)
|
||||||
|
VERSION="${2#v}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--setup-repo)
|
||||||
|
REPO_ONLY=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--no-autostart)
|
||||||
|
NO_AUTOSTART=1
|
||||||
|
;;
|
||||||
|
--*)
|
||||||
|
echo "Illegal option $1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift $(( $# > 0 ? 1 : 0 ))
|
||||||
|
done
|
||||||
|
|
||||||
|
case "$mirror" in
|
||||||
|
Aliyun)
|
||||||
|
DOWNLOAD_URL="https://mirrors.aliyun.com/docker-ce"
|
||||||
|
;;
|
||||||
|
AzureChinaCloud)
|
||||||
|
DOWNLOAD_URL="https://mirror.azure.cn/docker-ce"
|
||||||
|
;;
|
||||||
|
"")
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
>&2 echo "unknown mirror '$mirror': use either 'Aliyun', or 'AzureChinaCloud'."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$CHANNEL" in
|
||||||
|
stable|test)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
>&2 echo "unknown CHANNEL '$CHANNEL': use either stable or test."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
command_exists() {
|
||||||
|
command -v "$@" > /dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# version_gte checks if the version specified in $VERSION is at least the given
|
||||||
|
# SemVer (Maj.Minor[.Patch]), or CalVer (YY.MM) version.It returns 0 (success)
|
||||||
|
# if $VERSION is either unset (=latest) or newer or equal than the specified
|
||||||
|
# version, or returns 1 (fail) otherwise.
|
||||||
|
#
|
||||||
|
# examples:
|
||||||
|
#
|
||||||
|
# VERSION=23.0
|
||||||
|
# version_gte 23.0 // 0 (success)
|
||||||
|
# version_gte 20.10 // 0 (success)
|
||||||
|
# version_gte 19.03 // 0 (success)
|
||||||
|
# version_gte 26.1 // 1 (fail)
|
||||||
|
version_gte() {
|
||||||
|
if [ -z "$VERSION" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
version_compare "$VERSION" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# version_compare compares two version strings (either SemVer (Major.Minor.Path),
|
||||||
|
# or CalVer (YY.MM) version strings. It returns 0 (success) if version A is newer
|
||||||
|
# or equal than version B, or 1 (fail) otherwise. Patch releases and pre-release
|
||||||
|
# (-alpha/-beta) are not taken into account
|
||||||
|
#
|
||||||
|
# examples:
|
||||||
|
#
|
||||||
|
# version_compare 23.0.0 20.10 // 0 (success)
|
||||||
|
# version_compare 23.0 20.10 // 0 (success)
|
||||||
|
# version_compare 20.10 19.03 // 0 (success)
|
||||||
|
# version_compare 20.10 20.10 // 0 (success)
|
||||||
|
# version_compare 19.03 20.10 // 1 (fail)
|
||||||
|
version_compare() (
|
||||||
|
set +x
|
||||||
|
|
||||||
|
yy_a="$(echo "$1" | cut -d'.' -f1)"
|
||||||
|
yy_b="$(echo "$2" | cut -d'.' -f1)"
|
||||||
|
if [ "$yy_a" -lt "$yy_b" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$yy_a" -gt "$yy_b" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
mm_a="$(echo "$1" | cut -d'.' -f2)"
|
||||||
|
mm_b="$(echo "$2" | cut -d'.' -f2)"
|
||||||
|
|
||||||
|
# trim leading zeros to accommodate CalVer
|
||||||
|
mm_a="${mm_a#0}"
|
||||||
|
mm_b="${mm_b#0}"
|
||||||
|
|
||||||
|
if [ "${mm_a:-0}" -lt "${mm_b:-0}" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
)
|
||||||
|
|
||||||
|
is_dry_run() {
|
||||||
|
if [ -z "$DRY_RUN" ]; then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
is_wsl() {
|
||||||
|
case "$(uname -r)" in
|
||||||
|
*microsoft* ) true ;; # WSL 2
|
||||||
|
*Microsoft* ) true ;; # WSL 1
|
||||||
|
* ) false;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
is_darwin() {
|
||||||
|
case "$(uname -s)" in
|
||||||
|
*darwin* ) true ;;
|
||||||
|
*Darwin* ) true ;;
|
||||||
|
* ) false;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
deprecation_notice() {
|
||||||
|
distro=$1
|
||||||
|
distro_version=$2
|
||||||
|
echo
|
||||||
|
printf "\033[91;1mDEPRECATION WARNING\033[0m\n"
|
||||||
|
printf " This Linux distribution (\033[1m%s %s\033[0m) reached end-of-life and is no longer supported by this script.\n" "$distro" "$distro_version"
|
||||||
|
echo " No updates or security fixes will be released for this distribution, and users are recommended"
|
||||||
|
echo " to upgrade to a currently maintained version of $distro."
|
||||||
|
echo
|
||||||
|
printf "Press \033[1mCtrl+C\033[0m now to abort this script, or wait for the installation to continue."
|
||||||
|
echo
|
||||||
|
sleep 10
|
||||||
|
}
|
||||||
|
|
||||||
|
get_distribution() {
|
||||||
|
lsb_dist=""
|
||||||
|
# Every system that we officially support has /etc/os-release
|
||||||
|
if [ -r /etc/os-release ]; then
|
||||||
|
lsb_dist="$(. /etc/os-release && echo "$ID")"
|
||||||
|
fi
|
||||||
|
# Returning an empty string here should be alright since the
|
||||||
|
# case statements don't act unless you provide an actual value
|
||||||
|
echo "$lsb_dist"
|
||||||
|
}
|
||||||
|
|
||||||
|
start_docker_daemon() {
|
||||||
|
# Use systemctl if available (for systemd-based systems)
|
||||||
|
if command_exists systemctl; then
|
||||||
|
is_dry_run || >&2 echo "Using systemd to manage Docker service"
|
||||||
|
if (
|
||||||
|
is_dry_run || set -x
|
||||||
|
$sh_c systemctl enable --now docker.service 2>/dev/null
|
||||||
|
); then
|
||||||
|
is_dry_run || echo "INFO: Docker daemon enabled and started" >&2
|
||||||
|
else
|
||||||
|
is_dry_run || echo "WARNING: unable to enable the docker service" >&2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# No service management available (container environment)
|
||||||
|
if ! is_dry_run; then
|
||||||
|
>&2 echo "Note: Running in a container environment without service management"
|
||||||
|
>&2 echo "Docker daemon cannot be started automatically in this environment"
|
||||||
|
>&2 echo "The Docker packages have been installed successfully"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
>&2 echo
|
||||||
|
}
|
||||||
|
|
||||||
|
echo_docker_as_nonroot() {
|
||||||
|
if is_dry_run; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if command_exists docker && [ -e /var/run/docker.sock ]; then
|
||||||
|
(
|
||||||
|
set -x
|
||||||
|
$sh_c 'docker version'
|
||||||
|
) || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# intentionally mixed spaces and tabs here -- tabs are stripped by "<<-EOF", spaces are kept in the output
|
||||||
|
echo
|
||||||
|
echo "================================================================================"
|
||||||
|
echo
|
||||||
|
if version_gte "20.10"; then
|
||||||
|
echo "To run Docker as a non-privileged user, consider setting up the"
|
||||||
|
echo "Docker daemon in rootless mode for your user:"
|
||||||
|
echo
|
||||||
|
echo " dockerd-rootless-setuptool.sh install"
|
||||||
|
echo
|
||||||
|
echo "Visit https://docs.docker.com/go/rootless/ to learn about rootless mode."
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo "To run the Docker daemon as a fully privileged service, but granting non-root"
|
||||||
|
echo "users access, refer to https://docs.docker.com/go/daemon-access/"
|
||||||
|
echo
|
||||||
|
echo "WARNING: Access to the remote API on a privileged Docker daemon is equivalent"
|
||||||
|
echo " to root access on the host. Refer to the 'Docker daemon attack surface'"
|
||||||
|
echo " documentation for details: https://docs.docker.com/go/attack-surface/"
|
||||||
|
echo
|
||||||
|
echo "================================================================================"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if this is a forked Linux distro
|
||||||
|
check_forked() {
|
||||||
|
|
||||||
|
# Check for lsb_release command existence, it usually exists in forked distros
|
||||||
|
if command_exists lsb_release; then
|
||||||
|
# Check if the `-u` option is supported
|
||||||
|
set +e
|
||||||
|
lsb_release -a -u > /dev/null 2>&1
|
||||||
|
lsb_release_exit_code=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Check if the command has exited successfully, it means we're in a forked distro
|
||||||
|
if [ "$lsb_release_exit_code" = "0" ]; then
|
||||||
|
# Print info about current distro
|
||||||
|
cat <<-EOF
|
||||||
|
You're using '$lsb_dist' version '$dist_version'.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Get the upstream release info
|
||||||
|
lsb_dist=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'id' | cut -d ':' -f 2 | tr -d '[:space:]')
|
||||||
|
dist_version=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'codename' | cut -d ':' -f 2 | tr -d '[:space:]')
|
||||||
|
|
||||||
|
# Print info about upstream distro
|
||||||
|
cat <<-EOF
|
||||||
|
Upstream release is '$lsb_dist' version '$dist_version'.
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
if [ -r /etc/debian_version ] && [ "$lsb_dist" != "ubuntu" ] && [ "$lsb_dist" != "raspbian" ]; then
|
||||||
|
if [ "$lsb_dist" = "osmc" ]; then
|
||||||
|
# OSMC runs Raspbian
|
||||||
|
lsb_dist=raspbian
|
||||||
|
else
|
||||||
|
# We're Debian and don't even know it!
|
||||||
|
lsb_dist=debian
|
||||||
|
fi
|
||||||
|
dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')"
|
||||||
|
case "$dist_version" in
|
||||||
|
13|14|forky)
|
||||||
|
dist_version="trixie"
|
||||||
|
;;
|
||||||
|
12)
|
||||||
|
dist_version="bookworm"
|
||||||
|
;;
|
||||||
|
11)
|
||||||
|
dist_version="bullseye"
|
||||||
|
;;
|
||||||
|
10)
|
||||||
|
dist_version="buster"
|
||||||
|
;;
|
||||||
|
9)
|
||||||
|
dist_version="stretch"
|
||||||
|
;;
|
||||||
|
8)
|
||||||
|
dist_version="jessie"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
do_install() {
|
||||||
|
echo "# Executing docker install script, commit: $SCRIPT_COMMIT_SHA"
|
||||||
|
|
||||||
|
if command_exists docker; then
|
||||||
|
cat >&2 <<-'EOF'
|
||||||
|
Warning: the "docker" command appears to already exist on this system.
|
||||||
|
|
||||||
|
If you already have Docker installed, this script can cause trouble, which is
|
||||||
|
why we're displaying this warning and provide the opportunity to cancel the
|
||||||
|
installation.
|
||||||
|
|
||||||
|
If you installed the current Docker package using this script and are using it
|
||||||
|
again to update Docker, you can ignore this message, but be aware that the
|
||||||
|
script resets any custom changes in the deb and rpm repo configuration
|
||||||
|
files to match the parameters passed to the script.
|
||||||
|
|
||||||
|
You may press Ctrl+C now to abort this script.
|
||||||
|
EOF
|
||||||
|
( set -x; sleep 20 )
|
||||||
|
fi
|
||||||
|
|
||||||
|
user="$(id -un 2>/dev/null || true)"
|
||||||
|
|
||||||
|
sh_c='sh -c'
|
||||||
|
if [ "$user" != 'root' ]; then
|
||||||
|
if command_exists sudo; then
|
||||||
|
sh_c='sudo -E sh -c'
|
||||||
|
elif command_exists su; then
|
||||||
|
sh_c='su -c'
|
||||||
|
else
|
||||||
|
cat >&2 <<-'EOF'
|
||||||
|
Error: this installer needs the ability to run commands as root.
|
||||||
|
We are unable to find either "sudo" or "su" available to make this happen.
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if is_dry_run; then
|
||||||
|
sh_c="echo"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# perform some very rudimentary platform detection
|
||||||
|
lsb_dist=$( get_distribution )
|
||||||
|
lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
|
||||||
|
if is_wsl; then
|
||||||
|
echo
|
||||||
|
echo "WSL DETECTED: We recommend using Docker Desktop for Windows."
|
||||||
|
echo "Please get Docker Desktop from https://www.docker.com/products/docker-desktop/"
|
||||||
|
echo
|
||||||
|
cat >&2 <<-'EOF'
|
||||||
|
|
||||||
|
You may press Ctrl+C now to abort this script.
|
||||||
|
EOF
|
||||||
|
( set -x; sleep 20 )
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$lsb_dist" in
|
||||||
|
|
||||||
|
ubuntu)
|
||||||
|
if command_exists lsb_release; then
|
||||||
|
dist_version="$(lsb_release --codename | cut -f2)"
|
||||||
|
fi
|
||||||
|
if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then
|
||||||
|
dist_version="$(. /etc/lsb-release && echo "$DISTRIB_CODENAME")"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
debian|raspbian)
|
||||||
|
dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')"
|
||||||
|
case "$dist_version" in
|
||||||
|
13)
|
||||||
|
dist_version="trixie"
|
||||||
|
;;
|
||||||
|
12)
|
||||||
|
dist_version="bookworm"
|
||||||
|
;;
|
||||||
|
11)
|
||||||
|
dist_version="bullseye"
|
||||||
|
;;
|
||||||
|
10)
|
||||||
|
dist_version="buster"
|
||||||
|
;;
|
||||||
|
9)
|
||||||
|
dist_version="stretch"
|
||||||
|
;;
|
||||||
|
8)
|
||||||
|
dist_version="jessie"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
|
||||||
|
centos|rhel)
|
||||||
|
if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
|
||||||
|
dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
if command_exists lsb_release; then
|
||||||
|
dist_version="$(lsb_release --release | cut -f2)"
|
||||||
|
fi
|
||||||
|
if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
|
||||||
|
dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Check if this is a forked Linux distro
|
||||||
|
check_forked
|
||||||
|
|
||||||
|
# Print deprecation warnings for distro versions that recently reached EOL,
|
||||||
|
# but may still be commonly used (especially LTS versions).
|
||||||
|
case "$lsb_dist.$dist_version" in
|
||||||
|
centos.8|centos.7|rhel.7)
|
||||||
|
deprecation_notice "$lsb_dist" "$dist_version"
|
||||||
|
;;
|
||||||
|
debian.buster|debian.stretch|debian.jessie)
|
||||||
|
deprecation_notice "$lsb_dist" "$dist_version"
|
||||||
|
;;
|
||||||
|
raspbian.buster|raspbian.stretch|raspbian.jessie)
|
||||||
|
deprecation_notice "$lsb_dist" "$dist_version"
|
||||||
|
;;
|
||||||
|
ubuntu.focal|ubuntu.bionic|ubuntu.xenial|ubuntu.trusty)
|
||||||
|
deprecation_notice "$lsb_dist" "$dist_version"
|
||||||
|
;;
|
||||||
|
ubuntu.oracular|ubuntu.mantic|ubuntu.lunar|ubuntu.kinetic|ubuntu.impish|ubuntu.hirsute|ubuntu.groovy|ubuntu.eoan|ubuntu.disco|ubuntu.cosmic)
|
||||||
|
deprecation_notice "$lsb_dist" "$dist_version"
|
||||||
|
;;
|
||||||
|
fedora.*)
|
||||||
|
if [ "$dist_version" -lt 41 ]; then
|
||||||
|
deprecation_notice "$lsb_dist" "$dist_version"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Run setup for each distro accordingly
|
||||||
|
case "$lsb_dist" in
|
||||||
|
ubuntu|debian|raspbian)
|
||||||
|
pre_reqs="ca-certificates curl"
|
||||||
|
apt_repo="deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] $DOWNLOAD_URL/linux/$lsb_dist $dist_version $CHANNEL"
|
||||||
|
(
|
||||||
|
if ! is_dry_run; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
$sh_c 'apt-get -qq update >/dev/null'
|
||||||
|
$sh_c "DEBIAN_FRONTEND=noninteractive apt-get -y -qq install $pre_reqs >/dev/null"
|
||||||
|
$sh_c 'install -m 0755 -d /etc/apt/keyrings'
|
||||||
|
$sh_c "curl -fsSL \"$DOWNLOAD_URL/linux/$lsb_dist/gpg\" -o /etc/apt/keyrings/docker.asc"
|
||||||
|
$sh_c "chmod a+r /etc/apt/keyrings/docker.asc"
|
||||||
|
$sh_c "echo \"$apt_repo\" > /etc/apt/sources.list.d/docker.list"
|
||||||
|
$sh_c 'apt-get -qq update >/dev/null'
|
||||||
|
)
|
||||||
|
|
||||||
|
if [ "$REPO_ONLY" = "1" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
pkg_version=""
|
||||||
|
if [ -n "$VERSION" ]; then
|
||||||
|
if is_dry_run; then
|
||||||
|
echo "# WARNING: VERSION pinning is not supported in DRY_RUN"
|
||||||
|
else
|
||||||
|
# Will work for incomplete versions IE (17.12), but may not actually grab the "latest" if in the test channel
|
||||||
|
pkg_pattern="$(echo "$VERSION" | sed 's/-ce-/~ce~.*/g' | sed 's/-/.*/g')"
|
||||||
|
search_command="apt-cache madison docker-ce | grep '$pkg_pattern' | head -1 | awk '{\$1=\$1};1' | cut -d' ' -f 3"
|
||||||
|
pkg_version="$($sh_c "$search_command")"
|
||||||
|
echo "INFO: Searching repository for VERSION '$VERSION'"
|
||||||
|
echo "INFO: $search_command"
|
||||||
|
if [ -z "$pkg_version" ]; then
|
||||||
|
echo
|
||||||
|
echo "ERROR: '$VERSION' not found amongst apt-cache madison results"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if version_gte "18.09"; then
|
||||||
|
search_command="apt-cache madison docker-ce-cli | grep '$pkg_pattern' | head -1 | awk '{\$1=\$1};1' | cut -d' ' -f 3"
|
||||||
|
echo "INFO: $search_command"
|
||||||
|
cli_pkg_version="=$($sh_c "$search_command")"
|
||||||
|
fi
|
||||||
|
pkg_version="=$pkg_version"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
(
|
||||||
|
pkgs="docker-ce${pkg_version%=}"
|
||||||
|
if version_gte "18.09"; then
|
||||||
|
# older versions didn't ship the cli and containerd as separate packages
|
||||||
|
pkgs="$pkgs docker-ce-cli${cli_pkg_version%=} containerd.io"
|
||||||
|
fi
|
||||||
|
if version_gte "20.10"; then
|
||||||
|
pkgs="$pkgs docker-compose-plugin docker-ce-rootless-extras$pkg_version"
|
||||||
|
fi
|
||||||
|
if version_gte "23.0"; then
|
||||||
|
pkgs="$pkgs docker-buildx-plugin"
|
||||||
|
fi
|
||||||
|
if version_gte "28.2"; then
|
||||||
|
pkgs="$pkgs docker-model-plugin"
|
||||||
|
fi
|
||||||
|
if ! is_dry_run; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
$sh_c "DEBIAN_FRONTEND=noninteractive apt-get -y -qq install $pkgs >/dev/null"
|
||||||
|
)
|
||||||
|
if [ "$NO_AUTOSTART" != "1" ]; then
|
||||||
|
start_docker_daemon
|
||||||
|
fi
|
||||||
|
echo_docker_as_nonroot
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
centos|fedora|rhel)
|
||||||
|
if [ "$(uname -m)" = "s390x" ]; then
|
||||||
|
echo "Effective v27.5, please consult RHEL distro statement for s390x support."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
repo_file_url="$DOWNLOAD_URL/linux/$lsb_dist/$REPO_FILE"
|
||||||
|
(
|
||||||
|
if ! is_dry_run; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
if command_exists dnf5; then
|
||||||
|
$sh_c "dnf -y -q --setopt=install_weak_deps=False install dnf-plugins-core"
|
||||||
|
$sh_c "dnf5 config-manager addrepo --overwrite --save-filename=docker-ce.repo --from-repofile='$repo_file_url'"
|
||||||
|
|
||||||
|
if [ "$CHANNEL" != "stable" ]; then
|
||||||
|
$sh_c "dnf5 config-manager setopt \"docker-ce-*.enabled=0\""
|
||||||
|
$sh_c "dnf5 config-manager setopt \"docker-ce-$CHANNEL.enabled=1\""
|
||||||
|
fi
|
||||||
|
$sh_c "dnf makecache"
|
||||||
|
elif command_exists dnf; then
|
||||||
|
$sh_c "dnf -y -q --setopt=install_weak_deps=False install dnf-plugins-core"
|
||||||
|
$sh_c "rm -f /etc/yum.repos.d/docker-ce.repo /etc/yum.repos.d/docker-ce-staging.repo"
|
||||||
|
$sh_c "dnf config-manager --add-repo $repo_file_url"
|
||||||
|
|
||||||
|
if [ "$CHANNEL" != "stable" ]; then
|
||||||
|
$sh_c "dnf config-manager --set-disabled \"docker-ce-*\""
|
||||||
|
$sh_c "dnf config-manager --set-enabled \"docker-ce-$CHANNEL\""
|
||||||
|
fi
|
||||||
|
$sh_c "dnf makecache"
|
||||||
|
else
|
||||||
|
$sh_c "yum -y -q install yum-utils"
|
||||||
|
$sh_c "rm -f /etc/yum.repos.d/docker-ce.repo /etc/yum.repos.d/docker-ce-staging.repo"
|
||||||
|
$sh_c "yum-config-manager --add-repo $repo_file_url"
|
||||||
|
|
||||||
|
if [ "$CHANNEL" != "stable" ]; then
|
||||||
|
$sh_c "yum-config-manager --disable \"docker-ce-*\""
|
||||||
|
$sh_c "yum-config-manager --enable \"docker-ce-$CHANNEL\""
|
||||||
|
fi
|
||||||
|
$sh_c "yum makecache"
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
|
||||||
|
if [ "$REPO_ONLY" = "1" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
pkg_version=""
|
||||||
|
if command_exists dnf; then
|
||||||
|
pkg_manager="dnf"
|
||||||
|
pkg_manager_flags="-y -q --best"
|
||||||
|
else
|
||||||
|
pkg_manager="yum"
|
||||||
|
pkg_manager_flags="-y -q"
|
||||||
|
fi
|
||||||
|
if [ -n "$VERSION" ]; then
|
||||||
|
if is_dry_run; then
|
||||||
|
echo "# WARNING: VERSION pinning is not supported in DRY_RUN"
|
||||||
|
else
|
||||||
|
if [ "$lsb_dist" = "fedora" ]; then
|
||||||
|
pkg_suffix="fc$dist_version"
|
||||||
|
else
|
||||||
|
pkg_suffix="el"
|
||||||
|
fi
|
||||||
|
pkg_pattern="$(echo "$VERSION" | sed 's/-ce-/\\\\.ce.*/g' | sed 's/-/.*/g').*$pkg_suffix"
|
||||||
|
search_command="$pkg_manager list --showduplicates docker-ce | grep '$pkg_pattern' | tail -1 | awk '{print \$2}'"
|
||||||
|
pkg_version="$($sh_c "$search_command")"
|
||||||
|
echo "INFO: Searching repository for VERSION '$VERSION'"
|
||||||
|
echo "INFO: $search_command"
|
||||||
|
if [ -z "$pkg_version" ]; then
|
||||||
|
echo
|
||||||
|
echo "ERROR: '$VERSION' not found amongst $pkg_manager list results"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if version_gte "18.09"; then
|
||||||
|
# older versions don't support a cli package
|
||||||
|
search_command="$pkg_manager list --showduplicates docker-ce-cli | grep '$pkg_pattern' | tail -1 | awk '{print \$2}'"
|
||||||
|
cli_pkg_version="$($sh_c "$search_command" | cut -d':' -f 2)"
|
||||||
|
fi
|
||||||
|
# Cut out the epoch and prefix with a '-'
|
||||||
|
pkg_version="-$(echo "$pkg_version" | cut -d':' -f 2)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
(
|
||||||
|
pkgs="docker-ce$pkg_version"
|
||||||
|
if version_gte "18.09"; then
|
||||||
|
# older versions didn't ship the cli and containerd as separate packages
|
||||||
|
if [ -n "$cli_pkg_version" ]; then
|
||||||
|
pkgs="$pkgs docker-ce-cli-$cli_pkg_version containerd.io"
|
||||||
|
else
|
||||||
|
pkgs="$pkgs docker-ce-cli containerd.io"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if version_gte "20.10"; then
|
||||||
|
pkgs="$pkgs docker-compose-plugin docker-ce-rootless-extras$pkg_version"
|
||||||
|
fi
|
||||||
|
if version_gte "23.0"; then
|
||||||
|
pkgs="$pkgs docker-buildx-plugin docker-model-plugin"
|
||||||
|
fi
|
||||||
|
if ! is_dry_run; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
$sh_c "$pkg_manager $pkg_manager_flags install $pkgs"
|
||||||
|
)
|
||||||
|
if [ "$NO_AUTOSTART" != "1" ]; then
|
||||||
|
start_docker_daemon
|
||||||
|
fi
|
||||||
|
echo_docker_as_nonroot
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
sles)
|
||||||
|
echo "Effective v27.5, please consult SLES distro statement for s390x support."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ -z "$lsb_dist" ]; then
|
||||||
|
if is_darwin; then
|
||||||
|
echo
|
||||||
|
echo "ERROR: Unsupported operating system 'macOS'"
|
||||||
|
echo "Please get Docker Desktop from https://www.docker.com/products/docker-desktop"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo "ERROR: Unsupported distribution '$lsb_dist'"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# wrapped up in a function so that we have some protection against only getting
|
||||||
|
# half the file during "curl | sh"
|
||||||
|
do_install
|
||||||
20
markup.yml
20
markup.yml
@@ -15,12 +15,12 @@ echo "╚═══════════════════════
|
|||||||
echo "╔═════════════════════════════════════════════════════════════╗
|
echo "╔═════════════════════════════════════════════════════════════╗
|
||||||
echo "║ ✅ SERVER_IP: 192.168.4.4 ║
|
echo "║ ✅ SERVER_IP: 192.168.4.4 ║
|
||||||
echo "║ ✅ SERVER_HOSTNAME: jasper ║
|
echo "║ ✅ SERVER_HOSTNAME: jasper ║
|
||||||
echo "║ ✅ DUCKDNS_SUBDOMAINS: kelinreij ║
|
echo "║ ✅ DUCKDNS_SUBDOMAINS: yourdomain ║
|
||||||
echo "║ ✅ DUCKDNS_TOKEN: 41ef7faa-fc93-41d2-a32f-340fd2b75b2f ║
|
echo "║ ✅ DUCKDNS_TOKEN: your-duckdns-token ║
|
||||||
echo "║ ✅ DOMAIN: kelinreij.duckdns.org ║
|
echo "║ ✅ DOMAIN: yourdomain.duckdns.org ║
|
||||||
echo "║ ✅ DEFAULT_USER: kelin ║
|
echo "║ ✅ DEFAULT_USER: admin ║
|
||||||
echo "║ ✅ DEFAULT_PASSWORD: Tiberi0u$ ║
|
echo "║ ✅ DEFAULT_PASSWORD: changeme ║
|
||||||
echo "║ ✅ DEFAULT_EMAIL: kelinshomelab@gmail.com ║
|
echo "║ ✅ DEFAULT_EMAIL: admin@example.com ║
|
||||||
echo "╚═════════════════════════════════════════════════════════════╝
|
echo "╚═════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
echo "╔═════════════════════════════════════════════════════════════╗
|
echo "╔═════════════════════════════════════════════════════════════╗
|
||||||
@@ -31,16 +31,16 @@ echo "╔═══════════════════════
|
|||||||
echo "║ Deployment Complete! ║
|
echo "║ Deployment Complete! ║
|
||||||
echo "║ SSL Certificates may take a few minutes to be issued. ║
|
echo "║ SSL Certificates may take a few minutes to be issued. ║
|
||||||
echo "║ ║
|
echo "║ ║
|
||||||
echo "║ https://dockge.kelinreij.duckdns.org ║
|
echo "║ https://dockge.yourdomain.duckdns.org ║
|
||||||
echo "║ http://192.168.4.4:5001 ║
|
echo "║ http://192.168.4.4:5001 ║
|
||||||
echo "║ ║
|
echo "║ ║
|
||||||
echo "║ https://homepage.kelinreij.duckdns.org ║
|
echo "║ https://homepage.yourdomain.duckdns.org ║
|
||||||
echo "║ http://192.168.4.4:3003 ║
|
echo "║ http://192.168.4.4:3003 ║
|
||||||
echo "║ ║
|
echo "║ ║
|
||||||
echo "║ https://authelia.kelinreij.duckdns.org ║
|
echo "║ https://authelia.yourdomain.duckdns.org ║
|
||||||
echo "║ http://192.168.4.4:9091 ║
|
echo "║ http://192.168.4.4:9091 ║
|
||||||
echo "║ ║
|
echo "║ ║
|
||||||
echo "║ https://traefik.kelinreij.duckdns.org ║
|
echo "║ https://traefik.yourdomain.duckdns.org ║
|
||||||
echo "║ http://192.168.4.4:8080 ║
|
echo "║ http://192.168.4.4:8080 ║
|
||||||
echo "║ ║
|
echo "║ ║
|
||||||
echo "╚═════════════════════════════════════════════════════════════╝
|
echo "╚═════════════════════════════════════════════════════════════╝
|
||||||
|
|||||||
@@ -874,6 +874,26 @@ deploy_core() {
|
|||||||
sudo chown "$ACTUAL_USER:$ACTUAL_USER" /opt/stacks/core/docker-compose.yml
|
sudo chown "$ACTUAL_USER:$ACTUAL_USER" /opt/stacks/core/docker-compose.yml
|
||||||
sudo chown "$ACTUAL_USER:$ACTUAL_USER" /opt/stacks/core/.env
|
sudo chown "$ACTUAL_USER:$ACTUAL_USER" /opt/stacks/core/.env
|
||||||
|
|
||||||
|
# Fix multi-line secrets in .env file (merge split lines)
|
||||||
|
debug_log "Fixing multi-line secrets in .env file"
|
||||||
|
python3 << 'PYFIX'
|
||||||
|
import sys
|
||||||
|
with open('/opt/stacks/core/.env', 'r') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
new_lines = []
|
||||||
|
i = 0
|
||||||
|
while i < len(lines):
|
||||||
|
if any(k in lines[i] for k in ['AUTHELIA_JWT_SECRET=', 'AUTHELIA_SESSION_SECRET=', 'AUTHELIA_STORAGE_ENCRYPTION_KEY=']):
|
||||||
|
if i + 1 < len(lines) and '=' not in lines[i+1] and lines[i+1].strip() and not lines[i+1].strip().startswith('#'):
|
||||||
|
new_lines.append(lines[i].rstrip('\n') + lines[i+1].lstrip())
|
||||||
|
i += 2
|
||||||
|
continue
|
||||||
|
new_lines.append(lines[i])
|
||||||
|
i += 1
|
||||||
|
with open('/opt/stacks/core/.env', 'w') as f:
|
||||||
|
f.writelines(new_lines)
|
||||||
|
PYFIX
|
||||||
|
|
||||||
# Escape $ characters in password hashes to prevent Docker Compose variable substitution
|
# Escape $ characters in password hashes to prevent Docker Compose variable substitution
|
||||||
sed -i '/^AUTHELIA_ADMIN_PASSWORD_HASH=/ s/\$/\\$/g' /opt/stacks/core/.env
|
sed -i '/^AUTHELIA_ADMIN_PASSWORD_HASH=/ s/\$/\\$/g' /opt/stacks/core/.env
|
||||||
|
|
||||||
@@ -960,13 +980,9 @@ deploy_core() {
|
|||||||
|
|
||||||
# Remove invalid session.cookies section from Authelia config (not supported in v4.37.5)
|
# Remove invalid session.cookies section from Authelia config (not supported in v4.37.5)
|
||||||
debug_log "Removing invalid session.cookies section from Authelia config"
|
debug_log "Removing invalid session.cookies section from Authelia config"
|
||||||
sed -i '/^ cookies:/,/^$/d' /opt/stacks/core/authelia/configuration.yml
|
sed -i '/^ cookies:/,/^$/d' /opt/stacks/core/authelia/config/configuration.yml
|
||||||
|
|
||||||
# Move config files to the correct location for Docker mount
|
# Ensure proper ownership of Authelia files
|
||||||
debug_log "Moving Authelia config files to config directory"
|
|
||||||
mkdir -p /opt/stacks/core/authelia/config
|
|
||||||
mv /opt/stacks/core/authelia/configuration.yml /opt/stacks/core/authelia/config/
|
|
||||||
mv /opt/stacks/core/authelia/users_database.yml /opt/stacks/core/authelia/config/
|
|
||||||
sudo chown -R "$ACTUAL_USER:$ACTUAL_USER" /opt/stacks/core/authelia
|
sudo chown -R "$ACTUAL_USER:$ACTUAL_USER" /opt/stacks/core/authelia
|
||||||
|
|
||||||
# Generate shared CA for multi-server TLS
|
# Generate shared CA for multi-server TLS
|
||||||
|
|||||||
Reference in New Issue
Block a user