Reorganized for new stable/waypoint versioning design.

This commit is contained in:
2026-05-24 18:28:47 +00:00
parent 945d2225a2
commit bc7a168851
352 changed files with 1264 additions and 294 deletions

View File

@@ -0,0 +1,41 @@
# Lemmy
Lemmy is a selfhosted social link aggregation and discussion platform. It is an open-source alternative to Reddit, designed for the fediverse.
## Dependencies
- **PostgreSQL** - Database for storing communities, posts, and comments
## Components
Lemmy runs three separate services:
- **Backend** - Rust API server handling federation and data
- **UI** - Web frontend for browsing and interacting
- **pict-rs** - Image hosting and processing service
## Configuration
Key settings configured through your instance's `config.yaml`:
- **domain** - Where Lemmy will be accessible (default: `lemmy.{your-cloud-domain}`)
- **storage** - Persistent volume for application data (default: `10Gi`)
- **pictrsStorage** - Persistent volume for uploaded images (default: `50Gi`)
- **SMTP** - Email delivery settings inherited from your Wild Cloud instance
## Access
After deployment, Lemmy will be available at:
- `https://lemmy.{your-cloud-domain}`
## First-Time Setup
1. Add and deploy the app:
```bash
wild app add lemmy
wild app deploy lemmy
```
2. Create your admin account through the web interface
3. Set up your first community and customize your instance settings

View File

@@ -0,0 +1,36 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: lemmy-config
namespace: {{ .namespace }}
data:
lemmy.hjson: |
{
hostname: "{{ .domain }}"
bind: "0.0.0.0"
port: 8536
tls_enabled: false
database: {
uri: "postgresql://{{ .db.user }}:DBPASSWORD@{{ .db.host }}:{{ .db.port }}/{{ .db.name }}"
}
pictrs: {
url: "http://lemmy-pictrs:8080/"
api_key: "PICTRS_API_KEY"
}
email: {
smtp_server: "{{ .smtp.host }}:{{ .smtp.port }}"
smtp_login: "{{ .smtp.user }}"
smtp_password: "SMTP_PASSWORD"
smtp_from_address: "{{ .smtp.from }}"
tls_type: "{{ if eq .smtp.tls "true" }}tls{{ else }}none{{ end }}"
}
setup: {
admin_username: "admin"
admin_password: "ADMIN_PASSWORD"
site_name: "Lemmy"
}
}

View File

@@ -0,0 +1,76 @@
apiVersion: batch/v1
kind: Job
metadata:
name: lemmy-db-init
namespace: {{ .namespace }}
spec:
template:
metadata:
labels:
component: db-init
spec:
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 999
runAsGroup: 999
seccompProfile:
type: RuntimeDefault
containers:
- name: db-init
image: postgres:16-alpine
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: false
env:
- name: PGHOST
value: "{{ .db.host }}"
- name: PGPORT
value: "{{ .db.port }}"
- name: PGUSER
value: postgres
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: postgres.password
- name: DB_NAME
value: "{{ .db.name }}"
- name: DB_USER
value: "{{ .db.user }}"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: dbPassword
command:
- sh
- -c
- |
set -e
echo "Waiting for PostgreSQL to be ready..."
until pg_isready -h $PGHOST -p $PGPORT -U $PGUSER; do
echo "Waiting for database connection..."
sleep 2
done
echo "Creating database and user..."
psql -v ON_ERROR_STOP=1 <<-EOSQL
SELECT 'CREATE DATABASE ${DB_NAME}' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${DB_NAME}')\gexec
DO \$\$
BEGIN
IF NOT EXISTS (SELECT FROM pg_user WHERE usename = '${DB_USER}') THEN
CREATE USER ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';
ELSE
ALTER USER ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';
END IF;
END
\$\$;
GRANT ALL PRIVILEGES ON DATABASE ${DB_NAME} TO ${DB_USER};
\c ${DB_NAME}
GRANT ALL ON SCHEMA public TO ${DB_USER};
EOSQL
echo "Database initialization completed successfully"

View File

@@ -0,0 +1,102 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: lemmy-backend
namespace: {{ .namespace }}
spec:
replicas: 1
selector:
matchLabels:
component: backend
template:
metadata:
labels:
component: backend
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
initContainers:
- name: config-prep
image: busybox:stable
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: true
command:
- sh
- -c
- |
cp /config-template/lemmy.hjson /config/lemmy.hjson
sed -i "s|DBPASSWORD|${DB_PASSWORD}|g" /config/lemmy.hjson
sed -i "s|PICTRS_API_KEY|${PICTRS_API_KEY}|g" /config/lemmy.hjson
sed -i "s|SMTP_PASSWORD|${SMTP_PASSWORD}|g" /config/lemmy.hjson
sed -i "s|ADMIN_PASSWORD|${ADMIN_PASSWORD}|g" /config/lemmy.hjson
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: dbPassword
- name: PICTRS_API_KEY
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: jwtSecret
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: smtpPassword
- name: ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: adminPassword
volumeMounts:
- name: config-template
mountPath: /config-template
- name: config
mountPath: /config
containers:
- name: backend
image: dessalines/lemmy:0.19.15
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: false
env:
- name: LEMMY_CONFIG_LOCATION
value: /config/lemmy.hjson
- name: TZ
value: "UTC"
ports:
- containerPort: 8536
name: http
volumeMounts:
- name: config
mountPath: /config
livenessProbe:
httpGet:
path: /api/v3/site
port: 8536
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /api/v3/site
port: 8536
initialDelaySeconds: 10
periodSeconds: 5
volumes:
- name: config-template
configMap:
name: lemmy-config
- name: config
emptyDir: {}

