diff --git a/pixelfed/app.yaml b/pixelfed/app.yaml new file mode 100644 index 0000000..d13692b --- /dev/null +++ b/pixelfed/app.yaml @@ -0,0 +1,5 @@ +name: pixelfed +is: pixelfed +description: Pixelfed is a free and ethical photo sharing platform, federated via ActivityPub. +icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/pixelfed.svg +latest: "0" diff --git a/pixelfed/versions/0/README.md b/pixelfed/versions/0/README.md new file mode 100644 index 0000000..3158d86 --- /dev/null +++ b/pixelfed/versions/0/README.md @@ -0,0 +1,45 @@ +# Pixelfed + +Pixelfed is a federated, self-hosted photo sharing platform — a privacy-respecting alternative to Instagram, compatible with the ActivityPub protocol. + +## Dependencies + +- **PostgreSQL** - Database for storing posts and accounts +- **Redis** - Used for caching and job queuing +- **SMTP** - For account verification and notifications + +## Configuration + +Key settings in `config.yaml`: + +- **domain** - Where Pixelfed will be accessible +- **storage** - Persistent volume size (default: `2Gi`) +- **db.name** - Database name (default: `pixelfed`) +- **smtp** - Email settings inherited from your Wild Cloud SMTP service + +## First-Time Setup + +1. Add and deploy the app: + ```bash + wild app add pixelfed + wild app deploy pixelfed + ``` + +2. Create the admin user by running an artisan command in the pod: + ```bash + kubectl exec -n pixelfed deploy/pixelfed -- php artisan user:create \ + --name="Admin" \ + --username="admin" \ + --email="your@email.com" \ + --password="yourpassword" \ + --is_admin=1 \ + --confirm_email=1 + ``` + +3. Visit the app URL and log in with the credentials you just created. + +## Notes + +- This package uses the `ghcr.io/mattlqx/docker-pixelfed` community image (port 80, nginx) since the official image requires authentication to pull +- Federation with Mastodon and other ActivityPub platforms is enabled by default +- User registration can be set to open, invite-only, or closed via **Admin → Settings** diff --git a/pixelfed/versions/0/db-init-job.yaml b/pixelfed/versions/0/db-init-job.yaml new file mode 100644 index 0000000..34d1294 --- /dev/null +++ b/pixelfed/versions/0/db-init-job.yaml @@ -0,0 +1,59 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: pixelfed-db-init + labels: + component: db-init +spec: + template: + metadata: + labels: + component: db-init + spec: + restartPolicy: OnFailure + securityContext: + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + seccompProfile: + type: RuntimeDefault + containers: + - name: postgres-init + image: postgres:16 + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + env: + - name: PGHOST + value: {{ .db.host }} + - name: PGUSER + value: postgres + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: pixelfed-secrets + key: postgres.password + - name: DB_NAME + value: {{ .db.name }} + - name: DB_USER + value: {{ .db.user }} + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: pixelfed-secrets + key: dbPassword + command: + - /bin/bash + - -c + - | + set -e + until pg_isready; do sleep 2; done + psql -c "CREATE DATABASE ${DB_NAME};" || echo "Database already exists" + psql -c "CREATE USER ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';" || echo "User already exists" + psql -c "ALTER USER ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';" + psql -c "GRANT ALL PRIVILEGES ON DATABASE ${DB_NAME} TO ${DB_USER};" + psql -d ${DB_NAME} -c "GRANT ALL ON SCHEMA public TO ${DB_USER};" + echo "Done" diff --git a/pixelfed/versions/0/deployment-worker.yaml b/pixelfed/versions/0/deployment-worker.yaml new file mode 100644 index 0000000..86295e5 --- /dev/null +++ b/pixelfed/versions/0/deployment-worker.yaml @@ -0,0 +1,112 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pixelfed-worker + namespace: {{ .namespace }} +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + component: worker + template: + metadata: + labels: + component: worker + spec: + securityContext: + runAsNonRoot: true + runAsUser: 33 + runAsGroup: 33 + fsGroup: 33 + seccompProfile: + type: RuntimeDefault + containers: + - name: pixelfed-worker + image: ghcr.io/mattlqx/docker-pixelfed:v0.12.7-nginx + command: + - php + - artisan + - horizon + env: + - name: APP_NAME + value: Pixelfed + - name: APP_ENV + value: production + - name: APP_DEBUG + value: "false" + - name: APP_URL + value: https://{{ .domain }} + - name: APP_DOMAIN + value: {{ .domain }} + - name: APP_KEY + valueFrom: + secretKeyRef: + name: pixelfed-secrets + key: appKey + - name: DB_CONNECTION + value: pgsql + - name: DB_HOST + value: {{ .db.host }} + - name: DB_PORT + value: "{{ .db.port }}" + - name: DB_DATABASE + value: {{ .db.name }} + - name: DB_USERNAME + value: {{ .db.user }} + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: pixelfed-secrets + key: dbPassword + - name: REDIS_CLIENT + value: predis + - name: REDIS_HOST + value: {{ .redis.host }} + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: pixelfed-secrets + key: redis.password + - name: CACHE_DRIVER + value: redis + - name: SESSION_DRIVER + value: redis + - name: QUEUE_DRIVER + value: redis + - name: ACTIVITY_PUB + value: "1" + - name: AP_REMOTE_FOLLOW + value: "1" + - name: AP_INBOX + value: "1" + - name: AP_OUTBOX + value: "1" + - name: AP_SHAREDINBOX + value: "1" + resources: + limits: + cpu: 1000m + ephemeral-storage: 512Mi + memory: 1Gi + requests: + cpu: 50m + ephemeral-storage: 50Mi + memory: 256Mi + volumeMounts: + - name: pixelfed-storage + mountPath: /var/www/html/storage + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + volumes: + - name: pixelfed-storage + persistentVolumeClaim: + claimName: pixelfed-storage + restartPolicy: Always diff --git a/pixelfed/versions/0/deployment.yaml b/pixelfed/versions/0/deployment.yaml new file mode 100644 index 0000000..eadd2cb --- /dev/null +++ b/pixelfed/versions/0/deployment.yaml @@ -0,0 +1,161 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pixelfed + namespace: {{ .namespace }} +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + component: web + template: + metadata: + labels: + component: web + spec: + securityContext: + runAsNonRoot: true + runAsUser: 33 + runAsGroup: 33 + fsGroup: 33 + seccompProfile: + type: RuntimeDefault + containers: + - name: pixelfed + image: ghcr.io/mattlqx/docker-pixelfed:v0.12.7-nginx + ports: + - name: http + containerPort: 80 + protocol: TCP + env: + - name: APP_NAME + value: Pixelfed + - name: APP_ENV + value: production + - name: APP_DEBUG + value: "false" + - name: APP_PORT + value: "80" + - name: APP_URL + value: https://{{ .domain }} + - name: APP_DOMAIN + value: {{ .domain }} + - name: ADMIN_DOMAIN + value: {{ .domain }} + - name: SESSION_DOMAIN + value: {{ .domain }} + - name: APP_KEY + valueFrom: + secretKeyRef: + name: pixelfed-secrets + key: appKey + - name: DB_CONNECTION + value: pgsql + - name: DB_HOST + value: {{ .db.host }} + - name: DB_PORT + value: "{{ .db.port }}" + - name: DB_DATABASE + value: {{ .db.name }} + - name: DB_USERNAME + value: {{ .db.user }} + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: pixelfed-secrets + key: dbPassword + - name: REDIS_CLIENT + value: predis + - name: REDIS_HOST + value: {{ .redis.host }} + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: pixelfed-secrets + key: redis.password + - name: CACHE_DRIVER + value: redis + - name: SESSION_DRIVER + value: redis + - name: QUEUE_DRIVER + value: redis + - name: MAIL_MAILER + value: smtp + - name: MAIL_HOST + value: {{ .smtp.host }} + - name: MAIL_PORT + value: "{{ .smtp.port }}" + - name: MAIL_USERNAME + value: {{ .smtp.user }} + - name: MAIL_PASSWORD + valueFrom: + secretKeyRef: + name: pixelfed-secrets + key: smtpPassword + - name: MAIL_FROM_ADDRESS + value: {{ .smtp.from }} + - name: MAIL_ENCRYPTION + value: tls + - name: ACTIVITY_PUB + value: "1" + - name: AP_REMOTE_FOLLOW + value: "1" + - name: AP_INBOX + value: "1" + - name: AP_OUTBOX + value: "1" + - name: AP_SHAREDINBOX + value: "1" + - name: OAUTH_ENABLED + value: "true" + - name: OPEN_REGISTRATION + value: "true" + - name: FORCE_HTTPS + value: "true" + - name: PHP_POST_MAX_SIZE + value: 500M + - name: PHP_UPLOAD_MAX_FILE_SIZE + value: 500M + resources: + limits: + cpu: "1" + ephemeral-storage: 1Gi + memory: 1Gi + requests: + cpu: 50m + ephemeral-storage: 50Mi + memory: 256Mi + volumeMounts: + - name: pixelfed-storage + mountPath: /var/www/html/storage + livenessProbe: + httpGet: + path: /api/v1/instance + port: 80 + initialDelaySeconds: 120 + timeoutSeconds: 10 + periodSeconds: 30 + failureThreshold: 6 + readinessProbe: + httpGet: + path: /api/v1/instance + port: 80 + initialDelaySeconds: 60 + timeoutSeconds: 5 + periodSeconds: 15 + failureThreshold: 3 + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: false + volumes: + - name: pixelfed-storage + persistentVolumeClaim: + claimName: pixelfed-storage + restartPolicy: Always diff --git a/pixelfed/versions/0/ingress.yaml b/pixelfed/versions/0/ingress.yaml new file mode 100644 index 0000000..4010f68 --- /dev/null +++ b/pixelfed/versions/0/ingress.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: pixelfed + namespace: {{ .namespace }} + annotations: + external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }} + external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" + external-dns.alpha.kubernetes.io/ttl: "60" +spec: + ingressClassName: traefik + rules: + - host: {{ .domain }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: pixelfed + port: + number: 80 + tls: + - hosts: + - {{ .domain }} + secretName: {{ .tlsSecretName }} diff --git a/pixelfed/versions/0/kustomization.yaml b/pixelfed/versions/0/kustomization.yaml new file mode 100644 index 0000000..da635c5 --- /dev/null +++ b/pixelfed/versions/0/kustomization.yaml @@ -0,0 +1,17 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: {{ .namespace }} +labels: + - includeSelectors: true + pairs: + app: pixelfed + managedBy: kustomize + partOf: wild-cloud +resources: + - namespace.yaml + - db-init-job.yaml + - deployment.yaml + - deployment-worker.yaml + - service.yaml + - ingress.yaml + - pvc.yaml diff --git a/pixelfed/versions/0/manifest.yaml b/pixelfed/versions/0/manifest.yaml new file mode 100644 index 0000000..eb09287 --- /dev/null +++ b/pixelfed/versions/0/manifest.yaml @@ -0,0 +1,32 @@ +version: 0.12.7-1 +requires: + - name: postgres + - name: redis + - name: smtp +defaultConfig: + namespace: pixelfed + externalDnsDomain: '{{ .cloud.domain }}' + domain: pixelfed.{{ .cloud.domain }} + tlsSecretName: wildcard-wild-cloud-tls + storage: 2Gi + db: + host: '{{ .apps.postgres.host }}' + port: '{{ .apps.postgres.port }}' + name: pixelfed + user: pixelfed + redis: + host: '{{ .apps.redis.host }}' + smtp: + host: '{{ .apps.smtp.host }}' + port: '{{ .apps.smtp.port }}' + from: '{{ .apps.smtp.from }}' + user: '{{ .apps.smtp.user }}' +defaultSecrets: + - key: appKey + - key: dbPassword + - key: dbUrl + default: 'postgresql://{{ .app.db.user }}:{{ .secrets.dbPassword }}@{{ .app.db.host }}:{{ .app.db.port }}/{{ .app.db.name }}?sslmode=disable' + - key: smtpPassword +requiredSecrets: + - postgres.password + - redis.password diff --git a/pixelfed/versions/0/namespace.yaml b/pixelfed/versions/0/namespace.yaml new file mode 100644 index 0000000..054927e --- /dev/null +++ b/pixelfed/versions/0/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .namespace }} diff --git a/pixelfed/versions/0/pvc.yaml b/pixelfed/versions/0/pvc.yaml new file mode 100644 index 0000000..ea8a6ab --- /dev/null +++ b/pixelfed/versions/0/pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pixelfed-storage + namespace: {{ .namespace }} +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: {{ .storage }} diff --git a/pixelfed/versions/0/service.yaml b/pixelfed/versions/0/service.yaml new file mode 100644 index 0000000..004a95a --- /dev/null +++ b/pixelfed/versions/0/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: pixelfed + namespace: {{ .namespace }} +spec: + selector: + component: web + ports: + - name: http + port: 80 + targetPort: 80 + protocol: TCP