This commit is contained in:
Captain Arepa 2025-03-19 14:56:09 -04:00
commit af7c117071
8 changed files with 698 additions and 0 deletions

16
.ex.env Normal file
View file

@ -0,0 +1,16 @@
# .env
# Domain settings
DOMAIN=yourdomain.com
INSTANCE_NAME=YourPleromaInstance
# Database credentials
DB_USER=pleroma
DB_PASS=your_secure_db_password
DB_NAME=pleroma
# Admin credentials
ADMIN_EMAIL=admin@yourdomain.com
NOTIFY_EMAIL=notify@yourdomain.com
# Cloudflared credentials (if using Cloudflared container)
CLOUDFLARED_TOKEN=your_cloudflared_token

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
./cloudflared/config.yaml
./config/config.exs
.env

581
README.md Normal file
View file

@ -0,0 +1,581 @@
# Pleroma Docker Setup Guide
This guide outlines the setup of a Pleroma instance (backend and custom frontend) using Docker Compose, including Nginx reverse proxy, Cloudflared tunneling, persistent volumes, custom networking, updates, monitoring, and resource limits. The current date is March 19, 2025.
---
## Initial Docker Compose Setup
Pleroma doesnt have an official Docker image, so we build it from source. Heres the initial `docker-compose.yaml` with backend, frontend, and PostgreSQL:
### docker-compose.yaml
```yaml
version: "3.8"
services:
db:
image: postgres:15-alpine
container_name: pleroma_db
restart: always
environment:
POSTGRES_USER: pleroma
POSTGRES_PASSWORD: your_secure_password_here
POSTGRES_DB: pleroma
volumes:
- ./postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "pleroma"]
interval: 10s
timeout: 5s
retries: 5
pleroma_backend:
build:
context: ./pleroma_backend
dockerfile: Dockerfile
container_name: pleroma_backend
restart: always
ports:
- "4000:4000"
environment:
DOMAIN: yourdomain.com
INSTANCE_NAME: YourPleromaInstance
ADMIN_EMAIL: admin@yourdomain.com
NOTIFY_EMAIL: notify@yourdomain.com
DB_USER: pleroma
DB_PASS: your_secure_password_here
DB_NAME: pleroma
volumes:
- ./uploads:/var/lib/pleroma/uploads
- ./static:/var/lib/pleroma/static
- ./config:/etc/pleroma
depends_on:
db:
condition: service_healthy
command: ["/bin/sh", "-c", "mix ecto.migrate && ./bin/pleroma start"]
pleroma_frontend:
build:
context: ./pleroma_frontend
dockerfile: Dockerfile
container_name: pleroma_frontend
restart: always
volumes:
- ./pleroma_frontend/dist:/app/dist
```
### Backend (pleroma_backend/Dockerfile)
```
FROM elixir:1.14-alpine AS builder
RUN apk add --no-cache git build-base cmake postgresql-dev
WORKDIR /pleroma
RUN git clone https://git.pleroma.social/pleroma/pleroma.git .
RUN mix local.hex --force && mix local.rebar --force
RUN mix deps.get
RUN mix compile
RUN mkdir -p /etc/pleroma
FROM elixir:1.14-alpine
RUN apk add --no-cache postgresql-client
WORKDIR /pleroma
COPY --from=builder /pleroma /pleroma
ENV MIX_ENV=prod
EXPOSE 4000
CMD ["/bin/sh"]
```
### Frontend (pleroma_frontend/Dockerfile)
```
FROM node:18-alpine AS builder
WORKDIR /app
RUN apk add --no-cache git && \
git clone https://git.pleroma.social/pleroma/pleroma-fe.git .
RUN npm install
RUN npm run build
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/dist /app/dist
```
### Configuration file (config/config.exs)
```
use Mix.Config
config :pleroma, Pleroma.Web.Endpoint,
url: [host: "yourdomain.com", scheme: "https", port: 443],
http: [port: 4000]
config :pleroma, :instance,
name: "YourPleromaInstance",
email: "admin@yourdomain.com",
notify_email: "notify@yourdomain.com",
limit: 5000,
registrations_open: false
config :pleroma, Pleroma.Repo,
adapter: Ecto.Adapters.Postgres,
username: "pleroma",
password: "your_secure_password_here",
database: "pleroma",
hostname: "db"
```
### Directory structure (this folder)
```
your_project/
├── docker-compose.yaml
├── pleroma_backend/
│ └── Dockerfile
├── pleroma_frontend/
│ └── Dockerfile
├── config/
│ └── config.exs
├── postgres_data/ (auto-created)
├── uploads/ (auto-created)
└── static/ (auto-created)
```
### Running
1. Initialize DB: `docker-compose up -d db && docker exec -it pleroma_db psql -U pleroma -c "CREATE EXTENSION IF NOT EXISTS citext;`
2. Start build: `docker-compose up -d --build`
3. Access localhost: `http://localhost:4000`
## Optional
### Add nginx reverse proxy
Updated `docker-compose.yaml`
```
version: "3.8"
services:
db: # (unchanged)
pleroma_backend: # (remove ports: "4000:4000")
pleroma_frontend: # (unchanged)
nginx:
image: nginx:alpine
container_name: pleroma_nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./certs:/etc/nginx/certs
- ./static:/var/lib/pleroma/static:ro
depends_on:
- pleroma_backend
certbot:
image: certbot/certbot
container_name: pleroma_certbot
volumes:
- ./certs:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --post-hook \"docker exec pleroma_nginx nginx -s reload\"; sleep 12h; done;'"
depends_on:
- nginx
```
### Nginx config (nginx/conf.d/pleroma.conf)
```
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/nginx/certs/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://pleroma_backend:4000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /websocket {
proxy_pass http://pleroma_backend:4000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
### Certificate setup
1. Start nginx: `docker-compose up -d nginx`
2. Get certs: `docker-compose run --rm certbot certonly --webroot -w /var/www/certbot -d yourdomain.com`
3. Restart container: `docker-compose restart nginx`
## Persistent volumes and Cloudflared
### Persistent volumes (docker-compose.yaml)
```
version: "3.8"
services:
db: # (unchanged)
pleroma_backend: # (unchanged)
pleroma_frontend:
# (unchanged except volume renamed to ./pleroma_frontend_dist:/app/dist)
```
### Migration
1. Stop container `docker-compose down`
2. Compress `tar -czf pleroma_backup.tar.gz postgres_data uploads static config docker-compose.yaml pleroma_backend pleroma_frontend pleroma_frontend_dist`
3. Transfer and unzip on new server `tar -xzf pleroma_backup.tar.gz`
4. Start and build `docker-compose up -d --build`
### Cloudflared docker-compose.yaml
```
version: "3.8"
services:
db: # (unchanged)
pleroma_backend: # (remove ports if using internal network only)
pleroma_frontend: # (unchanged)
cloudflared:
image: cloudflare/cloudflared:latest
container_name: pleroma_cloudflared
restart: always
command: "tunnel --no-autoupdate run --token YOUR_CLOUDFLARED_TOKEN"
depends_on:
- pleroma_backend
```
### Cloudflared setup
1. Install `sudo apt install cloudflared`
2. Login `cloudflared login`
3. Create tunnel `cloudflared tunnel create pleroma-tunnel`
4. Congfig `~/.cloudflared/config.yml`
5. Add CNAME in Cloudflared `yourdomain.com -> <tunnel-uuid>.cfargotunnel.com`
6. Run `docker-compose up -d --build`
## Host-based Cloudflared
If cloudflared runs on the host system
### docker-compose.yaml
```
version: "3.8"
services:
db: # (unchanged)
pleroma_backend:
# (unchanged, add ports: - "4000:4000")
pleroma_frontend: # (unchanged)
```
### Config
1. Update cloudflared config
```
ingress:
- hostname: yourdomain.com
service: http://localhost:4000
```
2. Start `docker-compose up -d --build`
## Advanced featured
### Custom network (e.g. 172.24.0.0/16)
```
version: "3.8"
services:
db:
# (unchanged)
networks:
pleroma_net:
ipv4_address: 172.24.0.2
pleroma_backend:
# (unchanged)
networks:
pleroma_net:
ipv4_address: 172.24.0.3
pleroma_frontend:
# (unchanged)
networks:
pleroma_net:
ipv4_address: 172.24.0.4
networks:
pleroma_net:
driver: bridge
ipam:
config:
- subnet: 172.24.0.0/16
gateway: 172.24.0.1
```
### Updating frontend/backend
1. Stop container `docker-compose stop pleroma_backend` or `docker-compose stop pleroma_frontend`
2. Update
1. `cd pleroma_backend && git pull origin main` (or edit `Dockerfile`)
2. `cd pleroma_frontend && git pull origin main`
3. Rebuild `docker-compose up -d --build pleroma_backend` or `docker-compose up -d --build pleroma_frontend`
### Monitorin Oban queues
* Admin UI: `https://yourdomain.com/pleroma/admin` -> "Oban Jobs"
* DB Query: `docker exec -it pleroma_db psql -U pleroma -d pleroma
SELECT state, queue, worker, args, inserted_at FROM oban_jobs ORDER BY inserted_at DESC LIMIT 100;`
### Set RAM limit to containers
```
services:
db:
# (unchanged)
mem_limit: 512m
pleroma_backend:
# (unchanged)
mem_limit: 1g
pleroma_frontend:
# (unchanged)
mem_limit: 256m
```
## Final docker-compose.yaml
```
version: "3.8"
services:
db:
image: postgres:15-alpine
container_name: pleroma_db
restart: always
environment:
POSTGRES_USER: pleroma
POSTGRES_PASSWORD: your_secure_password_here
POSTGRES_DB: pleroma
volumes:
- ./postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "pleroma"]
interval: 10s
timeout: 5s
retries: 5
mem_limit: 512m
networks:
pleroma_net:
ipv4_address: 172.24.0.2
pleroma_backend:
build:
context: ./pleroma_backend
dockerfile: Dockerfile
container_name: pleroma_backend
restart: always
ports:
- "4000:4000"
environment:
DOMAIN: yourdomain.com
INSTANCE_NAME: YourPleromaInstance
ADMIN_EMAIL: admin@yourdomain.com
NOTIFY_EMAIL: notify@yourdomain.com
DB_USER: pleroma
DB_PASS: your_secure_password_here
DB_NAME: pleroma
volumes:
- ./uploads:/var/lib/pleroma/uploads
- ./static:/var/lib/pleroma/static
- ./config:/etc/pleroma
depends_on:
db:
condition: service_healthy
command: ["/bin/sh", "-c", "mix ecto.migrate && ./bin/pleroma start"]
mem_limit: 1g
networks:
pleroma_net:
ipv4_address: 172.24.0.3
pleroma_frontend:
build:
context: ./pleroma_frontend
dockerfile: Dockerfile
container_name: pleroma_frontend
restart: always
volumes:
- ./pleroma_frontend_dist:/app/dist
mem_limit: 256m
networks:
pleroma_net:
ipv4_address: 172.24.0.4
networks:
pleroma_net:
driver: bridge
ipam:
config:
- subnet: 172.24.0.0/16
gateway: 172.24.0.1
```
## Bonus: using a .env file
### .env file
```
# .env
# Domain settings
DOMAIN=yourdomain.com
INSTANCE_NAME=YourPleromaInstance
# Database credentials
DB_USER=pleroma
DB_PASS=your_secure_db_password
DB_NAME=pleroma
# Admin credentials
ADMIN_EMAIL=admin@yourdomain.com
NOTIFY_EMAIL=notify@yourdomain.com
# Cloudflared credentials (if using Cloudflared container)
CLOUDFLARED_TOKEN=your_cloudflared_token
```
### Updated docker-compose.yaml
```
version: "3.8"
services:
db:
image: postgres:15-alpine
container_name: pleroma_db
restart: always
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASS}
POSTGRES_DB: ${DB_NAME}
volumes:
- ./postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "${DB_USER}"]
interval: 10s
timeout: 5s
retries: 5
mem_limit: 512m
networks:
pleroma_net:
ipv4_address: 172.24.0.2
pleroma_backend:
build:
context: ./pleroma_backend
dockerfile: Dockerfile
container_name: pleroma_backend
restart: always
ports:
- "4000:4000"
environment:
DOMAIN: ${DOMAIN}
INSTANCE_NAME: ${INSTANCE_NAME}
ADMIN_EMAIL: ${ADMIN_EMAIL}
NOTIFY_EMAIL: ${NOTIFY_EMAIL}
DB_USER: ${DB_USER}
DB_PASS: ${DB_PASS}
DB_NAME: ${DB_NAME}
volumes:
- ./uploads:/var/lib/pleroma/uploads
- ./static:/var/lib/pleroma/static
- ./config:/etc/pleroma
depends_on:
db:
condition: service_healthy
command: ["/bin/sh", "-c", "mix ecto.migrate && ./bin/pleroma start"]
mem_limit: 1g
networks:
pleroma_net:
ipv4_address: 172.24.0.3
pleroma_frontend:
build:
context: ./pleroma_frontend
dockerfile: Dockerfile
container_name: pleroma_frontend
restart: always
volumes:
- ./pleroma_frontend_dist:/app/dist
mem_limit: 256m
networks:
pleroma_net:
ipv4_address: 172.24.0.4
networks:
pleroma_net:
driver: bridge
ipam:
config:
- subnet: 172.24.0.0/16
gateway: 172.24.0.1
```
Changes:
* Environment Variables: Replaced hardcoded values in the environment sections with `${VARIABLE_NAME}` (e.g., `${DOMAIN}`, `${DB_USER}`).
* Healthcheck: Updated `pg_isready` to use `${DB_USER}` dynamically.
* Cloudflared: If you were using the `cloudflared` service (not included here since if running it on the host), youd add:
```
cloudflared:
image: cloudflare/cloudflared:latest
container_name: pleroma_cloudflared
restart: always
command: "tunnel --no-autoupdate run --token ${CLOUDFLARED_TOKEN}"
depends_on:
- pleroma_backend
```
* For host-based Cloudflared, no changes are needed here since its managed outside Docker.
### Update `config.exs` for pleroma
The Pleroma configuration file (`config/config.exs`) needs to read environment variables at runtime. Elixirs `System.get_env/1` function can fetch these variables, so well modify `config.exs` to use them.
```
use Mix.Config
# Domain and endpoint settings
config :pleroma, Pleroma.Web.Endpoint,
url: [host: System.get_env("DOMAIN"), scheme: "https", port: 443],
http: [port: 4000]
# Instance settings
config :pleroma, :instance,
name: System.get_env("INSTANCE_NAME"),
email: System.get_env("ADMIN_EMAIL"),
notify_email: System.get_env("NOTIFY_EMAIL"),
limit: 5000,
registrations_open: false
# Database settings
config :pleroma, Pleroma.Repo,
adapter: Ecto.Adapters.Postgres,
username: System.get_env("DB_USER"),
password: System.get_env("DB_PASS"),
database: System.get_env("DB_NAME"),
hostname: "db"
```
Changes Explained
* Replaced static values with `System.get_env/1` calls (e.g., `System.get_env("DOMAIN")`).
* The variables (`DOMAIN`, `DB_USER`, etc.) match those in `.env` and are passed into the `pleroma_backend` container via the `environment` section in `docker-compose.yaml`.
## Host-based cloudflared config
If youre running cloudflared on the host, its configuration (`~/.cloudflared/config.yml`) isnt directly managed by Docker Compose. However, you can still reference the domain from the `.env` file manually when setting it up.
Updated ~/.cloudflared/config.yml