View File

@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: lemmy-pictrs
namespace: {{ .namespace }}
spec:
replicas: 1
selector:
matchLabels:
component: pictrs
template:
metadata:
labels:
component: pictrs
spec:
securityContext:
runAsNonRoot: true
runAsUser: 991
runAsGroup: 991
fsGroup: 991
seccompProfile:
type: RuntimeDefault
containers:
- name: pictrs
image: asonix/pictrs:0.5.5
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: false
env:
- name: PICTRS__SERVER__BIND
value: "0.0.0.0:8080"
- name: PICTRS__MEDIA__VIDEO_CODEC
value: vp9
- name: PICTRS__MEDIA__GIF__MAX_WIDTH
value: "256"
- name: PICTRS__MEDIA__GIF__MAX_HEIGHT
value: "256"
- name: PICTRS__MEDIA__GIF__MAX_AREA
value: "65536"
- name: PICTRS__MEDIA__GIF__MAX_FRAME_COUNT
value: "400"
- name: RUST_LOG
value: debug
- name: RUST_BACKTRACE
value: full
- name: PICTRS__REPO__TYPE
value: sled
- name: PICTRS__REPO__PATH
value: /mnt/sled-repo
- name: PICTRS__STORE__TYPE
value: filesystem
- name: PICTRS__STORE__PATH
value: /mnt/files
ports:
- containerPort: 8080
name: http
volumeMounts:
- name: storage
mountPath: /mnt
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
volumes:
- name: storage
persistentVolumeClaim:
claimName: lemmy-pictrs-storage

View File

@@ -0,0 +1,53 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: lemmy-ui
namespace: {{ .namespace }}
spec:
replicas: 1
selector:
matchLabels:
component: ui
template:
metadata:
labels:
component: ui
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: ui
image: dessalines/lemmy-ui:0.19.15
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: false
env:
- name: LEMMY_UI_LEMMY_INTERNAL_HOST
value: "lemmy-backend:8536"
- name: LEMMY_UI_LEMMY_EXTERNAL_HOST
value: "{{ .domain }}"
- name: LEMMY_UI_HTTPS
value: "true"
ports:
- containerPort: 1234
name: http
livenessProbe:
httpGet:
path: /
port: 1234
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /
port: 1234
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 5

View File

@@ -0,0 +1,42 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: lemmy-ingress
namespace: {{ .namespace }}
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }}
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
spec:
ingressClassName: traefik
tls:
- hosts:
- {{ .domain }}
secretName: {{ .tlsSecretName }}
rules:
- host: {{ .domain }}
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: lemmy-backend
port:
number: 8536
- path: /pictrs
pathType: Prefix
backend:
service:
name: lemmy-pictrs
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: lemmy-ui
port:
number: 1234

View File

@@ -0,0 +1,21 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: lemmy
labels:
- includeSelectors: true
pairs:
app: lemmy
managedBy: kustomize
partOf: wild-cloud
resources:
- namespace.yaml
- configmap.yaml
- pvc-pictrs.yaml
- db-init-job.yaml
- deployment-pictrs.yaml
- service-pictrs.yaml
- deployment-backend.yaml
- service-backend.yaml
- deployment-ui.yaml
- service-ui.yaml
- ingress.yaml

View File

@@ -0,0 +1,29 @@
version: 0.19.15-2
requires:
- name: postgres
- name: smtp
defaultConfig:
namespace: lemmy
externalDnsDomain: lemmy.{{ .cloud.baseDomain }}
domain: lemmy.{{ .cloud.domain }}
tlsSecretName: wildcard-wild-cloud-tls
storage: 10Gi
pictrsStorage: 50Gi
db:
host: '{{ .apps.postgres.host }}'
port: '{{ .apps.postgres.port }}'
name: lemmy
user: lemmy
smtp:
host: '{{ .apps.smtp.host }}'
port: '{{ .apps.smtp.port }}'
user: '{{ .apps.smtp.user }}'
from: 'noreply@{{ .cloud.baseDomain }}'
tls: '{{ .apps.smtp.tls }}'
defaultSecrets:
- key: dbPassword
- key: adminPassword
- key: jwtSecret
- key: smtpPassword
requiredSecrets:
- postgres.password

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: {{ .namespace }}

View File

@@ -0,0 +1,11 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: lemmy-pictrs-storage
namespace: {{ .namespace }}
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .pictrsStorage }}

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: lemmy-backend
namespace: {{ .namespace }}
spec:
type: ClusterIP
selector:
component: backend
ports:
- name: http
port: 8536
targetPort: 8536

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: lemmy-pictrs
namespace: {{ .namespace }}
spec:
type: ClusterIP
selector:
component: pictrs
ports:
- name: http
port: 8080
targetPort: 8080

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: lemmy-ui
namespace: {{ .namespace }}
spec:
type: ClusterIP
selector:
component: ui
ports:
- name: http
port: 1234
targetPort: 1234