Maxmind added. Pangolin handles certs.

- You can use Geo-blocking now. Maxmind added.
- Traefik conf files updated to handle certificates.
- Ingress changed to forward TCP to Pangolin
- Updated README.md with new changes.
This commit is contained in:
xoffio
2025-11-10 22:03:02 -05:00
parent a49ff6711b
commit 2bc5dbc7f0
7 changed files with 188 additions and 59 deletions

View File

@@ -10,10 +10,22 @@ cd xo-pangolin
# Install example:
helm install pangolin xo-pangolin \
--set-string settings.pangolin.serverSecretKey=SECRET_KEY_HERE \
--set-string ingress.hostDomain="pangolin.test" \
--set-string settings.traefik.certificatesResolver.email=YOUR_EMAIL_HERE \
--set-string ingress.hostDomain="YOUR_DOMAIN_HERE" \
--set-string volumes[0].name=vol-pangolin \
--set-string volumes[0].nfs.path=/volume/cluster/pangolin \
--set-string volumes[0].nfs.server=nas.lan
--set-string volumes[0].nfs.server=nas.lan \
--set settings.pangolin.email.enabled=true \
--set settings.pangolin.email.smtp_host=nas.lan \
--set settings.pangolin.email.smtp_port=587 \
--set settings.pangolin.email.smtp_user="SMTP_USER_HERE" \
--set settings.pangolin.email.smtp_pass="SMTP_PASS_HERE" \
--set settings.pangolin.email.smtp_tls_reject_unauthorized=false \
--set settings.traefik.proxyProtocol.enabled=true \
--set settings.traefik.proxyProtocol.trustedIPs[0]="10.48.0.0/16" \
--set settings.maxmind.enabled=true \
--set settings.maxmind.id="MAXMIND_ID_HERE" \
--set settings.maxmind.key="MAXMIND_KEY_KERE" \
# Uninstall example:
helm uninstall pangolin

View File

@@ -11,9 +11,19 @@ server:
secret: "{{ .Values.settings.pangolin.serverSecretKey }}"
internal_hostname: "{{ include "xo-pangolin.fullname" . }}-pangolin-cip.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain | default "cluster.local" }}"
{{- if .Values.settings.maxmind.enabled }}
maxmind_db_path: "/app/config/maxmind/GeoLite2-Country.mmdb"
{{- end }}
gerbil:
base_endpoint: "{{ .Values.ingress.hostDomain }}"
{{- if .Values.settings.xo-pangolin.email.enabled }}
{{- $email := omit .Values.settings.xo-pangolin.email "enabled" }}
email:
{{- toYaml $email | nindent 2 }}
{{- end }}
flags:
require_email_verification: false
disable_signup_without_invite: true

View File

@@ -1,21 +1,51 @@
http:
middlewares:
redirect-to-https:
redirectScheme:
scheme: https
routers:
# HTTP to HTTPS redirect router
main-app-router-redirect:
rule: Host(`{{ .Values.ingress.hostDomain }}`)
service: next-service
entryPoints:
- web
middlewares:
- redirect-to-https
# Next.js router (handles everything except API and WebSocket paths)
next-router:
rule: Host(`{{ .Values.ingress.hostDomain }}`) && !PathPrefix(`/api/v1`)
service: next-service
entryPoints: [web]
entryPoints:
- websecure
tls:
certResolver: letsencrypt
# API router (handles /api/v1 paths)
api-router:
rule: "Host(`{{ .Values.ingress.hostDomain }}`) && PathPrefix(`/api/v1`)"
service: api-service
entryPoints: [web]
entryPoints:
- websecure
tls:
certResolver: letsencrypt
# WebSocket router
ws-router:
rule: "Host(`{{ .Values.ingress.hostDomain }}`)"
service: api-service
entryPoints: [web]
entryPoints:
- websecure
tls:
certResolver: letsencrypt
services:
next-service:
loadBalancer:
servers: [{ url: "http://{{ include "xo-pangolin.fullname" . }}-pangolin-cip.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain | default "cluster.local" }}:3002" }]
servers:
- url: "http://{{ include "xo-pangolin.fullname" . }}-pangolin-cip.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain | default "cluster.local" }}:3002"
api-service:
loadBalancer:
servers: [{ url: "http://{{ include "xo-pangolin.fullname" . }}-pangolin-cip.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain | default "cluster.local" }}:3000" }]
servers:
- url: "http://{{ include "xo-pangolin.fullname" . }}-pangolin-cip.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain | default "cluster.local" }}:3000"

View File

@@ -16,9 +16,7 @@ log:
format: "common"
accessLog:
# JSON format
format: json
# Filter on status codes, retry attempts and minimal duration
filters:
statusCodes:
- "200-599"
@@ -29,11 +27,38 @@ accessLog:
User-Agent: keep
X-Forwarded-For: keep
certificatesResolvers:
letsencrypt:
acme:
httpChallenge:
entryPoint: web
email: {{ .Values.settings.traefik.certificatesResolver.email }}
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"
{{- if .Values.settings.traefik.proxyProtocol.enabled }}
proxyProtocol:
{{- if .Values.settings.traefik.proxyProtocol.insecure }}
# for testing; better to use trustedIPs in prod
insecure: true
{{- else if .Values.settings.traefik.proxyProtocol.trustedIPs }}
trustedIPs:
{{- range .Values.settings.traefik.proxyProtocol.trustedIPs }}
- {{ . | quote }}
{{- end }}
{{- end }}
{{- end }}
serversTransport:
insecureSkipVerify: true

