Compare commits

...

46 Commits

Author SHA1 Message Date
272250d4c2 Add hourly restart sidecar for invidious and companion
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 6s
Deploy Stacks / deploy-dev (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 11:38:06 -05:00
9ad35b77d8 Point meshmon.ghost.tel to ubuntu-dev instance
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 14s
Deploy Stacks / deploy-dev (push) Has been cancelled
The meshmonitor container is running on ubuntu-dev, not docker-dev.
Having both instances fight over the same Meshtastic node TCP connection
was causing repeated ECONNRESET disconnects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:58:07 -05:00
077d40321d Point tlc routes to ubuntu-dev
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 13s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-02-07 08:57:56 -05:00
adfeb664c9 Disable tlc.ghost.tel route
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 6s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-02-07 08:51:43 -05:00
1463bbced1 Route sdr.uplink.tel and update radio backend
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 14s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-02-05 22:36:37 -05:00
eed6196da5 Move Traefik file routes to Docker labels
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 6s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-02-05 22:04:28 -05:00
0970e97a8f Switch invidious to master branch for API 400 fix
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 8s
Deploy Stacks / deploy-dev (push) Has been cancelled
The fix for YouTube API 400 errors (PR #5614) was merged Feb 3, 2026
but hasn't been included in a tagged release yet. Using master tag
to get the fix now.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 21:44:59 -05:00
53332d416a Trigger GitOps via traefik config touch
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 3s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-02-05 20:36:09 -05:00
ca456e8ee6 Trigger GitOps run 2026-02-05 20:33:02 -05:00
c616d63083 Avoid SIGPIPE in workflow container listing 2026-02-05 20:02:04 -05:00
deb2403bad Remove gitea file-provider route
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 10s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-02-05 19:56:59 -05:00
0cbe7d3862 Use ubuntu-prod hostname in Traefik upstreams
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 0s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-02-05 19:21:55 -05:00
2a1d78fa69 Add fonts to perilous container for favicon rendering
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
Sharp requires fontconfig and fonts to render SVG text elements.
Added ttf-dejavu for the dynamically generated favicon.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:41:01 -05:00
6b5fcb2f61 Add homepage stack for ghost.tel
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
Static nginx container serving the main ghost.tel homepage.
Includes restart policy and /watch redirect to invidious.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 10:51:08 -05:00
d6a3d9a3f6 Add detailed access logging and Prometheus metrics
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
- accessLog: field filtering to drop sensitive headers (Authorization)
  while keeping useful ones (User-Agent, Content-Type, Referer)
- metrics: Prometheus endpoint with latency buckets (0.1, 0.3, 1.2, 5.0s)

Aligned with core's observability config.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 10:17:19 -05:00
c5e416d31c Add global HTTP to HTTPS redirect
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
All HTTP traffic now redirects to HTTPS at the entrypoint level,
eliminating the need for per-service redirect middleware.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 10:11:32 -05:00
a4dfbc715f Add astro stack for e.field.ghost.tel
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-01-24 22:55:12 -05:00
b14015b12f Adjust healthchecks and dev tooling
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 2s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-01-22 14:19:36 -05:00
6e22713454 Remove sequela.uk domains from routing rules
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
The sequela.uk domain doesn't have DNS configured, causing ACME
certificate generation to fail. Removed from wikijs and matomo
routing rules.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 10:49:55 -05:00
a0b6dcbdc3 Fix analoggallery build context to use main branch
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
The analogGallery repo uses 'main' not 'master' as default branch.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 10:40:33 -05:00
e944ac8b48 Add analoggallery-public stack, update traefik routing
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 11s
Deploy Stacks / deploy-dev (push) Has been cancelled
- Add analoggallery-public stack for analog.uplink.tel
- Update uplink.yml: remove routes now handled by Docker labels
  (nitter, freshrss, rsshub, searx, analog)
- Update sequela.yml: remove routes now handled by Docker labels
  (wiki.sequela.tel, matomo.sequela.tel)
- File routes now only contain external proxies (docker-public for
  invidious.uplink.tel, radio.uplink.tel)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 10:38:59 -05:00
2609411fd8 Fix authentik postgres version to match data
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 3s
Deploy Stacks / deploy-dev (push) Has been cancelled
Pin postgres to 12-alpine to match existing data directory
that was initialized with PostgreSQL 12.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 10:19:40 -05:00
477e22d5a6 Update GitOps workflow to respect stack-type labels
- deploy-prod (master → ubuntu-prod): Only deploys prod and public stacks
- deploy-dev (dev → ubuntu-dev): Only deploys dev-only stacks
- Skips stacks without stack-type labels (with warning)
- Fixed: Only create .env from template if .env doesn't exist

This prevents dev-only experimental stacks from being deployed to
production, even if they're in the master branch.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 10:07:26 -05:00
32e7536fd8 Add stack-type labels and public service stacks
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 6s
Deploy Stacks / deploy-dev (push) Has been cancelled
Add com.ghost.tel/stack-type labels to all stacks:
- prod (17): Production services from core
- dev-only (11): Experimental/device-specific services
- public (8): Public-facing services (uplink.tel, sequela.tel)

New public stacks from docker-public:
- nitter-public: Nitter instance for uplink.tel
- freshrss-public: FreshRSS for uplink.tel
- rsshub-public: RSSHub for uplink.tel
- searx-public: SearXNG for uplink.tel
- wikijs-public: Wiki.js for sequela.tel
- matomo-public: Matomo analytics for sequela.tel

Also fixes:
- Remove obsolete 'version' key from compose files
- Fix snowflake to remove duplicate watchtower service
- Standardize compose file formatting

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 10:02:37 -05:00
7704551668 Fix zerotier UI port and traefik basicAuth mount
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 2s
Deploy Stacks / deploy-dev (push) Has been cancelled
- zerotier: Change exposed port from 3180 to 3000 (actual UI port)
- zerotier: Add loadbalancer.server.port label for traefik
- traefik: Add basicAuth volume mount for dashboard-auth middleware
- test-services.sh: Fix registry URL to use /v2/ endpoint

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 22:48:31 -05:00
f949992127 Update registry to include UI service
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1m3s
Deploy Stacks / deploy-dev (push) Has been cancelled
- Add registry-ui container with dockerhub.${DOMAIN} hostname
- Registry API available at registry.${DOMAIN}
- UI available at dockerhub.${DOMAIN}/ui

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 20:37:09 -05:00
b2971e1f89 Fix smokeping hostname to match existing DNS record
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 7s
Deploy Stacks / deploy-dev (push) Has been cancelled
smoke.ghost.tel exists, smokeping.ghost.tel does not.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 15:59:05 -05:00
c91a89a33e Add service URL test script
Tests all configured service URLs and reports HTTP status.
Useful for verifying deployments and identifying routing issues.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 15:52:58 -05:00
e5b14eee4e Fix HostRegexp syntax for Traefik v3
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
Traefik v3 uses raw regex syntax instead of v2's {name:pattern} format.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 15:50:35 -05:00
6559870e06 Move perilous traefik routing from file provider to Docker labels
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
- Add traefik labels to perilous docker-compose.yml for web and code-server
- Remove stacks/traefik/conf.d/perilous.yml (no longer needed)
- Changed from host ports to expose (traefik routes directly to container)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 15:46:55 -05:00
db0745e57d Migrate perilous to ubuntu-prod
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
- Update traefik route to use Docker container names instead of host IPs
- Update Dockerfile to build full app with sharp, ejs, marked dependencies
- Simplify docker-compose.yml (remove traefik labels, use file provider routing)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 15:38:14 -05:00
cb9a8fa46b Add uplink.tel and sequela.tel routing via ubuntu-prod proxy
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
- Add uplink.yml: Routes nitter, invidious, searx, freshrss, rsshub, radio
  through ubuntu-prod to docker-public backend
- Add sequela.yml: Routes wiki and matomo through ubuntu-prod to docker-public
- Update traefik.yml: Add proxyProtocol insecure:true for VPS HAProxy
  send-proxy compatibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 14:52:04 -05:00
382292c52f Add perilous.dev routing config
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 15s
Deploy Stacks / deploy-dev (push) Has been cancelled
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 13:22:33 -05:00
aa2646c907 Trigger traefik config sync
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-01-21 12:35:07 -05:00
f46817fa7a Add traefik routing configs to GitOps
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
Sync all conf.d routing configs from core:
- authentik.yml - routes to ubuntu-prod:9000
- gitea.yml - routes to ubuntu-prod:3001
- middlewares.yaml - forward-auth, redirects, security headers
- dynamic.yml, library.yaml, meshmon.yaml, minecraft.yaml
- radio.yml, spider.yml, tlc.yml, wille.yaml

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 11:43:17 -05:00
244794d15f Sync Gitea and Authentik configs with production
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
- Gitea: Add port 3001:3000 for external access
- Gitea: Add GITEA_RUNNER_LABELS=ubuntu-prod:host for runner
- Authentik: Add port 9000:9000 for external access

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 10:58:31 -05:00
e2372fd67a Trigger deploy workflow
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 4s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-01-21 00:12:18 -05:00
68660717f2 Test ubuntu-prod runner 2026-01-21 00:11:37 -05:00
b19a0aa195 Test runner on ubuntu-prod 2026-01-21 00:08:54 -05:00
5388ef16d7 Trigger Gitea deploy to ubuntu-prod
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 1s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-01-20 20:03:54 -05:00
195c6860b5 Remove trigger file
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 4s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-01-20 13:06:20 -05:00
ba27db032e Fix invidious companion key docs (must be 16 chars) 2026-01-20 13:06:11 -05:00
5807713e22 Trigger invidious deploy
Some checks failed
Deploy Stacks / deploy-prod (push) Successful in 2s
Deploy Stacks / deploy-dev (push) Has been cancelled
2026-01-20 13:02:02 -05:00
55e1e0a400 Merge branch 'dev'
Some checks failed
Deploy Stacks / deploy-prod (push) Failing after 8s
Deploy Stacks / deploy-dev (push) Has been cancelled
# Conflicts:
#	.gitea/workflows/deploy.yml
2026-01-20 12:52:38 -05:00
9f61b06592 Update invidious stack to use companion approach
- Replace inv_sig_helper with invidious-companion for better YouTube API handling
- Add healthcheck for main container
- Add resource limits for all containers
- Add SQL init scripts for fresh database setup
- Update README with invidious secrets documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 12:52:19 -05:00
d7b65f9f6d Enable dev branch deploys 2025-12-31 19:34:43 -05:00
63 changed files with 1062 additions and 157 deletions

View File

@@ -27,15 +27,32 @@ jobs:
STACKS=$(git diff --name-only HEAD~1 HEAD 2>/dev/null | grep '^stacks/' | cut -d'/' -f2 | sort -u || echo "") STACKS=$(git diff --name-only HEAD~1 HEAD 2>/dev/null | grep '^stacks/' | cut -d'/' -f2 | sort -u || echo "")
if [ -z "$STACKS" ]; then if [ -z "$STACKS" ]; then
echo "No stacks changed, deploying all..." echo "No stacks changed, checking all stacks..."
STACKS=$(ls stacks/) STACKS=$(ls stacks/)
fi fi
echo "Deploying: $STACKS" echo "Evaluating stacks: $STACKS"
echo ""
for stack in $STACKS; do for stack in $STACKS; do
COMPOSE_FILE="stacks/$stack/docker-compose.yml"
# Check stack-type label
STACK_TYPE=$(grep -o 'stack-type=[^"]*' "$COMPOSE_FILE" 2>/dev/null | head -1 | cut -d= -f2)
if [ -z "$STACK_TYPE" ]; then
echo "⚠️ SKIP $stack - no stack-type label found"
continue
fi
# On prod, only deploy 'prod' and 'public' stacks
if [ "$STACK_TYPE" != "prod" ] && [ "$STACK_TYPE" != "public" ]; then
echo "⏭️ SKIP $stack - stack-type=$STACK_TYPE (not for prod)"
continue
fi
echo "==========================================" echo "=========================================="
echo "Deploying $stack..." echo "Deploying $stack (stack-type=$STACK_TYPE)..."
echo "==========================================" echo "=========================================="
STACK_DIR="${{ env.STACKS_DIR }}/$stack" STACK_DIR="${{ env.STACKS_DIR }}/$stack"
@@ -44,9 +61,10 @@ jobs:
# Copy files # Copy files
sudo cp -r stacks/$stack/* "$STACK_DIR/" sudo cp -r stacks/$stack/* "$STACK_DIR/"
# Create .env from template if exists # Create .env from template if .env doesn't exist
if [ -f "$STACK_DIR/.env.template" ]; then if [ -f "$STACK_DIR/.env.template" ] && [ ! -f "$STACK_DIR/.env" ]; then
sudo envsubst < "$STACK_DIR/.env.template" > "$STACK_DIR/.env" echo "Creating .env from template..."
sudo sh -c "DOMAIN=$DOMAIN envsubst < '$STACK_DIR/.env.template' > '$STACK_DIR/.env'"
fi fi
# Deploy # Deploy
@@ -59,11 +77,11 @@ jobs:
done done
- name: Show running containers - name: Show running containers
run: sudo docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | head -20 run: sudo docker ps --format "table {{.Names}}\t{{.Status}}" | head -30 || true
deploy-dev: deploy-dev:
if: ${{ github.ref == 'refs/heads/dev' }} if: ${{ github.ref == 'refs/heads/dev' }}
runs-on: ubuntu-dev runs-on: ubuntu-dev:host
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -77,15 +95,32 @@ jobs:
STACKS=$(git diff --name-only HEAD~1 HEAD 2>/dev/null | grep '^stacks/' | cut -d'/' -f2 | sort -u || echo "") STACKS=$(git diff --name-only HEAD~1 HEAD 2>/dev/null | grep '^stacks/' | cut -d'/' -f2 | sort -u || echo "")
if [ -z "$STACKS" ]; then if [ -z "$STACKS" ]; then
echo "No stacks changed, deploying all..." echo "No stacks changed, checking all stacks..."
STACKS=$(ls stacks/) STACKS=$(ls stacks/)
fi fi
echo "Deploying: $STACKS" echo "Evaluating stacks: $STACKS"
echo ""
for stack in $STACKS; do for stack in $STACKS; do
COMPOSE_FILE="stacks/$stack/docker-compose.yml"
# Check stack-type label
STACK_TYPE=$(grep -o 'stack-type=[^"]*' "$COMPOSE_FILE" 2>/dev/null | head -1 | cut -d= -f2)
if [ -z "$STACK_TYPE" ]; then
echo "⚠️ SKIP $stack - no stack-type label found"
continue
fi
# On dev, only deploy 'dev-only' stacks
if [ "$STACK_TYPE" != "dev-only" ]; then
echo "⏭️ SKIP $stack - stack-type=$STACK_TYPE (not for dev)"
continue
fi
echo "==========================================" echo "=========================================="
echo "Deploying $stack..." echo "Deploying $stack (stack-type=$STACK_TYPE)..."
echo "==========================================" echo "=========================================="
STACK_DIR="${{ env.STACKS_DIR }}/$stack" STACK_DIR="${{ env.STACKS_DIR }}/$stack"
@@ -94,9 +129,10 @@ jobs:
# Copy files # Copy files
sudo cp -r stacks/$stack/* "$STACK_DIR/" sudo cp -r stacks/$stack/* "$STACK_DIR/"
# Create .env from template if exists # Create .env from template if .env doesn't exist
if [ -f "$STACK_DIR/.env.template" ]; then if [ -f "$STACK_DIR/.env.template" ] && [ ! -f "$STACK_DIR/.env" ]; then
sudo envsubst < "$STACK_DIR/.env.template" > "$STACK_DIR/.env" echo "Creating .env from template..."
sudo sh -c "DOMAIN=$DOMAIN envsubst < '$STACK_DIR/.env.template' > '$STACK_DIR/.env'"
fi fi
# Deploy # Deploy
@@ -109,4 +145,4 @@ jobs:
done done
- name: Show running containers - name: Show running containers
run: sudo docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | head -20 run: sudo docker ps --format "table {{.Names}}\t{{.Status}}" | head -30 || true

View File

@@ -18,6 +18,7 @@ stacks/
├── perilous/ # Blog/website ├── perilous/ # Blog/website
├── ramz/ # Go web app ├── ramz/ # Go web app
├── bookclub/ # Form mailer ├── bookclub/ # Form mailer
├── invidious/ # YouTube frontend
├── watchtower/ # Auto container updates ├── watchtower/ # Auto container updates
├── dockge/ # Container management UI ├── dockge/ # Container management UI
└── smokeping/ # Network monitoring └── smokeping/ # Network monitoring
@@ -96,6 +97,13 @@ Set these in Gitea → Repository → Settings → Actions → Secrets:
|--------|-------------| |--------|-------------|
| `PERILOUS_CODE_SERVER_PASSWORD` | Code-server password | | `PERILOUS_CODE_SERVER_PASSWORD` | Code-server password |
### Invidious
| Secret | Description |
|--------|-------------|
| `INVIDIOUS_DB_PASSWORD` | PostgreSQL password |
| `INVIDIOUS_HMAC_KEY` | Generate: `openssl rand -hex 16` |
| `INVIDIOUS_COMPANION_KEY` | **Must be exactly 16 chars**: `openssl rand -base64 12` |
## Runner Setup ## Runner Setup
The workflow requires a self-hosted runner on the prod server: The workflow requires a self-hosted runner on the prod server:
@@ -139,3 +147,5 @@ act_runner daemon
``` ```
4. Then deploy other stacks as needed. 4. Then deploy other stacks as needed.
# Runner test Wed 21 Jan 2026 12:08:53 AM EST
# Runner test 2 Wed 21 Jan 2026 12:11:37 AM EST

96
scripts/test-services.sh Executable file
View File

@@ -0,0 +1,96 @@
#!/bin/bash
# Test all service URLs to verify they're responding
# Note: Some services may not be deployed yet - failures indicate either
# the service isn't running or routing isn't configured
DOMAIN="ghost.tel"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
# All service URLs
URLS=(
# ghost.tel services
"https://authentik.$DOMAIN"
"https://bookclub.$DOMAIN"
"https://brain.$DOMAIN"
"https://change.$DOMAIN"
"https://dockge.$DOMAIN"
"https://files.$DOMAIN"
"https://ghost.$DOMAIN"
"https://gitea.$DOMAIN"
"https://gollum.$DOMAIN"
"https://inv.$DOMAIN"
"https://memento.$DOMAIN"
"https://radicale.$DOMAIN"
"https://registry.$DOMAIN/v2/"
"https://smoke.$DOMAIN"
"https://syncthing.$DOMAIN"
"https://wallabag.$DOMAIN"
"https://xb.$DOMAIN"
"https://zerotierui.$DOMAIN"
# perilous.dev
"https://perilous.dev"
"https://www.perilous.dev"
"https://cs.perilous.dev"
"https://forest.perilous.dev"
"https://chapel.perilous.dev"
# uplink.tel (proxied via docker-public)
"https://nitter.uplink.tel"
"https://invidious.uplink.tel"
"https://searx.uplink.tel"
"https://freshrss.uplink.tel"
"https://rsshub.uplink.tel"
"https://radio.uplink.tel"
# sequela.tel (proxied via docker-public)
"https://wiki.sequela.tel"
"https://matomo.sequela.tel"
# Other domains
"https://spider.ghost.tel"
"https://tlc.ghost.tel"
"https://thislittlecorner.net"
"https://parker.ramz.cc"
)
echo "Testing ${#URLS[@]} service URLs..."
echo ""
PASS=0
FAIL=0
for url in "${URLS[@]}"; do
# Get HTTP status code with 5 second timeout
status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$url" 2>/dev/null)
if [[ -z "$status" || "$status" == "000" ]]; then
echo -e "${RED}FAIL${NC} $url - Connection failed/timeout"
((FAIL++))
elif [[ "$status" =~ ^[23] ]]; then
echo -e "${GREEN}PASS${NC} $url - HTTP $status"
((PASS++))
elif [[ "$status" =~ ^4 ]]; then
# 401/403 might be expected for auth-protected services
if [[ "$status" == "401" || "$status" == "403" ]]; then
echo -e "${YELLOW}AUTH${NC} $url - HTTP $status (auth required)"
((PASS++))
else
echo -e "${RED}FAIL${NC} $url - HTTP $status"
((FAIL++))
fi
else
echo -e "${RED}FAIL${NC} $url - HTTP $status"
((FAIL++))
fi
done
echo ""
echo "----------------------------------------"
echo -e "Results: ${GREEN}$PASS passed${NC}, ${RED}$FAIL failed${NC}"
exit $FAIL

View File

@@ -0,0 +1,26 @@
services:
gallery:
build:
context: https://gitea.ghost.tel/knight/analogGallery.git#main
container_name: analoggallery
restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=public"
- "traefik.enable=true"
- "traefik.http.routers.analoggallery.entrypoints=https"
- "traefik.http.routers.analoggallery.rule=Host(`analog.uplink.tel`)"
- "traefik.http.routers.analoggallery.tls.certresolver=http"
- "traefik.http.services.analoggallery.loadbalancer.server.port=3000"
environment:
- NODE_ENV=production
volumes:
- ./images:/app/images
- ./images.json:/app/images.json
expose:
- "3000"
networks:
- web
networks:
web:
external: true

View File

@@ -0,0 +1 @@
DOMAIN=${DOMAIN}

View File

@@ -0,0 +1,23 @@
services:
astro:
image: nginx:alpine
container_name: astro
restart: unless-stopped
expose:
- 80
volumes:
- ./dist:/usr/share/nginx/html:ro
- ./nginx-cors.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- web
labels:
- "com.ghost.tel/stack-type=public"
- "traefik.enable=true"
- "traefik.http.routers.astro.entrypoints=https"
- "traefik.http.routers.astro.rule=Host(`e.field.${DOMAIN}`)"
- "traefik.http.routers.astro.tls.certresolver=http"
- "traefik.http.services.astro.loadbalancer.server.port=80"
networks:
web:
external: true

View File

@@ -0,0 +1,27 @@
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
# CORS configuration
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
# Handle preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
try_files $uri $uri/ =404;
}
}

View File

@@ -3,6 +3,8 @@ services:
image: ghcr.io/goauthentik/server:latest image: ghcr.io/goauthentik/server:latest
container_name: authentik-server container_name: authentik-server
restart: unless-stopped restart: unless-stopped
ports:
- "9000:9000"
command: server command: server
environment: environment:
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY} AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
@@ -23,11 +25,16 @@ services:
- web - web
- default - default
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.authentik.entrypoints=https" - "traefik.http.routers.authentik.entrypoints=https"
- "traefik.http.routers.authentik.rule=Host(`authentik.${DOMAIN}`)" - "traefik.http.routers.authentik.rule=Host(`authentik.${DOMAIN}`)"
- "traefik.http.routers.authentik.tls.certresolver=http" - "traefik.http.routers.authentik.tls.certresolver=http"
- "traefik.http.services.authentik.loadbalancer.server.port=9000" - "traefik.http.services.authentik.loadbalancer.server.port=9000"
- "traefik.http.routers.authentik-outpost.entrypoints=https"
- "traefik.http.routers.authentik-outpost.rule=HostRegexp(`{subdomain:[a-z0-9]+}.ghost.tel`) && PathPrefix(`/outpost.goauthentik.io/`)"
- "traefik.http.routers.authentik-outpost.service=authentik"
- "traefik.http.routers.authentik-outpost.tls.certresolver=http"
worker: worker:
image: ghcr.io/goauthentik/server:latest image: ghcr.io/goauthentik/server:latest
@@ -52,7 +59,7 @@ services:
- redis - redis
postgresql: postgresql:
image: postgres:15-alpine image: postgres:12-alpine
container_name: authentik-postgres container_name: authentik-postgres
restart: unless-stopped restart: unless-stopped
environment: environment:

View File

@@ -6,6 +6,7 @@ services:
env_file: env_file:
- .env - .env
labels: labels:
- "com.ghost.tel/stack-type=dev-only"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.form-mailer.rule=Host(`bookclub.${DOMAIN}`)" - "traefik.http.routers.form-mailer.rule=Host(`bookclub.${DOMAIN}`)"
- "traefik.http.routers.form-mailer.entrypoints=https" - "traefik.http.routers.form-mailer.entrypoints=https"

View File

@@ -11,11 +11,12 @@ services:
networks: networks:
- web - web
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.brain.entrypoints=https" - "traefik.http.routers.brain.entrypoints=https"
- "traefik.http.routers.brain.rule=Host(`brain.${DOMAIN}`)" - "traefik.http.routers.brain.rule=Host(`brain.${DOMAIN}`)"
- "traefik.http.routers.brain.tls.certresolver=http" - "traefik.http.routers.brain.tls.certresolver=http"
- "traefik.http.routers.brain.middlewares=auth@file" - "traefik.http.routers.brain.middlewares=auth@docker"
sftp: sftp:
image: atmoz/sftp image: atmoz/sftp

View File

@@ -13,11 +13,12 @@ services:
networks: networks:
- web - web
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.changedetection.entrypoints=https" - "traefik.http.routers.changedetection.entrypoints=https"
- "traefik.http.routers.changedetection.rule=Host(`change.${DOMAIN}`)" - "traefik.http.routers.changedetection.rule=Host(`change.${DOMAIN}`)"
- "traefik.http.routers.changedetection.tls.certresolver=http" - "traefik.http.routers.changedetection.tls.certresolver=http"
- "traefik.http.routers.changedetection.middlewares=auth@file" - "traefik.http.routers.changedetection.middlewares=auth@docker"
depends_on: depends_on:
- playwright-chrome - playwright-chrome

View File

@@ -4,7 +4,7 @@ services:
container_name: dockge container_name: dockge
restart: unless-stopped restart: unless-stopped
ports: ports:
- 5001:5001 - 5002:5001
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
- ./data:/app/data - ./data:/app/data
@@ -14,6 +14,7 @@ services:
networks: networks:
- web - web
labels: labels:
- "com.ghost.tel/stack-type=dev-only"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.dockge.rule=Host(`dockge.${DOMAIN}`)" - "traefik.http.routers.dockge.rule=Host(`dockge.${DOMAIN}`)"
- "traefik.http.routers.dockge.entrypoints=https" - "traefik.http.routers.dockge.entrypoints=https"

View File

@@ -11,6 +11,7 @@ services:
networks: networks:
- web - web
labels: labels:
- "com.ghost.tel/stack-type=dev-only"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.filebrowser.entrypoints=https" - "traefik.http.routers.filebrowser.entrypoints=https"
- "traefik.http.routers.filebrowser.rule=Host(`files.${DOMAIN}`)" - "traefik.http.routers.filebrowser.rule=Host(`files.${DOMAIN}`)"

View File

@@ -0,0 +1,23 @@
services:
freshrss:
image: lscr.io/linuxserver/freshrss:latest
container_name: freshrss
restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=public"
- "traefik.enable=true"
- "traefik.http.routers.freshrss.entrypoints=https"
- "traefik.http.routers.freshrss.rule=Host(`freshrss.uplink.tel`)"
- "traefik.http.routers.freshrss.tls.certresolver=http"
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
volumes:
- ./config:/config
networks:
- web
networks:
web:
external: true

View File

@@ -18,6 +18,7 @@ services:
volumes: volumes:
- ./content:/var/lib/ghost/content - ./content:/var/lib/ghost/content
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.ghost.entrypoints=https" - "traefik.http.routers.ghost.entrypoints=https"
- "traefik.http.routers.ghost.rule=Host(`ghost.${DOMAIN}`)" - "traefik.http.routers.ghost.rule=Host(`ghost.${DOMAIN}`)"

0
stacks/gitea/.gitkeep Normal file
View File

1
stacks/gitea/.trigger Normal file
View File

@@ -0,0 +1 @@
# Trigger deploy 1768957434

View File

@@ -10,6 +10,7 @@ services:
- "22" - "22"
ports: ports:
- "2245:22" - "2245:22"
- "3001:3000"
depends_on: depends_on:
- db - db
environment: environment:
@@ -21,6 +22,7 @@ services:
- default - default
- web - web
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.gitea.entrypoints=https" - "traefik.http.routers.gitea.entrypoints=https"
- "traefik.http.routers.gitea.rule=Host(`gitea.${DOMAIN}`)" - "traefik.http.routers.gitea.rule=Host(`gitea.${DOMAIN}`)"
@@ -52,6 +54,7 @@ services:
environment: environment:
- GITEA_INSTANCE_URL=https://gitea.${DOMAIN} - GITEA_INSTANCE_URL=https://gitea.${DOMAIN}
- GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_TOKEN} - GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_TOKEN}
- GITEA_RUNNER_LABELS=ubuntu-prod:host
networks: networks:
web: web:

View File

@@ -13,11 +13,12 @@ services:
networks: networks:
- web - web
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.gollum.entrypoints=https" - "traefik.http.routers.gollum.entrypoints=https"
- "traefik.http.routers.gollum.rule=Host(`gollum.${DOMAIN}`)" - "traefik.http.routers.gollum.rule=Host(`gollum.${DOMAIN}`)"
- "traefik.http.routers.gollum.tls.certresolver=http" - "traefik.http.routers.gollum.tls.certresolver=http"
- "traefik.http.routers.gollum.middlewares=auth@file" - "traefik.http.routers.gollum.middlewares=auth@docker"
networks: networks:
web: web:

View File

@@ -0,0 +1,28 @@
services:
homepage:
image: nginx
container_name: homepage
restart: unless-stopped
volumes:
- ./html:/usr/share/nginx/html # Mount your content directory
- ./templates:/etc/nginx/templates # Mount your templates directory
expose:
- "80"
labels:
- "traefik.enable=true"
- "traefik.http.routers.homepage-secure.entrypoints=https,http"
- "traefik.http.routers.homepage-secure.rule=Host(`ghost.tel`)"
- "traefik.http.routers.homepage-secure.tls.certresolver=http"
- "traefik.http.middlewares.watch-redirect.redirectregex.regex=https?://ghost.tel/watch(.*)"
- "traefik.http.middlewares.watch-redirect.redirectregex.replacement=https://invid.ghost.tel/watch$${1}"
- "traefik.http.middlewares.watch-redirect.redirectregex.permanent=true"
- "traefik.http.routers.homepage-secure.middlewares=watch-redirect"
# - "traefik.http.routers.homepage-secure.middlewares=auth@file"
environment:
- NGINX_HOST=ghost.tel
- NGINX_PORT=80
networks:
- web
networks:
web:
external: true

View File

@@ -1,5 +1,4 @@
DOMAIN=${DOMAIN} DOMAIN=${DOMAIN}
INVIDIOUS_DB_PASSWORD=${INVIDIOUS_DB_PASSWORD} INVIDIOUS_DB_PASSWORD=${INVIDIOUS_DB_PASSWORD}
INVIDIOUS_VISITOR_DATA=${INVIDIOUS_VISITOR_DATA}
INVIDIOUS_PO_TOKEN=${INVIDIOUS_PO_TOKEN}
INVIDIOUS_HMAC_KEY=${INVIDIOUS_HMAC_KEY} INVIDIOUS_HMAC_KEY=${INVIDIOUS_HMAC_KEY}
INVIDIOUS_COMPANION_KEY=${INVIDIOUS_COMPANION_KEY}

View File

@@ -0,0 +1,12 @@
-- Table: public.annotations
-- DROP TABLE public.annotations;
CREATE TABLE IF NOT EXISTS public.annotations
(
id text NOT NULL,
annotations xml,
CONSTRAINT annotations_id_key UNIQUE (id)
);
GRANT ALL ON TABLE public.annotations TO current_user;

View File

@@ -0,0 +1,30 @@
-- Table: public.channel_videos
-- DROP TABLE public.channel_videos;
CREATE TABLE IF NOT EXISTS public.channel_videos
(
id text NOT NULL,
title text,
published timestamp with time zone,
updated timestamp with time zone,
ucid text,
author text,
length_seconds integer,
live_now boolean,
premiere_timestamp timestamp with time zone,
views bigint,
CONSTRAINT channel_videos_id_key UNIQUE (id)
);
GRANT ALL ON TABLE public.channel_videos TO current_user;
-- Index: public.channel_videos_ucid_idx
-- DROP INDEX public.channel_videos_ucid_idx;
CREATE INDEX IF NOT EXISTS channel_videos_ucid_idx
ON public.channel_videos
USING btree
(ucid COLLATE pg_catalog."default");

View File

@@ -0,0 +1,25 @@
-- Table: public.channels
-- DROP TABLE public.channels;
CREATE TABLE IF NOT EXISTS public.channels
(
id text NOT NULL,
author text,
updated timestamp with time zone,
deleted boolean,
subscribed timestamp with time zone,
CONSTRAINT channels_id_key UNIQUE (id)
);
GRANT ALL ON TABLE public.channels TO current_user;
-- Index: public.channels_id_idx
-- DROP INDEX public.channels_id_idx;
CREATE INDEX IF NOT EXISTS channels_id_idx
ON public.channels
USING btree
(id COLLATE pg_catalog."default");

View File

@@ -0,0 +1,22 @@
-- Table: public.nonces
-- DROP TABLE public.nonces;
CREATE TABLE IF NOT EXISTS public.nonces
(
nonce text,
expire timestamp with time zone,
CONSTRAINT nonces_id_key UNIQUE (nonce)
);
GRANT ALL ON TABLE public.nonces TO current_user;
-- Index: public.nonces_nonce_idx
-- DROP INDEX public.nonces_nonce_idx;
CREATE INDEX IF NOT EXISTS nonces_nonce_idx
ON public.nonces
USING btree
(nonce COLLATE pg_catalog."default");

View File

@@ -0,0 +1,19 @@
-- Table: public.playlist_videos
-- DROP TABLE public.playlist_videos;
CREATE TABLE IF NOT EXISTS public.playlist_videos
(
title text,
id text,
author text,
ucid text,
length_seconds integer,
published timestamptz,
plid text references playlists(id),
index int8,
live_now boolean,
PRIMARY KEY (index,plid)
);
GRANT ALL ON TABLE public.playlist_videos TO current_user;

View File

@@ -0,0 +1,29 @@
-- Type: public.privacy
-- DROP TYPE public.privacy;
CREATE TYPE public.privacy AS ENUM
(
'Public',
'Unlisted',
'Private'
);
-- Table: public.playlists
-- DROP TABLE public.playlists;
CREATE TABLE IF NOT EXISTS public.playlists
(
title text,
id text primary key,
author text,
description text,
video_count integer,
created timestamptz,
updated timestamptz,
privacy privacy,
index int8[]
);
GRANT ALL ON public.playlists TO current_user;

View File

@@ -0,0 +1,23 @@
-- Table: public.session_ids
-- DROP TABLE public.session_ids;
CREATE TABLE IF NOT EXISTS public.session_ids
(
id text NOT NULL,
email text,
issued timestamp with time zone,
CONSTRAINT session_ids_pkey PRIMARY KEY (id)
);
GRANT ALL ON TABLE public.session_ids TO current_user;
-- Index: public.session_ids_id_idx
-- DROP INDEX public.session_ids_id_idx;
CREATE INDEX IF NOT EXISTS session_ids_id_idx
ON public.session_ids
USING btree
(id COLLATE pg_catalog."default");

View File

@@ -0,0 +1,29 @@
-- Table: public.users
-- DROP TABLE public.users;
CREATE TABLE IF NOT EXISTS public.users
(
updated timestamp with time zone,
notifications text[],
subscriptions text[],
email text NOT NULL,
preferences text,
password text,
token text,
watched text[],
feed_needs_update boolean,
CONSTRAINT users_email_key UNIQUE (email)
);
GRANT ALL ON TABLE public.users TO current_user;
-- Index: public.email_unique_idx
-- DROP INDEX public.email_unique_idx;
CREATE UNIQUE INDEX IF NOT EXISTS email_unique_idx
ON public.users
USING btree
(lower(email) COLLATE pg_catalog."default");

View File

@@ -0,0 +1,23 @@
-- Table: public.videos
-- DROP TABLE public.videos;
CREATE UNLOGGED TABLE IF NOT EXISTS public.videos
(
id text NOT NULL,
info text,
updated timestamp with time zone,
CONSTRAINT videos_pkey PRIMARY KEY (id)
);
GRANT ALL ON TABLE public.videos TO current_user;
-- Index: public.id_idx
-- DROP INDEX public.id_idx;
CREATE UNIQUE INDEX IF NOT EXISTS id_idx
ON public.videos
USING btree
(id COLLATE pg_catalog."default");

View File

@@ -1,10 +1,8 @@
services: services:
invidious: invidious:
image: quay.io/invidious/invidious:latest image: quay.io/invidious/invidious:master
container_name: invidious container_name: invidious
restart: unless-stopped restart: unless-stopped
ports:
- "3001:3000"
environment: environment:
INVIDIOUS_CONFIG: | INVIDIOUS_CONFIG: |
db: db:
@@ -14,45 +12,96 @@ services:
host: invidious-db host: invidious-db
port: 5432 port: 5432
check_tables: true check_tables: true
signature_server: inv_sig_helper:12999 invidious_companion:
visitor_data: ${INVIDIOUS_VISITOR_DATA} - private_url: "http://invidious-companion:8282/companion"
po_token: ${INVIDIOUS_PO_TOKEN} public_url: "https://inv.${DOMAIN}"
invidious_companion_key: "${INVIDIOUS_COMPANION_KEY}"
external_port: 443
domain: inv.${DOMAIN}
https_only: true
hmac_key: "${INVIDIOUS_HMAC_KEY}" hmac_key: "${INVIDIOUS_HMAC_KEY}"
hsts: false
log_level: Info
healthcheck:
test: wget -nv --tries=1 --spider "http://127.0.0.1:3000/api/v1/search?q=test" || exit 1
interval: 30s
timeout: 5s
retries: 2
logging: logging:
options: options:
max-size: "1G" max-size: "1G"
max-file: "4" max-file: "4"
depends_on: depends_on:
- invidious-db - invidious-db
deploy:
resources:
limits:
cpus: '1'
memory: 2G
labels: labels:
- "com.ghost.tel/stack-type=public"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.services.invidious.loadbalancer.server.port=3000" - "traefik.http.services.invid.loadbalancer.server.port=3000"
- "traefik.http.routers.invidious.entrypoints=https" - "traefik.http.routers.invid.entrypoints=http,https"
- "traefik.http.routers.invidious.rule=Host(`invid.${DOMAIN}`, `i.${DOMAIN}`)" - "traefik.http.routers.invid.rule=Host(`inv.${DOMAIN}`) && !(Path(`/latest_version`) || PathPrefix(`/api/manifest/dash/id/`) || PathPrefix(`/videoplayback`) || PathPrefix(`/download`))"
- "traefik.http.routers.invidious.tls.certresolver=http" - "traefik.http.routers.invid.tls.certresolver=http"
networks: networks:
- web - web
- default - default
inv_sig_helper: invidious-companion:
image: quay.io/invidious/inv-sig-helper:latest image: quay.io/invidious/invidious-companion:latest
container_name: inv-sig-helper container_name: invidious-companion
command: ["--tcp", "0.0.0.0:12999"]
environment:
- RUST_LOG=info
restart: unless-stopped restart: unless-stopped
environment:
- SERVER_SECRET_KEY=${INVIDIOUS_COMPANION_KEY}
- SERVER_BASE_URL=https://inv.${DOMAIN}/companion
logging:
options:
max-size: "1G"
max-file: "4"
cap_drop: cap_drop:
- ALL - ALL
read_only: true read_only: true
volumes:
- companion-cache:/var/tmp/youtubei.js:rw
security_opt: security_opt:
- no-new-privileges:true - no-new-privileges:true
deploy:
resources:
limits:
cpus: '0.5'
memory: 1G
labels:
- "traefik.enable=true"
- "traefik.http.services.invid-companion.loadbalancer.server.port=8282"
- "traefik.http.routers.invid-companion.entrypoints=http,https"
- "traefik.http.routers.invid-companion.rule=Host(`inv.${DOMAIN}`) && (Path(`/latest_version`) || PathPrefix(`/api/manifest/dash/id/`) || PathPrefix(`/youtubei/v1/player`) || PathPrefix(`/videoplayback`) || PathPrefix(`/download`))"
- "traefik.http.routers.invid-companion.tls.certresolver=http"
- "traefik.http.routers.invid-companion.middlewares=invid-companion-prefix@docker"
networks:
- web
- default
invidious-restarter:
image: docker:cli
container_name: invidious-restarter
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: sh -c "while true; do sleep 3600; docker restart invidious invidious-companion; done"
deploy:
resources:
limits:
cpus: '0.1'
memory: 32M
invidious-db: invidious-db:
image: postgres:14 image: postgres:14
container_name: invidious-db container_name: invidious-db
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./postgres:/var/lib/postgresql/data - postgres-data:/var/lib/postgresql/data
- ./config/sql:/config/sql - ./config/sql:/config/sql
- ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh - ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
environment: environment:
@@ -61,6 +110,15 @@ services:
POSTGRES_PASSWORD: ${INVIDIOUS_DB_PASSWORD} POSTGRES_PASSWORD: ${INVIDIOUS_DB_PASSWORD}
healthcheck: healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
deploy:
resources:
limits:
cpus: '0.5'
memory: 1G
volumes:
postgres-data:
companion-cache:
networks: networks:
web: web:

View File

@@ -0,0 +1,12 @@
#!/bin/bash
set -eou pipefail
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/channels.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/videos.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/channel_videos.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/users.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/session_ids.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/nonces.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/annotations.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/playlists.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/playlist_videos.sql

View File

@@ -0,0 +1,2 @@
MATOMO_MYSQL_ROOT_PASSWORD=changeme
MATOMO_MYSQL_PASSWORD=changeme

View File

@@ -0,0 +1,50 @@
services:
db:
image: mariadb:latest
container_name: matomo-db
restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=public"
command: --max-allowed-packet=64MB
environment:
MYSQL_ROOT_PASSWORD: ${MATOMO_MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: matomo
MYSQL_USER: matomo
MYSQL_PASSWORD: ${MATOMO_MYSQL_PASSWORD}
volumes:
- ./mysql:/var/lib/mysql
app:
image: matomo:latest
container_name: matomo
restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=public"
- "traefik.enable=true"
- "traefik.http.routers.matomo.entrypoints=https"
- "traefik.http.routers.matomo.rule=Host(`matomo.sequela.tel`)"
- "traefik.http.routers.matomo.tls.certresolver=http"
- "traefik.http.services.matomo.loadbalancer.server.port=80"
environment:
MATOMO_DATABASE_HOST: db
MATOMO_DATABASE_ADAPTER: mysql
MATOMO_DATABASE_TABLES_PREFIX: matomo_
MATOMO_DATABASE_USERNAME: matomo
MATOMO_DATABASE_PASSWORD: ${MATOMO_MYSQL_PASSWORD}
MATOMO_DATABASE_DBNAME: matomo
volumes:
- matomo-data:/var/www/html
expose:
- "80"
depends_on:
- db
networks:
- web
- default
volumes:
matomo-data:
networks:
web:
external: true

View File

@@ -11,6 +11,7 @@ services:
- web - web
- default - default
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.memento.entrypoints=https" - "traefik.http.routers.memento.entrypoints=https"
- "traefik.http.routers.memento.rule=Host(`memento.${DOMAIN}`)" - "traefik.http.routers.memento.rule=Host(`memento.${DOMAIN}`)"

View File

@@ -2,6 +2,8 @@ services:
meshmonitor: meshmonitor:
image: ghcr.io/yeraze/meshmonitor:latest image: ghcr.io/yeraze/meshmonitor:latest
container_name: meshmonitor container_name: meshmonitor
labels:
- "com.ghost.tel/stack-type=dev-only"
ports: ports:
- "8383:3001" - "8383:3001"
restart: unless-stopped restart: unless-stopped

View File

@@ -3,5 +3,7 @@ services:
image: ghcr.io/meshtastic/web:latest image: ghcr.io/meshtastic/web:latest
container_name: meshtastic-web container_name: meshtastic-web
restart: unless-stopped restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=dev-only"
ports: ports:
- "8585:8080" - "8585:8080"

View File

@@ -1,8 +1,8 @@
version: "3.9"
services: services:
grafana-alert-webhook: grafana-alert-webhook:
build: . build: .
labels:
- "com.ghost.tel/stack-type=dev-only"
env_file: env_file:
- .env - .env
ports: ports:

View File

@@ -1,11 +1,11 @@
version: "3.9"
services: services:
frontend: frontend:
build: build:
context: . context: .
dockerfile: frontend/Dockerfile dockerfile: frontend/Dockerfile
restart: always restart: always
labels:
- "com.ghost.tel/stack-type=dev-only"
env_file: env_file:
- .env - .env
environment: environment:

View File

@@ -3,6 +3,8 @@ services:
obsidian: obsidian:
image: lscr.io/linuxserver/obsidian:latest image: lscr.io/linuxserver/obsidian:latest
container_name: obsidian container_name: obsidian
labels:
- "com.ghost.tel/stack-type=dev-only"
security_opt: security_opt:
- seccomp:unconfined #optional - seccomp:unconfined #optional
environment: environment:
@@ -14,7 +16,5 @@ services:
ports: ports:
- 3002:3000 - 3002:3000
- 3003:3001 - 3003:3001
devices:
- /dev/dri:/dev/dri #optional
shm_size: "1gb" shm_size: "1gb"
restart: unless-stopped restart: unless-stopped

View File

@@ -18,12 +18,13 @@ services:
depends_on: depends_on:
- syncthing - syncthing
labels: labels:
- "com.ghost.tel/stack-type=dev-only"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=web" - "traefik.docker.network=web"
- "traefik.http.routers.todo-obbytodo.entrypoints=https" - "traefik.http.routers.todo-obbytodo.entrypoints=https"
- "traefik.http.routers.todo-obbytodo.rule=Host(`shell.${DOMAIN}`) && PathPrefix(`/todo`)" - "traefik.http.routers.todo-obbytodo.rule=Host(`shell.${DOMAIN}`) && PathPrefix(`/todo`)"
- "traefik.http.routers.todo-obbytodo.tls.certresolver=http" - "traefik.http.routers.todo-obbytodo.tls.certresolver=http"
- "traefik.http.routers.todo-obbytodo.middlewares=todo-obbytodo-stripprefix@docker,dashboard-auth@file" - "traefik.http.routers.todo-obbytodo.middlewares=todo-obbytodo-stripprefix@docker,dashboard-auth@docker"
- "traefik.http.routers.todo-obbytodo.priority=100" - "traefik.http.routers.todo-obbytodo.priority=100"
- "traefik.http.middlewares.todo-obbytodo-stripprefix.stripPrefix.prefixes=/todo" - "traefik.http.middlewares.todo-obbytodo-stripprefix.stripPrefix.prefixes=/todo"
- "traefik.http.services.todo-obbytodo.loadbalancer.server.port=3000" - "traefik.http.services.todo-obbytodo.loadbalancer.server.port=3000"
@@ -31,7 +32,7 @@ services:
- "traefik.http.routers.events-obbytodo.entrypoints=https" - "traefik.http.routers.events-obbytodo.entrypoints=https"
- "traefik.http.routers.events-obbytodo.rule=Host(`shell.${DOMAIN}`) && PathPrefix(`/events`)" - "traefik.http.routers.events-obbytodo.rule=Host(`shell.${DOMAIN}`) && PathPrefix(`/events`)"
- "traefik.http.routers.events-obbytodo.tls.certresolver=http" - "traefik.http.routers.events-obbytodo.tls.certresolver=http"
- "traefik.http.routers.events-obbytodo.middlewares=dashboard-auth@file" - "traefik.http.routers.events-obbytodo.middlewares=dashboard-auth@docker"
- "traefik.http.routers.events-obbytodo.priority=100" - "traefik.http.routers.events-obbytodo.priority=100"
- "traefik.http.routers.events-obbytodo.service=todo-obbytodo" - "traefik.http.routers.events-obbytodo.service=todo-obbytodo"
@@ -52,13 +53,18 @@ services:
- syncthing - syncthing
networks: networks:
- web - web
healthcheck:
test: ["CMD-SHELL", "wget -qO- 'http://127.0.0.1:3001/api/search?q=test' >/dev/null 2>&1 || exit 1"]
interval: 30s
timeout: 5s
retries: 3
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=web" - "traefik.docker.network=web"
- "traefik.http.routers.shell-secure.entrypoints=https" - "traefik.http.routers.shell-secure.entrypoints=https"
- "traefik.http.routers.shell-secure.rule=Host(`shell.${DOMAIN}`)" - "traefik.http.routers.shell-secure.rule=Host(`shell.${DOMAIN}`)"
- "traefik.http.routers.shell-secure.tls.certresolver=http" - "traefik.http.routers.shell-secure.tls.certresolver=http"
- "traefik.http.routers.shell-secure.middlewares=dashboard-auth@file" - "traefik.http.routers.shell-secure.middlewares=dashboard-auth@docker"
- "traefik.http.services.shell-secure.loadbalancer.server.port=3033" - "traefik.http.services.shell-secure.loadbalancer.server.port=3033"
- "traefik.http.routers.shell-secure.service=shell-secure" - "traefik.http.routers.shell-secure.service=shell-secure"

View File

@@ -1,7 +1,7 @@
FROM node:18-alpine FROM node:18-alpine
RUN apk add --no-cache python3 make g++ vips-dev fontconfig ttf-dejavu
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY package.json ./ COPY content/package.json ./
RUN npm install RUN npm install
COPY server.js ./
EXPOSE 3000 EXPOSE 3000
CMD ["node", "server.js"] CMD ["node", "content/server.js"]

View File

@@ -3,40 +3,45 @@ services:
build: . build: .
container_name: perilous-web container_name: perilous-web
restart: unless-stopped restart: unless-stopped
ports: expose:
- "3003:3000" - "3000"
volumes: volumes:
- ./content:/usr/src/app/content - ./content:/usr/src/app/content
labels: environment:
- "traefik.enable=true" - EMAIL_PASSWORD=${PERILOUS_CODE_SERVER_PASSWORD}
- "traefik.http.routers.perilous-secure.entrypoints=https,http"
- "traefik.http.routers.perilous-secure.rule=Host(`chapel.perilous.dev`,`forest.perilous.dev`,`castle.perilous.dev`,`siege.perilous.dev`,`pass.perilous.dev`,`perilous.dev`,`www.perilous.dev`,`word.perilous.dev`,`mirror.perilous.dev`,`request.perilous.dev`,`the.chapel.perilous.dev`,`the.forest.perilous.dev`,`the.castle.perilous.dev`,`the.siege.perilous.dev`,`the.pass.perilous.dev`,`the.word.perilous.dev`,`the.mirror.perilous.dev`,`the.request.perilous.dev`,`the.adventure.perilous.dev`,`the.cs.perilous.dev`,`the.gallery.perilous.dev`,`gallery.perilous.dev`,`the.perilous.dev`,`ring.perilous.dev`,`the.ring.perilous.dev`,`autumn.perilous.dev`,`the.autumn.perilous.dev`)"
- "traefik.http.routers.perilous-secure.tls.certresolver=http"
networks: networks:
- web - web
labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true"
- "traefik.http.routers.perilous.entrypoints=https"
- "traefik.http.routers.perilous.rule=Host(`perilous.dev`) || Host(`www.perilous.dev`) || HostRegexp(`^.+\\.perilous\\.dev$$`)"
- "traefik.http.routers.perilous.tls.certresolver=http"
- "traefik.http.services.perilous.loadbalancer.server.port=3000"
code-server: code-server:
image: lscr.io/linuxserver/code-server:latest image: lscr.io/linuxserver/code-server:latest
container_name: perilous-code-server container_name: perilous-code-server
restart: unless-stopped restart: unless-stopped
expose:
- "8443"
volumes: volumes:
- ./content:/home/project - ./content:/home/project
- ./config:/config - ./config:/config
ports:
- "8180:8443"
environment: environment:
- PASSWORD=${PERILOUS_CODE_SERVER_PASSWORD} - PASSWORD=${PERILOUS_CODE_SERVER_PASSWORD}
- PUID=1000 - PUID=1000
- PGID=1000 - PGID=1000
- PROXY_DOMAIN=cs.perilous.dev - PROXY_DOMAIN=cs.perilous.dev
- DEFAULT_WORKSPACE=/home/project - DEFAULT_WORKSPACE=/home/project
labels:
- "traefik.enable=true"
- "traefik.http.routers.pcs-secure.entrypoints=https,http"
- "traefik.http.routers.pcs-secure.rule=Host(`cs.perilous.dev`)"
- "traefik.http.routers.pcs-secure.tls.certresolver=http"
networks: networks:
- web - web
labels:
- "traefik.enable=true"
- "traefik.http.routers.perilous-cs.entrypoints=https"
- "traefik.http.routers.perilous-cs.rule=Host(`cs.perilous.dev`)"
- "traefik.http.routers.perilous-cs.tls.certresolver=http"
- "traefik.http.services.perilous-cs.loadbalancer.server.port=8443"
networks: networks:
web: web:

View File

@@ -25,6 +25,7 @@ services:
volumes: volumes:
- ./data:/data - ./data:/data
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.radicale.entrypoints=https" - "traefik.http.routers.radicale.entrypoints=https"
- "traefik.http.routers.radicale.rule=Host(`radicale.${DOMAIN}`)" - "traefik.http.routers.radicale.rule=Host(`radicale.${DOMAIN}`)"

View File

@@ -13,6 +13,7 @@ services:
networks: networks:
- web - web
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.ramz-secure.entrypoints=https,http" - "traefik.http.routers.ramz-secure.entrypoints=https,http"
- "traefik.http.routers.ramz-secure.rule=Host(`parker.ramz.cc`)" - "traefik.http.routers.ramz-secure.rule=Host(`parker.ramz.cc`)"

View File

@@ -3,25 +3,45 @@ services:
image: registry:2 image: registry:2
container_name: registry container_name: registry
restart: unless-stopped restart: unless-stopped
volumes:
- ./data:/var/lib/registry
- ./auth:/auth
environment:
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
REGISTRY_HTTP_SECRET: ${REGISTRY_HTTP_SECRET}
expose: expose:
- 5000 - "5000"
volumes:
- ./docker:/var/lib/registry
networks: networks:
- web - web
healthcheck:
test: ["CMD", "wget", "--spider", "localhost:5000/v2/"]
interval: 60s
timeout: 10s
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.registry.entrypoints=https" - "traefik.http.routers.registry.entrypoints=https"
- "traefik.http.routers.registry.rule=Host(`registry.${DOMAIN}`)" - "traefik.http.routers.registry.rule=Host(`registry.${DOMAIN}`)"
- "traefik.http.routers.registry.tls.certresolver=http" - "traefik.http.routers.registry.tls.certresolver=http"
- "traefik.http.services.registry.loadbalancer.server.port=5000" - "traefik.http.services.registry.loadbalancer.server.port=5000"
registry-ui:
image: quiq/docker-registry-ui:latest
container_name: registry-ui
restart: unless-stopped
expose:
- "8000"
volumes:
- ./registry-ui:/opt/data
- ./registry-ui.yml:/opt/config.yml:ro
depends_on:
registry:
condition: service_healthy
networks:
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.registry-ui.entrypoints=https"
- "traefik.http.routers.registry-ui.rule=Host(`dockerhub.${DOMAIN}`)"
- "traefik.http.routers.registry-ui.tls.certresolver=http"
- "traefik.http.services.registry-ui.loadbalancer.server.port=8000"
networks: networks:
web: web:
external: true external: true

View File

@@ -0,0 +1,22 @@
services:
rsshub:
image: diygod/rsshub:latest
container_name: rsshub
restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=public"
- "traefik.enable=true"
- "traefik.http.routers.rsshub.entrypoints=https"
- "traefik.http.routers.rsshub.rule=Host(`rsshub.uplink.tel`)"
- "traefik.http.routers.rsshub.tls.certresolver=http"
- "traefik.http.services.rsshub.loadbalancer.server.port=1200"
environment:
- CACHE_EXPIRE=3600
expose:
- "1200"
networks:
- web
networks:
web:
external: true

View File

@@ -0,0 +1,54 @@
services:
redis:
image: redis:alpine
container_name: searx-redis
restart: unless-stopped
command: redis-server --save "" --appendonly "no"
tmpfs:
- /var/lib/redis
cap_drop:
- ALL
cap_add:
- SETGID
- SETUID
- DAC_OVERRIDE
networks:
- default
searxng:
image: searxng/searxng:latest
container_name: searxng
restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=public"
- "traefik.enable=true"
- "traefik.http.routers.searx.entrypoints=https"
- "traefik.http.routers.searx.rule=Host(`searx.uplink.tel`)"
- "traefik.http.routers.searx.tls.certresolver=http"
- "traefik.http.services.searx.loadbalancer.server.port=8080"
environment:
- SEARXNG_BASE_URL=https://searx.uplink.tel/
volumes:
- ./config:/etc/searxng:rw
expose:
- "8080"
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"
depends_on:
- redis
networks:
- web
- default
networks:
web:
external: true

View File

@@ -0,0 +1,24 @@
services:
service-map:
build: .
container_name: service-map
restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=dev-only"
- "traefik.enable=true"
- "traefik.http.routers.service-map.rule=Host(`map.ghost.tel`)"
- "traefik.http.routers.service-map.entrypoints=https"
- "traefik.http.routers.service-map.tls.certresolver=http"
- "traefik.http.routers.service-map.middlewares=dashboard-auth@docker"
- "traefik.http.services.service-map.loadbalancer.server.port=3000"
environment:
- HOSTS=ubuntu-dev,ubuntu-prod
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ~/.ssh:/root/.ssh:ro
networks:
- web
networks:
web:
external: true

View File

@@ -15,11 +15,12 @@ services:
networks: networks:
- web - web
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "org.opencontainers.image.source=https://gitea.ghost.tel/knight/docker-stacks" - "org.opencontainers.image.source=https://gitea.ghost.tel/knight/docker-stacks"
- "com.centurylinklabs.watchtower.enable=true" - "com.centurylinklabs.watchtower.enable=true"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.smokeping.entrypoints=https" - "traefik.http.routers.smokeping.entrypoints=https"
- "traefik.http.routers.smokeping.rule=Host(`smokeping.${DOMAIN}`)" - "traefik.http.routers.smokeping.rule=Host(`smoke.${DOMAIN}`)"
- "traefik.http.routers.smokeping.tls.certresolver=http" - "traefik.http.routers.smokeping.tls.certresolver=http"
- "traefik.http.services.smokeping.loadbalancer.server.port=80" - "traefik.http.services.smokeping.loadbalancer.server.port=80"

View File

@@ -1,15 +1,11 @@
services: services:
snowflake-proxy: snowflake-proxy:
network_mode: host network_mode: host
image: containers.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake:latest image: containers.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake:latest
container_name: snowflake-proxy container_name: snowflake-proxy
restart: unless-stopped restart: unless-stopped
# For a full list of Snowflake Proxy CLI parameters see labels:
# https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/tree/main/proxy?ref_type=heads#running-a-standalone-snowflake-proxy - "com.ghost.tel/stack-type=public"
#command: [ "-ephemeral-ports-range", "30000:60000" ] # For a full list of Snowflake Proxy CLI parameters see
watchtower: # https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/tree/main/proxy?ref_type=heads#running-a-standalone-snowflake-proxy
image: containrrr/watchtower #command: [ "-ephemeral-ports-range", "30000:60000" ]
container_name: watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: snowflake-proxy

View File

@@ -19,6 +19,7 @@ services:
networks: networks:
- web - web
labels: labels:
- "com.ghost.tel/stack-type=dev-only"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.syncthing.entrypoints=https" - "traefik.http.routers.syncthing.entrypoints=https"
- "traefik.http.routers.syncthing.rule=Host(`syncthing.${DOMAIN}`)" - "traefik.http.routers.syncthing.rule=Host(`syncthing.${DOMAIN}`)"

View File

@@ -3,9 +3,10 @@
## Use this as a template to set up docker compose, or as guide to set up other ## Use this as a template to set up docker compose, or as guide to set up other
## orchestration services ## orchestration services
services: services:
server: server:
image: szurubooru/server:latest image: szurubooru/server:latest
labels:
- "com.ghost.tel/stack-type=dev-only"
depends_on: depends_on:
- sql - sql
environment: environment:

View File

View File

@@ -1,61 +0,0 @@
# Core middlewares for traefik
# External service routers should be added as separate files or via docker labels
http:
routers:
# Redirect HTTP to HTTPS
https-redirect:
entryPoints:
- http
rule: "HostRegexp(`{host:.+}`)"
service: noop@internal
middlewares:
- redirect-to-https
priority: 1
middlewares:
# HTTPS redirect
redirect-to-https:
redirectScheme:
scheme: https
# Authentik forward auth - update URL after authentik is deployed
auth:
forwardAuth:
address: http://authentik-server:9000/outpost.goauthentik.io/auth/traefik
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
- X-authentik-jwt
- X-authentik-meta-jwks
- X-authentik-meta-outpost
- X-authentik-meta-provider
- X-authentik-meta-app
- X-authentik-meta-version
# Security headers
securityHeaders:
headers:
customResponseHeaders:
X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex"
server: ""
X-Forwarded-Proto: "https"
sslProxyHeaders:
X-Forwarded-Proto: https
referrerPolicy: "same-origin"
hostsProxyHeaders:
- "X-Forwarded-Host"
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsSeconds: 63072000
stsPreload: true
# Gzip compression
gzip:
compress: {}

View File

@@ -5,6 +5,137 @@ services:
restart: unless-stopped restart: unless-stopped
security_opt: security_opt:
- no-new-privileges:true - no-new-privileges:true
labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`traefik.ghost.tel`)"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=auth@docker"
- "traefik.http.routers.traefik.tls.certresolver=http"
- "traefik.http.routers.immich-redirect.entrypoints=http,https"
- "traefik.http.routers.immich-redirect.rule=Host(`immich.ghost.tel`)"
- "traefik.http.routers.immich-redirect.service=dummy"
- "traefik.http.routers.immich-redirect.middlewares=redirect-immich-to-photos@docker"
- "traefik.http.routers.immich-redirect.tls.certresolver=http"
- "traefik.http.routers.homeassist.entrypoints=https"
- "traefik.http.routers.homeassist.rule=Host(`home.ghost.tel`)"
- "traefik.http.routers.homeassist.service=homeassistant"
- "traefik.http.routers.homeassist.middlewares=securityHeaders@docker"
- "traefik.http.routers.homeassist.tls.certresolver=http"
- "traefik.http.routers.dynmap.entrypoints=http,https"
- "traefik.http.routers.dynmap.rule=Host(`dynmap.ghost.tel`)"
- "traefik.http.routers.dynmap.service=dynmap"
- "traefik.http.routers.dynmap.tls.certresolver=http"
- "traefik.http.routers.amp.entrypoints=http"
- "traefik.http.routers.amp.rule=Host(`amped.ghost.tel`)"
- "traefik.http.routers.amp.service=amp"
- "traefik.http.routers.amp.tls.certresolver=http"
- "traefik.http.routers.picam.entrypoints=http,https"
- "traefik.http.routers.picam.rule=Host(`printview.ghost.tel`)"
- "traefik.http.routers.picam.service=picam"
- "traefik.http.routers.picam.tls.certresolver=http"
- "traefik.http.routers.library.entrypoints=http,https"
- "traefik.http.routers.library.rule=Host(`library.ghost.tel`)"
- "traefik.http.routers.library.service=library"
- "traefik.http.routers.library.middlewares=securityHeaders@docker"
- "traefik.http.routers.library.tls.certresolver=http"
- "traefik.http.routers.meshmon.entrypoints=http,https"
- "traefik.http.routers.meshmon.rule=Host(`meshmon.ghost.tel`)"
- "traefik.http.routers.meshmon.service=meshmon"
- "traefik.http.routers.meshmon.middlewares=securityHeaders@docker"
- "traefik.http.routers.meshmon.tls.certresolver=http"
- "traefik.http.routers.skeyta.entrypoints=http,https"
- "traefik.http.routers.skeyta.rule=Host(`skeyta.ghost.tel`)"
- "traefik.http.routers.skeyta.service=skeyta"
- "traefik.http.routers.skeyta.middlewares=securityHeaders@docker"
- "traefik.http.routers.skeyta.tls.certresolver=http"
- "traefik.http.routers.radio.entrypoints=http,https"
- "traefik.http.routers.radio.rule=Host(`radio.uplink.tel`)"
- "traefik.http.routers.radio.service=radio-wunder"
- "traefik.http.routers.radio.middlewares=securityHeaders@docker"
- "traefik.http.routers.radio.tls.certresolver=http"
- "traefik.http.routers.sdr.entrypoints=http,https"
- "traefik.http.routers.sdr.rule=Host(`sdr.uplink.tel`)"
- "traefik.http.routers.sdr.service=sdr"
- "traefik.http.routers.sdr.middlewares=redirect-to-https"
- "traefik.http.routers.sdr.tls.certresolver=http"
- "traefik.http.routers.spider.entrypoints=http,https"
- "traefik.http.routers.spider.rule=Host(`spider.ghost.tel`)"
- "traefik.http.routers.spider.service=spider"
- "traefik.http.routers.spider.middlewares=securityHeaders@docker"
- "traefik.http.routers.spider.tls.certresolver=http"
- "traefik.http.routers.tlc.entrypoints=http,https"
- "traefik.http.routers.tlc.rule=Host(`tlc.ghost.tel`) || Host(`thislittlecorner.net`)"
- "traefik.http.routers.tlc.service=tlc"
- "traefik.http.routers.tlc.middlewares=securityHeaders@docker"
- "traefik.http.routers.tlc.tls.certresolver=http"
- "traefik.http.routers.photos.entrypoints=http,https"
- "traefik.http.routers.photos.rule=Host(`photos.ghost.tel`)"
- "traefik.http.routers.photos.service=wille"
- "traefik.http.routers.photos.middlewares=securityHeaders@docker"
- "traefik.http.routers.photos.tls.certresolver=http"
- "traefik.http.routers.invidious-uplink.entrypoints=https"
- "traefik.http.routers.invidious-uplink.rule=Host(`invidious.uplink.tel`)"
- "traefik.http.routers.invidious-uplink.service=docker-public"
- "traefik.http.routers.invidious-uplink.tls.certresolver=http"
- "traefik.http.routers.service-map.entrypoints=https"
- "traefik.http.routers.service-map.rule=Host(`map.ghost.tel`)"
- "traefik.http.routers.service-map.service=service-map"
- "traefik.http.routers.service-map.middlewares=dashboard-auth@docker"
- "traefik.http.routers.service-map.tls.certresolver=http"
- "traefik.http.services.dummy.loadbalancer.server.url=http://127.0.0.1"
- "traefik.http.services.homeassistant.loadbalancer.server.url=http://homeassistant.localdomain:8123"
- "traefik.http.services.homeassistant.loadbalancer.passHostHeader=true"
- "traefik.http.services.dynmap.loadbalancer.server.url=http://ramiel:8123/"
- "traefik.http.services.amp.loadbalancer.server.url=http://192.168.1.205:8080"
- "traefik.http.services.amp.loadbalancer.passHostHeader=true"
- "traefik.http.services.picam.loadbalancer.server.url=http://192.168.1.80:8080"
- "traefik.http.services.picam.loadbalancer.passHostHeader=true"
- "traefik.http.services.library.loadbalancer.server.url=http://docker-dev:8033/"
- "traefik.http.services.library.loadbalancer.passHostHeader=true"
- "traefik.http.services.meshmon.loadbalancer.server.url=http://ubuntu-dev:8383/"
- "traefik.http.services.meshmon.loadbalancer.passHostHeader=true"
- "traefik.http.services.skeyta.loadbalancer.server.url=http://ramiel.localdomain:8"
- "traefik.http.services.skeyta.loadbalancer.passHostHeader=true"
- "traefik.http.services.radio-wunder.loadbalancer.server.url=http://wunder.localdomain:3000"
- "traefik.http.services.sdr.loadbalancer.server.url=http://wunder.localdomain:8073"
- "traefik.http.services.sdr.loadbalancer.passHostHeader=true"
- "traefik.http.services.radio-wunder.loadbalancer.passHostHeader=true"
- "traefik.http.services.spider.loadbalancer.server.url=http://melchior.localdomain:30870"
- "traefik.http.services.spider.loadbalancer.passHostHeader=true"
- "traefik.http.services.tlc.loadbalancer.passHostHeader=true"
- "traefik.http.services.tlc.loadbalancer.server.url=http://ubuntu-dev.localdomain:8088"
- "traefik.http.services.wille.loadbalancer.server.url=http://wille.localdomain:2283"
- "traefik.http.services.wille.loadbalancer.passHostHeader=true"
- "traefik.http.services.service-map.loadbalancer.server.url=http://docker-dev:3333/"
- "traefik.http.services.service-map.loadbalancer.passHostHeader=true"
- "traefik.http.services.docker-public.loadbalancer.server.url=https://192.168.5.46:443"
- "traefik.http.services.docker-public.loadbalancer.passHostHeader=true"
- "traefik.http.services.docker-public.loadbalancer.serversTransport=insecure-transport"
- "traefik.http.serversTransports.insecure-transport.insecureSkipVerify=true"
- "traefik.http.middlewares.redirect-immich-to-photos.redirectregex.regex=^https?://immich\\.ghost\\.tel(/.*)?$"
- "traefik.http.middlewares.redirect-immich-to-photos.redirectregex.replacement=https://photos.ghost.tel$1"
- "traefik.http.middlewares.redirect-immich-to-photos.redirectregex.permanent=true"
- "traefik.http.middlewares.dashboard-auth.basicauth.usersfile=/basicAuth"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.middlewares.auth.forwardauth.address=http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
- "traefik.http.middlewares.auth.forwardauth.trustForwardHeader=true"
- "traefik.http.middlewares.auth.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version"
- "traefik.http.middlewares.securityHeaders.headers.customResponseHeaders.X-Robots-Tag=none,noarchive,nosnippet,notranslate,noimageindex"
- "traefik.http.middlewares.securityHeaders.headers.customResponseHeaders.server="
- "traefik.http.middlewares.securityHeaders.headers.customResponseHeaders.X-Forwarded-Proto=https"
- "traefik.http.middlewares.securityHeaders.headers.sslProxyHeaders.X-Forwarded-Proto=https"
- "traefik.http.middlewares.securityHeaders.headers.referrerPolicy=same-origin"
- "traefik.http.middlewares.securityHeaders.headers.hostsProxyHeaders=X-Forwarded-Host"
- "traefik.http.middlewares.securityHeaders.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.securityHeaders.headers.browserXssFilter=true"
- "traefik.http.middlewares.securityHeaders.headers.forceSTSHeader=true"
- "traefik.http.middlewares.securityHeaders.headers.stsIncludeSubdomains=true"
- "traefik.http.middlewares.securityHeaders.headers.stsSeconds=63072000"
- "traefik.http.middlewares.securityHeaders.headers.stsPreload=true"
- "traefik.http.middlewares.invid-companion-prefix.addprefix.prefix=/companion"
- "traefik.http.middlewares.gzip.compress=true"
networks: networks:
- web - web
ports: ports:
@@ -17,7 +148,7 @@ services:
- /var/run/docker.sock:/var/run/docker.sock:ro - /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro - ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json - ./acme.json:/acme.json
- ./conf.d/:/conf.d/ - ./basicAuth:/basicAuth:ro
- /var/log:/var/log - /var/log:/var/log
networks: networks:

View File

@@ -8,14 +8,20 @@ api:
entryPoints: entryPoints:
http: http:
address: ":80" address: ":80"
proxyProtocol:
insecure: true
http:
redirections:
entryPoint:
to: https
scheme: https
https: https:
address: ":443" address: ":443"
proxyProtocol:
insecure: true
providers: providers:
providersThrottleDuration: 2s providersThrottleDuration: 2s
file:
directory: "/conf.d"
watch: true
docker: docker:
watch: true watch: true
endpoint: "unix:///var/run/docker.sock" endpoint: "unix:///var/run/docker.sock"
@@ -38,3 +44,22 @@ log:
accessLog: accessLog:
filePath: /var/log/traefik_access.log filePath: /var/log/traefik_access.log
format: json format: json
fields:
defaultMode: keep
names:
clientUsername: drop
headers:
defaultMode: keep
names:
User-Agent: keep
Authorization: drop
Content-Type: keep
Referer: keep
metrics:
prometheus:
buckets:
- 0.1
- 0.3
- 1.2
- 5.0

View File

@@ -25,6 +25,7 @@ services:
volumes: volumes:
- ./images:/var/www/wallabag/web/assets/images - ./images:/var/www/wallabag/web/assets/images
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.wallabag.entrypoints=https" - "traefik.http.routers.wallabag.entrypoints=https"
- "traefik.http.routers.wallabag.rule=Host(`wallabag.${DOMAIN}`)" - "traefik.http.routers.wallabag.rule=Host(`wallabag.${DOMAIN}`)"

View File

@@ -3,6 +3,8 @@ services:
image: containrrr/watchtower:latest image: containrrr/watchtower:latest
container_name: watchtower container_name: watchtower
restart: unless-stopped restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=prod"
environment: environment:
- TZ=America/New_York - TZ=America/New_York
- DOCKER_API_VERSION=1.44 - DOCKER_API_VERSION=1.44

View File

@@ -0,0 +1 @@
WIKIJS_DB_PASSWORD=changeme

View File

@@ -0,0 +1,45 @@
services:
db:
image: postgres:11-alpine
container_name: wikijs-db
restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=public"
environment:
POSTGRES_DB: wiki
POSTGRES_USER: wikijs
POSTGRES_PASSWORD: ${WIKIJS_DB_PASSWORD}
volumes:
- ./db-data:/var/lib/postgresql/data
logging:
driver: "none"
wiki:
image: requarks/wiki:2
container_name: wikijs
restart: unless-stopped
labels:
- "com.ghost.tel/stack-type=public"
- "traefik.enable=true"
- "traefik.http.routers.wikijs.entrypoints=https"
- "traefik.http.routers.wikijs.rule=Host(`wiki.sequela.tel`)"
- "traefik.http.routers.wikijs.tls.certresolver=http"
- "traefik.http.services.wikijs.loadbalancer.server.port=3000"
environment:
DB_TYPE: postgres
DB_HOST: db
DB_PORT: 5432
DB_USER: wikijs
DB_PASS: ${WIKIJS_DB_PASSWORD}
DB_NAME: wiki
expose:
- "3000"
depends_on:
- db
networks:
- web
- default
networks:
web:
external: true

View File

@@ -14,6 +14,7 @@ services:
networks: networks:
- web - web
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.xbackbone.entrypoints=https" - "traefik.http.routers.xbackbone.entrypoints=https"
- "traefik.http.routers.xbackbone.rule=Host(`xb.${DOMAIN}`)" - "traefik.http.routers.xbackbone.rule=Host(`xb.${DOMAIN}`)"

View File

@@ -4,7 +4,7 @@ services:
container_name: zerotier-ui container_name: zerotier-ui
restart: always restart: always
expose: expose:
- 3180 - 3000
volumes: volumes:
- ./ztncui:/opt/key-networks/ztncui/etc - ./ztncui:/opt/key-networks/ztncui/etc
- ./zt1:/var/lib/zerotier-one - ./zt1:/var/lib/zerotier-one
@@ -13,11 +13,13 @@ services:
networks: networks:
- web - web
labels: labels:
- "com.ghost.tel/stack-type=prod"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.zerotier.entrypoints=https" - "traefik.http.routers.zerotier.entrypoints=https"
- "traefik.http.routers.zerotier.rule=Host(`zerotierui.${DOMAIN}`)" - "traefik.http.routers.zerotier.rule=Host(`zerotierui.${DOMAIN}`)"
- "traefik.http.routers.zerotier.tls.certresolver=http" - "traefik.http.routers.zerotier.tls.certresolver=http"
- "traefik.http.routers.zerotier.middlewares=dashboard-auth@file" - "traefik.http.routers.zerotier.middlewares=dashboard-auth@docker"
- "traefik.http.services.zerotier.loadbalancer.server.port=3000"
networks: networks:
web: web: