Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ services:
retries: 20

minio:
image: quay.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
image: docker.io/pgsty/minio@sha256:b6bfe7239bfc83fb90d31612d9704d86039dd714f7904b3f1ad68f211e602372
restart: unless-stopped
command: server /data --console-address :9001
environment:
Expand Down
2 changes: 1 addition & 1 deletion deploy/dokploy/blueprints/blogfactory/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ services:
retries: 20

minio:
image: quay.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
image: docker.io/pgsty/minio@sha256:b6bfe7239bfc83fb90d31612d9704d86039dd714f7904b3f1ad68f211e602372
restart: unless-stopped
command: server /data --console-address :9001
environment:
Expand Down
4 changes: 2 additions & 2 deletions deploy/railway/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The public template maps the canonical Compose stack to five Railway services so
| `web` | `ghcr.io/blogfactoryhq/blogfactory-web:v0.1.0` | yes | `PORT=80`; `API_UPSTREAM=http://${{api.RAILWAY_PRIVATE_DOMAIN}}:3000` |
| `api` | `ghcr.io/blogfactoryhq/blogfactory-api:v0.1.0` | no | pre-deploy `bun run src/init-s3-bucket.ts`; variables below; health path `/api/ready` |
| `Postgres` | Railway managed PostgreSQL | no | managed service defaults |
| `minio` | `quay.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e` | no | command `/usr/bin/minio server /data --address :9000 --console-address :9001`; volume mounted at `/data` |
| `minio` | `docker.io/pgsty/minio@sha256:b6bfe7239bfc83fb90d31612d9704d86039dd714f7904b3f1ad68f211e602372` | no | command `/usr/bin/minio server /data --address :9000 --console-address :9001`; volume mounted at `/data` |
| `cron` | `ghcr.io/blogfactoryhq/blogfactory-api:v0.1.0` | no | command `bun run src/run-cron-once.ts`; cron `0 */6 * * *`; restart `NEVER` |

The template asks only for `ADMIN_EMAILS`. It generates independent values for `JWT_SECRET`, `API_KEY_ENCRYPTION_SECRET`, `CRON_SECRET`, and `MINIO_ROOT_PASSWORD` with Railway template variable functions. Do not publish a template with literal defaults.
Expand All @@ -34,7 +34,7 @@ S3_BUCKET=blogfactory
S3_REGION=us-east-1
```

MinIO uses `MINIO_ROOT_USER=blogfactory`, a generated `MINIO_ROOT_PASSWORD`, and port `9000`. Mount a 500 MB persistent volume at `/data` on Railway Hobby. Before each API deployment, Railway runs the following idempotent pre-deploy command with the API's `S3_*` variables:
The `minio` image is the AGPL-3.0 community fork `pgsty/minio` (`RELEASE.2026-08-04T00-00-00Z`), because upstream MinIO images are no longer pullable. MinIO uses `MINIO_ROOT_USER=blogfactory`, a generated `MINIO_ROOT_PASSWORD`, and port `9000`. Mount a 500 MB persistent volume at `/data` on Railway Hobby. Before each API deployment, Railway runs the following idempotent pre-deploy command with the API's `S3_*` variables:

```sh
bun run src/init-s3-bucket.ts
Expand Down
4 changes: 4 additions & 0 deletions docs/self-hosting.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ docker compose up -d

If the older application is incompatible with the migrated schema, restore the pre-upgrade PostgreSQL dump and matching MinIO copy instead of trying to reverse migrations.

### MinIO image source

Upstream MinIO no longer publishes pullable images: `quay.io/minio/minio` and Docker Hub `minio/minio` return `unauthorized`, and the `minio/minio` repository is archived. Compose, Dokploy, and Railway pin the AGPL-3.0 community fork [`pgsty/minio`](https://github.com/pgsty/minio) by digest. It is the same server and bundled `mc` client with the same environment variables, health endpoint, and on-disk format, so an existing `minio-data` volume starts unchanged. After a verified backup, pick up the new pin with `docker compose pull minio && docker compose up -d`.

## Dokploy runbook

The upstream-compatible blueprint is in [`deploy/dokploy/blueprints/blogfactory`](../deploy/dokploy/blueprints/blogfactory). It creates web, API, scheduler, PostgreSQL, and MinIO services with persistent database and object-storage volumes. Only web receives a Dokploy domain. The API initializes the S3 bucket and runs locked additive migrations before serving.
Expand Down
4 changes: 2 additions & 2 deletions scripts/self-host-backup-restore-smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ storage_path="$(jq -er '.storagePath // .storage_path' "$tmp_dir/upload.json")"
"${source_compose[@]}" stop api scheduler
"${source_compose[@]}" exec -T postgres pg_dump -U blogfactory -d blogfactory -Fc > "$tmp_dir/blogfactory.dump"
mkdir "$tmp_dir/objects"
docker run --rm --user "$(id -u):$(id -g)" --network "${source_project}_default" -e MC_CONFIG_DIR=/tmp/.mc -v "$tmp_dir/objects:/backup" --entrypoint /bin/sh quay.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e -c \
docker run --rm --user "$(id -u):$(id -g)" --network "${source_project}_default" -e MC_CONFIG_DIR=/tmp/.mc -v "$tmp_dir/objects:/backup" --entrypoint /bin/sh docker.io/pgsty/minio@sha256:b6bfe7239bfc83fb90d31612d9704d86039dd714f7904b3f1ad68f211e602372 -c \
'mc alias set local http://minio:9000 blogfactory minio-backup-0123456789abcdef0123456789abcdef && mc mirror local/blogfactory /backup'
"${source_compose[@]}" down --volumes --remove-orphans

"${target_compose[@]}" up -d
for _ in {1..90}; do curl --fail --silent "$base_url/api/ready" >/dev/null && break; sleep 2; done
"${target_compose[@]}" stop api scheduler
"${target_compose[@]}" exec -T postgres pg_restore -U blogfactory -d blogfactory --clean --if-exists < "$tmp_dir/blogfactory.dump"
docker run --rm --network "${target_project}_default" -v "$tmp_dir/objects:/backup:ro" --entrypoint /bin/sh quay.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e -c \
docker run --rm --network "${target_project}_default" -v "$tmp_dir/objects:/backup:ro" --entrypoint /bin/sh docker.io/pgsty/minio@sha256:b6bfe7239bfc83fb90d31612d9704d86039dd714f7904b3f1ad68f211e602372 -c \
'mc alias set local http://minio:9000 blogfactory minio-backup-0123456789abcdef0123456789abcdef && mc mirror /backup local/blogfactory'
"${target_compose[@]}" start api scheduler
for _ in {1..60}; do curl --fail --silent "$base_url/api/ready" >/dev/null && break; sleep 2; done
Expand Down
Loading