View File

@@ -0,0 +1,43 @@
{{- if .Values.settings.maxmind.enabled }}
{{- $fullName := include "xo-pangolin.fullname" . -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "xo-pangolin.fullname" . }}-maxmind
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: maxmind
template:
metadata:
labels:
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: maxmind
app: {{ include "xo-pangolin.fullname" . }}-maxmind
spec:
containers:
- name: maxmind
image: "{{ .Values.deployments.maxmind.image.repository }}:{{ .Values.deployments.maxmind.image.tag }}"
imagePullPolicy: "{{ .Values.deployments.maxmind.image.pullPolicy }}"
env:
- name: GEOIPUPDATE_ACCOUNT_ID
value: "{{ .Values.settings.maxmind.id }}"
- name: GEOIPUPDATE_LICENSE_KEY
value: "{{ .Values.settings.maxmind.key }}"
- name: GEOIPUPDATE_FREQUENCY
value: "{{ .Values.settings.maxmind.frequency }}"
- name: GEOIPUPDATE_EDITION_IDS
value: "{{ .Values.settings.maxmind.dbs }}"
{{- $vols := required "values.volumes must be a non-empty list" .Values.volumes }}
{{- $first := required "values.volumes[0] is missing" (index $vols 0) }}
{{- $volName := required "values.volumes[0].name is required" $first.name }}
volumeMounts:
- mountPath: /usr/share/GeoIP
name: {{ $volName }}
subPath: config/maxmind
volumes:
{{- toYaml $vols | nindent 8 }}
{{- end }}

View File

@@ -1,35 +1,32 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
{{- $fullName := include "xo-pangolin.fullname" . -}}
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: {{ include "xo-pangolin.fullname" . }}-pangolin-in
name: {{ $fullName }}-pangolin-http-ingress
spec:
rules:
- host: {{ .Values.ingress.hostDomain }}
http:
paths:
- backend:
service:
name: {{ include "xo-pangolin.fullname" . }}-gerbil-cip
port:
number: 80
path: /
pathType: Prefix
- backend:
service:
name: {{ include "xo-pangolin.fullname" . }}-gerbil-cip
port:
number: 80
path: /api/v1
pathType: Prefix
- host: '*.{{ .Values.ingress.hostDomain }}'
http:
paths:
- backend:
service:
name: {{ include "xo-pangolin.fullname" . }}-gerbil-cip
port:
number: 80
path: /
pathType: Prefix
{{- end }}
entryPoints:
- web
routes:
- match: Host(`{{ .Values.ingress.hostDomain }}`) || HostRegexp(`^.+\.{{ .Values.ingress.hostDomain }}`)
services:
- name: {{ $fullName }}-gerbil-cip
port: 80
---
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: {{ $fullName }}-pangolin-tcp-ingress
spec:
entryPoints:
- websecure
routes:
- match: HostSNI(`{{ .Values.ingress.hostDomain }}`) || HostSNIRegexp(`^.+\.{{ .Values.ingress.hostDomain }}$`)
services:
- name: {{ $fullName }}-gerbil-cip
port: 443
{{- if .Values.settings.traefik.proxyProtocol.enabled }}
proxyProtocol:
version: 2
{{- end }}
tls:
passthrough: true

View File

@@ -4,9 +4,30 @@
settings:
pangolin:
serverSecretKey: 'SECRET_KEY_HERE'
serverSecretKey: ''
email:
enabled: false
# smtp_host: ""
# smtp_port: 587
# smtp_user: ""
# smtp_pass: ""
# smtp_tls_reject_unauthorized: false
traefik:
badgerVersion: "v1.2.0"
certificatesResolver:
email: ""
proxyProtocol:
enabled: false
insecure: false
trustedIPs: []
maxmind:
enabled: false
id: ""
key: ""
frequency: 24
dbs: "GeoLite2-ASN GeoLite2-City GeoLite2-Country"
deployments:
pangolin:
@@ -14,7 +35,7 @@ deployments:
image:
repository: "fosrl/pangolin"
pullPolicy: IfNotPresent
tag: "1.11.0"
tag: "1.12.1"
gerbil:
replicaCount: 1
image:
@@ -27,24 +48,15 @@ deployments:
repository: "traefik"
pullPolicy: IfNotPresent
tag: "3.4.0"
maxmind:
replicaCount: 1
image:
repository: "maxmindinc/geoipupdate"
pullPolicy: IfNotPresent
tag: "v7.1"
# This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/
ingress:
hostDomain: pangolin.test
enabled: true
className: ""
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
# Additional volumes on the output Deployment definition.
volumes: []