Files
homelab-manifests/privatebin-system/privatebin.yaml
T
2026-01-20 18:01:32 +01:00

421 lines
12 KiB
YAML

---
# PrivateBin - Zero-knowledge pastebin
# Domain: privatebin.dooplex.hu
# Authentication: Authentik proxy for POST (create), public GET (read)
# Version: 2.0.3
apiVersion: v1
kind: Namespace
metadata:
name: privatebin-system
labels:
app.kubernetes.io/name: privatebin
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: privatebin-data
namespace: privatebin-system
labels:
app.kubernetes.io/name: privatebin
app.kubernetes.io/instance: privatebin
recurring-job-group.longhorn.io/default: enabled
recurring-job.longhorn.io/source: enabled
annotations:
argocd.argoproj.io/sync-options: Prune=false
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: ConfigMap
metadata:
name: privatebin-configs
namespace: privatebin-system
labels:
app.kubernetes.io/name: privatebin
app.kubernetes.io/instance: privatebin
data:
conf.php: |
;<?php http_response_code(403); /*
; PrivateBin configuration
; https://github.com/PrivateBin/PrivateBin/wiki/Configuration
[main]
; Project name displayed on the website
name = "Dooplex Paste"
; Base path for OpenGraph/social media previews
basepath = "https://privatebin.dooplex.hu/"
; Enable discussion/comments feature
discussion = true
; Don't preselect discussion by default
opendiscussion = false
; Enable password protection option
password = true
; Allow file uploads (attached files)
fileupload = true
; Don't preselect burn after reading
burnafterreadingselected = false
; Default text formatter
defaultformatter = "syntaxhighlighting"
; Syntax highlighting theme (empty = default)
syntaxhighlightingtheme = "sons-of-obsidian"
; Maximum paste size (10 MB)
sizelimit = 10485760
; Use Bootstrap 5 template (dark mode)
template = "bootstrap-dark"
; Enable QR code generation for paste URLs
qrcode = true
; Enable email sharing button
email = true
; Icon style (identicon/jdenticon/vizhash/none)
icon = "jdenticon"
; Custom notice (optional)
; notice = "Note: Pastes may be deleted after expiration."
; Compression algorithm (zlib/none)
compression = "zlib"
[expire]
; Default expiration time
default = "1week"
[expire_options]
; Available expiration options
5min = 300
10min = 600
1hour = 3600
1day = 86400
1week = 604800
1month = 2592000
1year = 31536000
never = 0
[formatter_options]
; Available formatters
plaintext = "Plain Text"
syntaxhighlighting = "Source Code"
markdown = "Markdown"
[traffic]
; Rate limiting - 10 seconds between paste creations per IP
limit = 10
; Exempted IPs from rate limiting (internal networks)
exempted = "10.42.0.0/16,10.43.0.0/16"
; Traffic limit in bytes (0 = no limit)
; creators = 0
[purge]
; Purge expired pastes probability (1 in X requests)
limit = 300
; Maximum items to delete per purge
batchsize = 10
[model]
; Use filesystem storage
class = Filesystem
[model_options]
; Data directory (mounted via PVC)
dir = PATH "data"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: privatebin
namespace: privatebin-system
labels:
app.kubernetes.io/name: privatebin
app.kubernetes.io/instance: privatebin
app.kubernetes.io/version: "2.0.3"
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: privatebin
app.kubernetes.io/instance: privatebin
template:
metadata:
labels:
app.kubernetes.io/name: privatebin
app.kubernetes.io/instance: privatebin
app.kubernetes.io/version: "2.0.3"
spec:
automountServiceAccountToken: false
securityContext:
runAsUser: 65534
runAsGroup: 82
fsGroup: 82
containers:
- name: privatebin
image: privatebin/nginx-fpm-alpine:2.0.3
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
protocol: TCP
securityContext:
readOnlyRootFilesystem: true
privileged: false
allowPrivilegeEscalation: false
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
volumeMounts:
- name: configs
mountPath: /srv/cfg
- name: data
mountPath: /srv/data
- name: run
mountPath: /run
- name: tmp
mountPath: /tmp
- name: nginx-cache
mountPath: /var/lib/nginx/tmp
volumes:
- name: configs
configMap:
name: privatebin-configs
- name: data
persistentVolumeClaim:
claimName: privatebin-data
- name: run
emptyDir:
medium: Memory
- name: tmp
emptyDir:
medium: Memory
- name: nginx-cache
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: privatebin
namespace: privatebin-system
labels:
app.kubernetes.io/name: privatebin
app.kubernetes.io/instance: privatebin
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: http
protocol: TCP
selector:
app.kubernetes.io/name: privatebin
app.kubernetes.io/instance: privatebin
---
# =============================================================================
# INGRESS CONFIGURATION
# =============================================================================
#
# OPTION 1 (Current): Public access on both domains
# - privatebin.dooplex.hu - public HTTPS access
# - privatebin.home - internal access
#
# OPTION 2: Authenticated writes, public reads
# This requires Authentik configuration (see instructions below).
# Comment out the public ingress and uncomment the authenticated one.
#
# =============================================================================
# PUBLIC INGRESS - No authentication required
# Anyone can create and view pastes
#apiVersion: networking.k8s.io/v1
#kind: Ingress
#metadata:
# name: privatebin
# namespace: privatebin-system
# labels:
# app.kubernetes.io/name: privatebin
# app.kubernetes.io/instance: privatebin
# annotations:
# cert-manager.io/cluster-issuer: letsencrypt-prod
# external-dns.alpha.kubernetes.io/hostname: privatebin.home,privatebin.dooplex.hu
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
# nginx.ingress.kubernetes.io/proxy-body-size: "12m"
#spec:
# ingressClassName: nginx-internal
# tls:
# - hosts:
# - privatebin.dooplex.hu
# secretName: privatebin-tls
# rules:
# - host: privatebin.dooplex.hu
# http:
# paths:
# - path: /
# pathType: Prefix
# backend:
# service:
# name: privatebin
# port:
# number: 80
# - host: privatebin.home
# http:
# paths:
# - path: /
# pathType: Prefix
# backend:
# service:
# name: privatebin
# port:
# number: 80
#
# =============================================================================
# AUTHENTICATED INGRESS (Optional)
# =============================================================================
# To enable authentication for creating pastes while keeping viewing public,
# follow these steps:
#
# 1. AUTHENTIK SETUP:
# a) Create Application:
# - Name: PrivateBin
# - Slug: privatebin
# - Provider: (create new proxy provider below)
#
# b) Create Proxy Provider:
# - Name: privatebin-provider
# - Authorization flow: default-provider-authorization-implicit-consent
# - Mode: Forward auth (single application)
# - External host: https://privatebin.dooplex.hu
#
# c) Create Expression Policy for conditional auth:
# - Name: privatebin-method-check
# - Expression:
# # GET/HEAD requests pass through without requiring login
# # POST requests require authentication
# if request.http_request.method in ["GET", "HEAD", "OPTIONS"]:
# # Pass the policy - but note: user may still not be authenticated
# # The key is setting "Unauthenticated URLs" below
# return True
# # For POST/PUT/DELETE, require the user to be authenticated
# if request.user.is_authenticated:
# return True
# return False
#
# d) Configure Provider settings:
# - Unauthenticated URLs: ^https://privatebin\.dooplex\.hu/\?[a-f0-9]+.*$
# (This regex matches paste view URLs)
# - Or simpler: Check "Intercept header authentication" in advanced settings
# and handle auth at ingress level
#
# e) Create/Update Outpost:
# - Name: privatebin-outpost
# - Type: Proxy
# - Add the PrivateBin application
#
# 2. UPDATE INGRESS:
# Comment out the public ingress above and uncomment this one:
#
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: privatebin
namespace: privatebin-system
labels:
app.kubernetes.io/name: privatebin
app.kubernetes.io/instance: privatebin
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
external-dns.alpha.kubernetes.io/hostname: privatebin.home,privatebin.dooplex.hu
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "12m"
nginx.ingress.kubernetes.io/auth-url: http://ak-outpost-privatebin-outpost.auth-system.svc.cluster.local:9000/outpost.goauthentik.io/auth/nginx
nginx.ingress.kubernetes.io/auth-signin: https://privatebin.dooplex.hu/outpost.goauthentik.io/start?rd=$escaped_request_uri
nginx.ingress.kubernetes.io/auth-response-headers: Set-Cookie,X-authentik-username,X-authentik-groups,X-authentik-email
nginx.ingress.kubernetes.io/auth-snippet: |
proxy_set_header X-Forwarded-Host $http_host;
nginx.ingress.kubernetes.io/proxy-buffer-size: "16k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "4"
nginx.ingress.kubernetes.io/proxy-busy-buffers-size: "32k"
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($geoip2_country_code != "HU") {
return 403 "Access restricted to Hungary";
}
spec:
ingressClassName: nginx-internal
tls:
- hosts:
- privatebin.dooplex.hu
secretName: privatebin-tls
rules:
- host: privatebin.dooplex.hu
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: privatebin
port:
number: 80
- host: privatebin.home
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: privatebin
port:
number: 80
#
# 3. ALTERNATIVE: Use existing outpost
# If you want to use an existing outpost (like arr-outpost),
# just add privatebin.dooplex.hu to that outpost's applications
# and update the auth-url to point to that outpost.
---
# ServiceAccount (minimal, not needed but good practice)
apiVersion: v1
kind: ServiceAccount
metadata:
name: privatebin
namespace: privatebin-system
labels:
app.kubernetes.io/name: privatebin
app.kubernetes.io/instance: privatebin
automountServiceAccountToken: false