View file

@ -0,0 +1,6 @@
tunnel: abcd1234-...
credentials-file: /root/.cloudflared/abcd1234-....json
ingress:
- hostname: yourdomain.com
service: http://pleroma_backend:4000
- service: http_status:404

16
config/ex.config.exs Normal file
View file

@ -0,0 +1,16 @@
use Mix.Config
config :pleroma, Pleroma.Web.Endpoint,
url: [host: "yourdomain.com", scheme: "https", port: 443],
http: [port: 4000]
config :pleroma, :instance,
name: "YourPleromaInstance",
email: "admin@yourdomain.com",
notify_email: "notify@yourdomain.com",
limit: 5000,
registrations_open: false
config :pleroma, Pleroma.Repo,
adapter: Ecto.Adapters.Postgres,
username: "pleroma",
password: "your_secure_password_here",
database: "pleroma",
hostname: "db"

52
docker-compose.yaml Normal file
View file

@ -0,0 +1,52 @@
version: "3.8"
services:
db:
image: postgres:15-alpine
container_name: pleroma_db
restart: always
environment:
POSTGRES_USER: pleroma
POSTGRES_PASSWORD: your_secure_password_here
POSTGRES_DB: pleroma
volumes:
- ./postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "pleroma"]
interval: 10s
timeout: 5s
retries: 5
pleroma_backend:
build:
context: ./pleroma_backend
dockerfile: Dockerfile
container_name: pleroma_backend
restart: always
ports:
- "4000:4000"
environment:
DOMAIN: yourdomain.com
INSTANCE_NAME: YourPleromaInstance
ADMIN_EMAIL: admin@yourdomain.com
NOTIFY_EMAIL: notify@yourdomain.com
DB_USER: pleroma
DB_PASS: your_secure_password_here
DB_NAME: pleroma
volumes:
- ./uploads:/var/lib/pleroma/uploads
- ./static:/var/lib/pleroma/static
- ./config:/etc/pleroma
depends_on:
db:
condition: service_healthy
command: ["/bin/sh", "-c", "mix ecto.migrate && ./bin/pleroma start"]
pleroma_frontend:
build:
context: ./pleroma_frontend
dockerfile: Dockerfile
container_name: pleroma_frontend
restart: always
volumes:
- ./pleroma_frontend/dist:/app/dist

View file

@ -0,0 +1,15 @@
FROM elixir:1.14-alpine AS builder
RUN apk add --no-cache git build-base cmake postgresql-dev
WORKDIR /pleroma
RUN git clone https://git.pleroma.social/pleroma/pleroma.git .
RUN mix local.hex --force && mix local.rebar --force
RUN mix deps.get
RUN mix compile
RUN mkdir -p /etc/pleroma
FROM elixir:1.14-alpine
RUN apk add --no-cache postgresql-client
WORKDIR /pleroma
COPY --from=builder /pleroma /pleroma
ENV MIX_ENV=prod
EXPOSE 4000
CMD ["/bin/sh"]

View file

@ -0,0 +1,9 @@
FROM node:18-alpine AS builder
WORKDIR /app
RUN apk add --no-cache git && \
git clone https://git.pleroma.social/pleroma/pleroma-fe.git .
RUN npm install
RUN npm run build
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/dist /app/dist