diff --git a/pangolin/.env b/pangolin/.env new file mode 100644 index 0000000..e50d6fe --- /dev/null +++ b/pangolin/.env @@ -0,0 +1,18 @@ +TZ=America/Chicago + +POSTGRES_PASSWORD=nu8Vohx1ot1eesoono5teshu6bohn9eiteich6Bu +AUTHENTIK_SECRET_KEY=7kIHbomK9MV4lEvObyOGGvzF222eLZ1RC6fKn28EDEIB4iF8kC + +# SMTP Host Emails are sent to +AUTHENTIK_EMAIL__HOST=smtp.gmail.com +AUTHENTIK_EMAIL__PORT=587 +# Optionally authenticate (don't add quotation marks to your password) +AUTHENTIK_EMAIL__USERNAME=akanealw@gmail.com +AUTHENTIK_EMAIL__PASSWORD=dqtqnqvdmtgtvwjf +# Use StartTLS +AUTHENTIK_EMAIL__USE_TLS=true +# Use SSL +AUTHENTIK_EMAIL__USE_SSL=false +AUTHENTIK_EMAIL__TIMEOUT=10 +# Email address authentik will send from, should have a correct @domain +AUTHENTIK_EMAIL__FROM=akanealw@gmail.com diff --git a/pangolin/.gitignore b/pangolin/.gitignore new file mode 100644 index 0000000..30dfa5d --- /dev/null +++ b/pangolin/.gitignore @@ -0,0 +1,3 @@ +*.db +*.sqlite +acme.json \ No newline at end of file diff --git a/pangolin/config/config.yml b/pangolin/config/config.yml new file mode 100644 index 0000000..8b51033 --- /dev/null +++ b/pangolin/config/config.yml @@ -0,0 +1,68 @@ +# To see all available options, please visit the docs: +# https://docs.fossorial.io/Pangolin/Configuration/config + +app: + dashboard_url: "https://pangolin.akanealw.com" + log_level: "debug + save_logs: true + +domains: + domain1: + base_domain: "akanealw.com" + cert_resolver: "letsencrypt" + prefer_wildcard_cert: true + +server: + external_port: 3000 + internal_port: 3001 + next_port: 3002 + internal_hostname: "pangolin" + session_cookie_name: "p_session_token" + resource_access_token_param: "p_token" + resource_access_token_headers: + id: "P-Access-Token-Id" + token: "P-Access-Token" + resource_session_request_param: "p_session_request" + secret: CGjidUyt3AbKdYA3hpvsfbObKx2tyrdy + cors: + origins: ["https://pangolin.akanealw.com"] + methods: ["GET", "POST", "PUT", "DELETE", "PATCH"] + headers: ["X-CSRF-Token", "Content-Type"] + credentials: false + +traefik: + cert_resolver: "letsencrypt" + http_entrypoint: "web" + https_entrypoint: "websecure" + +gerbil: + start_port: 51820 + base_endpoint: "pangolin.akanealw.com" + use_subdomain: false + block_size: 24 + site_block_size: 30 + subnet_group: 100.89.137.0/20 + +rate_limits: + global: + window_minutes: 1 + max_requests: 500 + +email: + smtp_host: "smtp.gmail.com" + smtp_port: 587 + smtp_user: "akanealw@gmail.com" + smtp_pass: "dqtqnqvdmtgtvwjf" + no_reply: "akanealw@gmail.com" + +users: + server_admin: + email: "akanealw@gmail.com" + password: "Bungie1!" + +flags: + require_email_verification: true + disable_signup_without_invite: true + disable_user_create_org: false + allow_raw_resources: true + allow_base_domain_resources: true diff --git a/pangolin/config/traefik/dynamic_config.yml b/pangolin/config/traefik/dynamic_config.yml new file mode 100644 index 0000000..65045e3 --- /dev/null +++ b/pangolin/config/traefik/dynamic_config.yml @@ -0,0 +1,57 @@ +http: + middlewares: + redirect-to-https: + redirectScheme: + scheme: https + + routers: + # HTTP to HTTPS redirect router + main-app-router-redirect: + rule: "Host(`pangolin.akanealw.com`)" + service: next-service + entryPoints: + - web + middlewares: + - redirect-to-https + + # Next.js router (handles everything except API and WebSocket paths) + next-router: + rule: "Host(`pangolin.akanealw.com`) && !PathPrefix(`/api/v1`)" + service: next-service + entryPoints: + - websecure + tls: + certResolver: letsencrypt + domains: + - main: "akanealw.com" + sans: + - "*.akanealw.com" + + # API router (handles /api/v1 paths) + api-router: + rule: "Host(`pangolin.akanealw.com`) && PathPrefix(`/api/v1`)" + service: api-service + entryPoints: + - websecure + tls: + certResolver: letsencrypt + + # WebSocket router + ws-router: + rule: "Host(`pangolin.akanealw.com`)" + service: api-service + entryPoints: + - websecure + tls: + certResolver: letsencrypt + + services: + next-service: + loadBalancer: + servers: + - url: "http://pangolin:3002" # Next.js server + + api-service: + loadBalancer: + servers: + - url: "http://pangolin:3000" # API/WebSocket server diff --git a/pangolin/config/traefik/traefik_config.yml b/pangolin/config/traefik/traefik_config.yml new file mode 100644 index 0000000..b76b8ca --- /dev/null +++ b/pangolin/config/traefik/traefik_config.yml @@ -0,0 +1,44 @@ +api: + insecure: true + dashboard: true + +providers: + http: + endpoint: "http://pangolin:3001/api/v1/traefik-config" + pollInterval: "5s" + file: + filename: "/etc/traefik/dynamic_config.yml" + +experimental: + plugins: + badger: + moduleName: "github.com/fosrl/badger" + version: "v1.1.0" + +log: + level: "INFO" + format: "common" + +certificatesResolvers: + letsencrypt: + acme: + dnsChallenge: + provider: "cloudflare" + email: "akanealw@gmail.com" + storage: "/letsencrypt/acme.json" + caServer: "https://acme-v02.api.letsencrypt.org/directory" + +entryPoints: + web: + address: ":80" + websecure: + address: ":443" + transport: + respondingTimeouts: + readTimeout: "30m" + http: + tls: + certResolver: "letsencrypt" + +serversTransport: + insecureSkipVerify: true diff --git a/pangolin/docker-compose.yml b/pangolin/docker-compose.yml new file mode 100644 index 0000000..762b8ef --- /dev/null +++ b/pangolin/docker-compose.yml @@ -0,0 +1,150 @@ +services: + authentik-server: + image: ghcr.io/goauthentik/server:2025.2.2 + container_name: authentik-server + command: server + environment: + - AUTHENTIK_REDIS__HOST=authentik-redis + - AUTHENTIK_POSTGRESQL__HOST=authentik-postgres + - AUTHENTIK_POSTGRESQL__USER=authentik + - AUTHENTIK_POSTGRESQL__NAME=authentik + - AUTHENTIK_POSTGRESQL__PASSWORD=${POSTGRES_PASSWORD} + - AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY} + - AUTHENTIK_EMAIL__HOST=${AUTHENTIK_EMAIL__HOST} + - AUTHENTIK_EMAIL__PORT=${AUTHENTIK_EMAIL__PORT} + - AUTHENTIK_EMAIL__USERNAME=${AUTHENTIK_EMAIL__USERNAME} + - AUTHENTIK_EMAIL__PASSWORD=${AUTHENTIK_EMAIL__PASSWORD} + - AUTHENTIK_EMAIL__USE_TLS=${AUTHENTIK_EMAIL__USE_TLS} + - AUTHENTIK_EMAIL__USE_SSL=${AUTHENTIK_EMAIL__USE_SSL} + - AUTHENTIK_EMAIL__TIMEOUT=${AUTHENTIK_EMAIL__TIMEOUT} + - AUTHENTIK_EMAIL__FROM=${AUTHENTIK_EMAIL__FROM} + ports: + - 9000:9000 + - 9443:9443 + networks: + - authentik + - reverseproxy + volumes: + - ./config/authentik/media:/media + - ./config/authentik/custom-templates:/templates + depends_on: + - authentik-postgres + - authentik-redis + restart: unless-stopped + + authentik-worker: + image: ghcr.io/goauthentik/server:2025.2.2 + container_name: authentik-worker + command: worker + environment: + - AUTHENTIK_REDIS__HOST=authentik-redis + - AUTHENTIK_POSTGRESQL__HOST=authentik-postgres + - AUTHENTIK_POSTGRESQL__USER=authentik + - AUTHENTIK_POSTGRESQL__NAME=authentik + - AUTHENTIK_POSTGRESQL__PASSWORD=${POSTGRES_PASSWORD} + - AUTHENTIK_SECRET_KEY=${AUTHENTIK_SECRET_KEY} + - AUTHENTIK_EMAIL__HOST=${AUTHENTIK_EMAIL__HOST} + - AUTHENTIK_EMAIL__PORT=${AUTHENTIK_EMAIL__PORT} + - AUTHENTIK_EMAIL__USERNAME=${AUTHENTIK_EMAIL__USERNAME} + - AUTHENTIK_EMAIL__PASSWORD=${AUTHENTIK_EMAIL__PASSWORD} + - AUTHENTIK_EMAIL__USE_TLS=${AUTHENTIK_EMAIL__USE_TLS} + - AUTHENTIK_EMAIL__USE_SSL=${AUTHENTIK_EMAIL__USE_SSL} + - AUTHENTIK_EMAIL__TIMEOUT=${AUTHENTIK_EMAIL__TIMEOUT} + - AUTHENTIK_EMAIL__FROM=${AUTHENTIK_EMAIL__FROM} + networks: + - authentik + - reverseproxy + user: root + volumes: + - /run/docker.sock:/run/docker.sock + - ./config/authentik/media:/media + - ./config/authentik/certs:/certs + - ./config/authentik/custom-templates:/templates + depends_on: + - authentik-postgres + - authentik-redis + restart: unless-stopped + + authentik-redis: + image: docker.io/library/redis:7.4.2 + container_name: authentik-redis + command: --save 60 1 --loglevel warning + healthcheck: + test: ["CMD-SHELL", "redis-cli ping | grep PONG"] + start_period: 20s + interval: 30s + retries: 5 + timeout: 3s + networks: + - authentik + volumes: + - ./config/authentik/redis:/data + restart: unless-stopped + + authentik-postgres: + image: docker.io/library/postgres:17.4 + container_name: authentik-postgres + environment: + - POSTGRES_USER=authentik + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - POSTGRES_DB=authentik + - TZ=${TZ} + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U "authentik"'] + start_period: 30s + interval: 10s + timeout: 10s + retries: 5 + networks: + - authentik + volumes: + - ./config/authentik/postgres:/var/lib/postgresql/data + restart: unless-stopped + + pangolin: + image: fosrl/pangolin:1.3.1 + container_name: pangolin + restart: unless-stopped + networks: + - reverseproxy + volumes: + - ./config:/app/config + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"] + interval: "10s" + timeout: "10s" + retries: 15 + + traefik: + image: traefik:v3.3.6 + container_name: traefik + restart: unless-stopped + environment: + CLOUDFLARE_DNS_API_TOKEN: "5zUXBZfX5rfi2ixLIRLOLRN9PCJ8a7KnloBCrN5p" + networks: + - reverseproxy + ports: + - 443:443 + - 80:80 + depends_on: + pangolin: + condition: service_healthy + command: + - --configFile=/etc/traefik/traefik_config.yml + volumes: + - ./config/traefik:/etc/traefik:ro # Volume to store the Traefik configuration + - ./config/letsencrypt:/letsencrypt # Volume to store the Let's Encrypt certificates + - ./config/traefik/logs:/var/log/traefik # Volume to store Traefik logs + + whoami: + image: traefik/whoami + container_name: whoami + networks: + - reverseproxy + +networks: + authentik: + name: authentik + reverseproxy: + external: true + \ No newline at end of file