Lemmy на Pethost в один клик
Агрегатор ссылок и форум для федиверса
Что произойдет
- Вы входите в Pethost или создаете аккаунт — с passkey, через GitHub или Google.
- Машины еще нет? Вы выбираете тариф, и мы готовим машину для вас. Ссылка ждет в вашем браузере, пока машина не будет готова.
- Окно «Новый проект» открывается на этом приложении. Вы заполняете то, что оно просит, и нажимаете «Создать проект»: Пароль администратора.
- Через минуту-две приложение работает по своему адресу с HTTPS. Его секреты создаются случайно, а данные попадают в ночной бэкап.
- Это проект как любой другой: его compose.yaml, .env, логи и терминал — в панели, а ваш агент может его изменить, откатить или восстановить.
Первые шаги
Войдите как admin с паролем, который вы задали; первый запуск занимает минуту-две. Новые аккаунты ждут вашего одобрения: Registration Mode находится в Admin Settings. Пароль меняется в настройках самого Lemmy: тот, что в .env, читается только один раз. Адрес — это имя инстанса в федиверсе, поэтому не меняйте его.
Что запускается
Шаблон — это этот compose.yaml и переменные, которые он пишет в .env проекта. Pethost запускает файл так, как он написан.
services:
# Lemmy's own front door: a fediverse server asks for a page as ActivityPub
# JSON, and those requests, the API's and every non-GET go to the backend;
# the rest goes to the UI.
proxy:
image: nginx:1-alpine
restart: unless-stopped
configs:
- source: nginx
target: /etc/nginx/nginx.conf
depends_on:
- lemmy
- lemmy-ui
lemmy:
image: dessalines/lemmy:0.19.20
restart: unless-stopped
environment:
RUST_LOG: warn
configs:
- source: lemmy
target: /config/config.hjson
depends_on:
db:
condition: service_healthy
pictrs:
condition: service_started
# The first start runs the migrations and makes the admin before it listens.
healthcheck:
test: ["CMD", "curl", "-fsS", "-o", "/dev/null", "http://127.0.0.1:8536/api/v3/site"]
interval: 10s
timeout: 5s
retries: 5
start_period: 180s
lemmy-ui:
image: dessalines/lemmy-ui:0.19.20
restart: unless-stopped
environment:
LEMMY_UI_LEMMY_INTERNAL_HOST: lemmy:8536
LEMMY_UI_LEMMY_EXTERNAL_HOST: ${HOST}
LEMMY_UI_HTTPS: "true"
depends_on:
lemmy:
condition: service_healthy
# The image's own check runs once a minute; this one answers in ten seconds.
healthcheck:
test: ["CMD-SHELL", "curl -ILfSs http://localhost:1234/ > /dev/null || exit 1"]
interval: 10s
timeout: 10s
retries: 3
start_period: 30s
pictrs:
image: asonix/pictrs:0.5
restart: unless-stopped
environment:
PICTRS__SERVER__API_KEY: ${PICTRS_API_KEY}
# Kept light: no video transcoding, and small animations, as Lemmy's docs set them.
PICTRS__MEDIA__VIDEO__ENABLE: "false"
PICTRS__MEDIA__ANIMATION__MAX_WIDTH: 256
PICTRS__MEDIA__ANIMATION__MAX_HEIGHT: 256
PICTRS__MEDIA__ANIMATION__MAX_AREA: 65536
PICTRS__MEDIA__ANIMATION__MAX_FRAME_COUNT: 400
volumes:
- pictrs:/mnt
db:
image: postgres:18-alpine
restart: unless-stopped
environment:
POSTGRES_DB: lemmy
POSTGRES_USER: lemmy
POSTGRES_PASSWORD: ${DB_PASSWORD}
# Lemmy's docs raise Docker's 64 MB: big queries fail with "could not resize shared memory segment".
shm_size: 1g
volumes:
- db:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U lemmy -d lemmy"]
interval: 5s
timeout: 5s
retries: 12
start_period: 30s
configs:
# Lemmy reads its settings from this file alone. `setup` makes the admin at the
# first start, so no setup page is left open; the password is a multiline
# string, which Hjson takes as written, quotes and backslashes included.
lemmy:
content: |
{
hostname: "${HOST}"
database: {
host: db
password: "${DB_PASSWORD}"
}
pictrs: {
url: "http://pictrs:8080/"
api_key: "${PICTRS_API_KEY}"
# Thumbnails of linked pages stay where they are, not copied into pict-rs.
image_mode: "None"
}
setup: {
admin_username: admin
admin_password:
'''
${ADMIN_PASSWORD}
'''
site_name: Lemmy
}
}
# Lemmy's nginx_internal.conf (lemmy-ansible); $$ is a $ to Compose.
nginx:
content: |
worker_processes auto;
events {
worker_connections 1024;
}
http {
# Docker's DNS, asked at each request, so that a recreated container is found.
resolver 127.0.0.11 valid=5s;
# The visitor's address, from the machine's proxy.
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
map "$$request_method:$$http_accept" $$proxpass {
default "http://lemmy-ui:1234";
"~^(?:GET|HEAD):.*?application\/(?:activity|ld)\+json" "http://lemmy:8536";
"~^(?!(GET|HEAD)).*:" "http://lemmy:8536";
}
server {
set $$lemmy_ui "lemmy-ui:1234";
set $$lemmy "lemmy:8536";
listen 8536;
server_name localhost;
server_tokens off;
# Uploads go to pict-rs through the backend.
client_max_body_size 20M;
proxy_set_header Host $$http_host;
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
location / {
proxy_pass $$proxpass;
rewrite ^(.+)/+$$ $$1 permanent;
}
location = /.well-known/security.txt {
proxy_pass "http://$$lemmy_ui";
}
location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known|version|sitemap.xml) {
proxy_pass "http://$$lemmy";
}
}
}
volumes:
pictrs:
db: