Skip to content

Commit 72d596c

Browse files
committed
chore(release): bump PG 18.6-trixie + pg_cron 1.6.7; rename prod compose; inline env
- Dockerfile.postgres: PG 18.6-trixie + pg_cron 1.6.7; POSTGRES_DB=openblog and cron.database_name=openblog baked into image (no compose required) - docker-compose.yaml -> docker-compose.prod.yaml; all env vars inlined with REPLACE_ME placeholders for POSTGRES_PASSWORD and AUTH_SECRET - .env.example marked local-dev-only - install.sh, README, CONTRIBUTING, REQUIREMENTS, ROADMAP updated
1 parent 049179e commit 72d596c

12 files changed

Lines changed: 192 additions & 123 deletions

.env.example

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
# OpenBlog environment configuration
1+
# OpenBlog — local development environment configuration
22
#
3-
# Compose reads this file (or `.env`) from the project root automatically.
4-
# The required vars are `AUTH_SECRET`, `POSTGRES_PASSWORD`, and `BASE_URL`. The optional vars
5-
# below cover port mapping, image pinning, and feature toggles.
3+
# ⚠️ PRODUCTION DEPLOYMENT DOES NOT USE THIS FILE. The prod compose
4+
# (`docker-compose.prod.yaml`) has all env vars inlined — secrets and
5+
# all. This file exists only for `pnpm dev`, vitest, prisma CLI,
6+
# and any scripts that read `process.env` directly via dotenv.
67
#
7-
# All other config (NODE_ENV, DATABASE_URL, etc.) is baked into the
8-
# compose files. You only need this file.
8+
# Required vars for local dev: `DATABASE_URL`, `AUTH_SECRET`.
9+
# `BASE_URL` and `PORT` are referenced by the dev server.
10+
#
11+
# Copy this file to `.env` and fill in the values to start.
912

1013
# ─── Required ─────────────────────────────────────────────────────────────────
1114
# BetterAuth signing secret. Generate with `openssl rand -base64 32`.

.github/workflows/publish.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,12 @@ jobs:
331331
file: ./Dockerfile.postgres
332332
platforms: linux/amd64,linux/arm64
333333
push: ${{ github.event_name != 'pull_request' }}
334-
tags: ghcr.io/${{ steps.tags.outputs.repo_lc }}:postgres-16.14-pg-cron-1.6.7
334+
# `:postgres` is a moving alias that always points at the most
335+
# recent release's image — matches the default in docker-compose.prod.yaml.
336+
# `postgres-18.6-pg-cron-1.6.7` is the immutable tag for this build.
337+
tags: |
338+
ghcr.io/${{ steps.tags.outputs.repo_lc }}:postgres
339+
ghcr.io/${{ steps.tags.outputs.repo_lc }}:postgres-18.6-pg-cron-1.6.7
335340
provenance: mode=max
336341
sbom: true
337342
cache-from: type=gha,scope=postgres

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Two compose files ship with the repo:
3030

3131
| File | Purpose |
3232
| --------------------------- | ------------------------------------------------------------------------------------------ |
33-
| `docker-compose.yaml` | **Production.** Pulls `ghcr.io/iamcoder18/openblog:latest`. No build step. |
33+
| `docker-compose.prod.yaml` | **Production.** Pulls `ghcr.io/iamcoder18/openblog:latest`. Shipped via wget; NOT in this repo. |
3434
| `docker-compose.local.yaml` | **Dev.** Builds the image from the local `Dockerfile`. Use when iterating on the codebase. |
3535

3636
For day-to-day local iteration:

Dockerfile.postgres

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# syntax=docker/dockerfile:1.7
22

3-
ARG POSTGRES_VERSION=16.14-bookworm
3+
ARG POSTGRES_VERSION=18.6-trixie
44
ARG PG_CRON_VERSION=1.6.7
55

66
FROM postgres:${POSTGRES_VERSION} AS pg-cron-builder
@@ -9,7 +9,7 @@ ARG PG_CRON_VERSION
99
ARG PG_CRON_SHA256=d950bc29155f31017567e23a31d268ff672e98276c0e9d062512fb7870351f03
1010

1111
RUN apt-get update \
12-
&& apt-get install --yes --no-install-recommends ca-certificates curl gcc libc6-dev make postgresql-server-dev-16 \
12+
&& apt-get install --yes --no-install-recommends ca-certificates curl gcc libc6-dev make postgresql-server-dev-18 \
1313
&& curl --fail --location --silent --show-error \
1414
"https://github.com/citusdata/pg_cron/archive/refs/tags/v${PG_CRON_VERSION}.tar.gz" \
1515
--output /tmp/pg_cron.tar.gz \
@@ -23,13 +23,24 @@ FROM postgres:${POSTGRES_VERSION}
2323

2424
ARG PG_CRON_VERSION
2525

26+
# Bake the database name into the image. The Postgres entrypoint script
27+
# reads $POSTGRES_DB and creates that database on first boot, so bare
28+
# `docker run` users get an `openblog` DB automatically. This is paired
29+
# with `cron.database_name=openblog` in the CMD below — both are required
30+
# for pg_cron to allow `CREATE EXTENSION pg_cron` from the right DB.
31+
ENV POSTGRES_DB=openblog
32+
2633
LABEL org.opencontainers.image.title="OpenBlog PostgreSQL" \
2734
org.opencontainers.image.description="PostgreSQL with pg_cron for OpenBlog scheduled publishing" \
2835
org.opencontainers.image.source="https://github.com/IamCoder18/OpenBlog" \
2936
org.opencontainers.image.licenses="MIT" \
3037
org.opencontainers.image.version="${PG_CRON_VERSION}"
3138

32-
COPY --from=pg-cron-builder /opt/pg_cron/usr/lib/postgresql/16/lib/pg_cron.so /usr/lib/postgresql/16/lib/pg_cron.so
33-
COPY --from=pg-cron-builder /opt/pg_cron/usr/share/postgresql/16/extension/ /usr/share/postgresql/16/extension/
39+
COPY --from=pg-cron-builder /opt/pg_cron/usr/lib/postgresql/18/lib/pg_cron.so /usr/lib/postgresql/18/lib/pg_cron.so
40+
COPY --from=pg-cron-builder /opt/pg_cron/usr/share/postgresql/18/extension/ /usr/share/postgresql/18/extension/
3441

35-
CMD ["postgres", "-c", "shared_preload_libraries=pg_cron", "-c", "cron.use_background_workers=on"]
42+
# `cron.database_name` is locked to `openblog`. To use a different name,
43+
# fork the image and rebuild — `CREATE EXTENSION pg_cron` will otherwise
44+
# refuse to run from any other database. Compose files must NOT override
45+
# this with a different value.
46+
CMD ["postgres", "-c", "shared_preload_libraries=pg_cron", "-c", "cron.database_name=openblog", "-c", "cron.use_background_workers=on"]

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ curl -fsSL https://raw.githubusercontent.com/IamCoder18/OpenBlog/main/scripts/in
4545

4646
The installer:
4747

48-
1. Downloads `docker-compose.yaml` into the current directory.
48+
1. Downloads `docker-compose.prod.yaml` into the current directory.
4949
2. Prompts for `BASE_URL`, `BLOG_NAME`, and admin credentials.
5050
3. Pulls the published image from `ghcr.io/iamcoder18/openblog:latest`.
5151
4. Brings up Postgres + the app, waits for healthy, runs migrations.
@@ -295,7 +295,7 @@ The compose file passes both forms automatically, so **you only ever set `BASE_U
295295
| `NEXT_PUBLIC_BLOG_NAME` | `OpenBlog` | Same, inlined for the client. |
296296
| `SIGN_UP_ENABLED` | `false` | When `true`, `/auth/signup` is open to the public. Off by default — create users via the admin script. |
297297
| `DISABLE_RATE_LIMITING` | `false` | Disables BetterAuth rate limiting. Used by E2E tests; do not enable in production. |
298-
| `DATABASE_URL` | compose default | Postgres connection string. Hardcoded in `docker-compose.yaml`; override per environment. |
298+
| `DATABASE_URL` | compose default | Postgres connection string. Hardcoded in `docker-compose.prod.yaml`; per-deployment values are baked in by the installer. |
299299
| `PORT` | `3000` | Port the Next.js standalone server listens on inside the container. |
300300
| `NODE_ENV` | `production` | Set to `development` only when running `pnpm dev` outside Docker. |
301301

@@ -666,7 +666,7 @@ openblog/
666666
│ └── api.md # Full HTTP API reference
667667
├── sessions/ # Agent session notes (audit trail)
668668
├── Dockerfile # Three-stage build (fetcher → builder → runner). Builds with zero required args.
669-
├── docker-compose.yaml # Production compose: pulls published image from ghcr.io.
669+
├── docker-compose.prod.yaml # Production compose: pulls published image from ghcr.io. Ships via wget, not the repo.
670670
├── docker-compose.local.yaml# Dev compose: builds from local Dockerfile.
671671
└── docker-compose.test.yaml # Test-only Postgres
672672
```

REQUIREMENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ The database must support the following core relations:
6565

6666
- The platform must be fully self-hostable, providing users with total ownership over their data and infrastructure.
6767
- The platform should be built with the latest version of Next.js.
68-
- **Docker Compose:** This is the primary and recommended deployment method. The repository must include a production-ready `docker-compose.yaml` that orchestrates the app and the Postgres database.
68+
- **Docker Compose:** This is the primary and recommended deployment method. The project must ship a production-ready `docker-compose.prod.yaml` (deployed via wget, outside the repo) that orchestrates the app and the Postgres database.
6969

7070
### 5.2 Dynamic Configuration
7171

ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ This roadmap defines the logical progression from infrastructure to deployment f
9090
**Duration:** Production Readiness
9191
**Focus:** Containerization, CI/CD, and self-hosting support
9292

93-
- Create production-ready docker-compose.yaml
93+
- Create production-ready docker-compose.prod.yaml (shipped via wget, not the repo)
9494
- Configure multi-stage Docker builds
9595
- Set up environment variable documentation
9696
- Implement health checks and logging

docker-compose.local.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
# ─────────────────────────────────────────────────────────────────────────────
22
# OpenBlog — local source build compose (developer workflow)
33
# ─────────────────────────────────────────────────────────────────────────────
4-
# Identical to docker-compose.yaml but builds the image from the local
4+
# Identical to docker-compose.prod.yaml but builds the image from the local
55
# Dockerfile instead of pulling from a registry.
66
#
77
# Use this when you're hacking on the codebase:
88
# docker compose -f docker-compose.local.yaml up -d --build
99
#
1010
# To customize baked-in defaults (NEXT_PUBLIC_BLOG_NAME, etc.), edit the
1111
# `ENV` block in Dockerfile before building.
12+
#
13+
# ⚠️ DATABASE NAME IS LOCKED TO `openblog` — DO NOT CHANGE ⚠️
14+
#
15+
# The Postgres service, the OpenBlog app, and the pg_cron extension all
16+
# hard-code the database name `openblog`. See docker-compose.prod.yaml for the
17+
# long-form explanation. In short: don't change POSTGRES_DB, the
18+
# cron.database_name flag, or the /openblog path in DATABASE_URL — pg_cron
19+
# and Prisma migrations won't follow.
1220
# ─────────────────────────────────────────────────────────────────────────────
1321

1422
services:

docker-compose.prod.yaml

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# ─────────────────────────────────────────────────────────────────────────────
2+
# OpenBlog — production compose
3+
# ─────────────────────────────────────────────────────────────────────────────
4+
# Pulls published images from ghcr.io and runs the full stack. This file
5+
# is the artifact end users deploy — it is NOT pulled from this git repo;
6+
# users download it via wget (or have it generated locally by the installer).
7+
#
8+
# Direct deployment:
9+
# 1. wget https://raw.githubusercontent.com/IamCoder18/OpenBlog/main/docker-compose.prod.yaml
10+
# 2. Replace each `REPLACE_ME_…` placeholder below with a freshly generated
11+
# secret:
12+
# POSTGRES_PASSWORD → openssl rand -hex 32
13+
# AUTH_SECRET → openssl rand -base64 32
14+
# Or just run `./scripts/install.sh` to do the substitution automatically.
15+
# 3. Edit `BASE_URL` to your real deployment URL.
16+
# 4. docker compose up -d
17+
#
18+
# Image source:
19+
# postgres → ghcr.io/iamcoder18/openblog:postgres
20+
# app → ghcr.io/iamcoder18/openblog:latest
21+
# Pin to a version (e.g. :v0.1.0) for production by editing the `image:` lines.
22+
#
23+
# To build from source instead of pulling, use docker-compose.local.yaml.
24+
# ─────────────────────────────────────────────────────────────────────────────
25+
#
26+
# ⚠️ DATABASE NAME IS LOCKED TO `openblog` — DO NOT CHANGE ⚠️
27+
#
28+
# The Postgres service, the OpenBlog application, and the pg_cron extension
29+
# all hard-code the database name `openblog`. Changing any of the lines
30+
# below that reference it (POSTGRES_DB, cron.database_name, the /openblog
31+
# path in DATABASE_URL) will cause one or more of the following failures:
32+
#
33+
# • `CREATE EXTENSION pg_cron` refuses with
34+
# "can only create extension in database postgres"
35+
# when connected to a differently-named database.
36+
# • Scheduled-publish migrations (`cron.schedule` calls) target the
37+
# wrong catalog and silently no-op.
38+
# • First-time Prisma migrations target a DB that doesn't exist.
39+
#
40+
# If you genuinely need a different database name, fork the repo, edit
41+
# Dockerfile.postgres (POSTGRES_DB + cron.database_name CMD flag), edit
42+
# the same three lines in BOTH compose files, and rebuild — there is no
43+
# runtime override. This is intentional: it removes a class of subtle
44+
# bugs at the cost of flexibility.
45+
# ─────────────────────────────────────────────────────────────────────────────
46+
47+
services:
48+
postgres:
49+
image: ghcr.io/iamcoder18/openblog:postgres
50+
container_name: openblog-db
51+
restart: unless-stopped
52+
environment:
53+
POSTGRES_USER: postgres
54+
POSTGRES_PASSWORD: "REPLACE_ME_run_openssl_rand_hex_32"
55+
POSTGRES_DB: openblog
56+
command:
57+
- postgres
58+
- -c
59+
- shared_preload_libraries=pg_cron
60+
- -c
61+
- cron.database_name=openblog
62+
- -c
63+
- cron.use_background_workers=on
64+
volumes:
65+
- postgres_data:/var/lib/postgresql/data
66+
ports:
67+
- "127.0.0.1:5432:5432"
68+
healthcheck:
69+
test: ["CMD-SHELL", "pg_isready -U postgres"]
70+
interval: 10s
71+
timeout: 5s
72+
retries: 5
73+
74+
app:
75+
image: ghcr.io/iamcoder18/openblog:latest
76+
container_name: openblog-app
77+
restart: unless-stopped
78+
init: true
79+
depends_on:
80+
postgres:
81+
condition: service_healthy
82+
ports:
83+
- "3000:3000"
84+
environment:
85+
DATABASE_URL: "postgresql://postgres:REPLACE_ME_run_openssl_rand_hex_32@postgres:5432/openblog?schema=public"
86+
BASE_URL: "http://localhost:3000"
87+
BLOG_NAME: "OpenBlog"
88+
BLOG_DESCRIPTION: ""
89+
SITE_LOGO_URL: ""
90+
SITE_CONTACT_EMAIL: ""
91+
SITE_SOCIAL_URL: ""
92+
NODE_ENV: production
93+
PORT: 3000
94+
AUTH_SECRET: "REPLACE_ME_run_openssl_rand_base64_32"
95+
SIGN_UP_ENABLED: "false"
96+
SMTP_HOST: ""
97+
SMTP_PORT: ""
98+
SMTP_SECURE: ""
99+
SMTP_USER: ""
100+
SMTP_PASSWORD: ""
101+
SMTP_FROM: ""
102+
healthcheck:
103+
test:
104+
[
105+
"CMD-SHELL",
106+
"wget -qO- http://127.0.0.1:3000/api/health >/dev/null || exit 1",
107+
]
108+
interval: 30s
109+
timeout: 5s
110+
retries: 3
111+
start_period: 20s
112+
113+
volumes:
114+
postgres_data:

docker-compose.test.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# ─────────────────────────────────────────────────────────────────────────────
2+
# OpenBlog — test database (used by `pnpm run test:*`)
3+
# ─────────────────────────────────────────────────────────────────────────────
4+
# Brings up a throwaway Postgres instance for the test suite.
5+
#
6+
# ⚠️ EXCEPTION TO THE `openblog` LOCKDOWN: this compose uses
7+
# `openblog_test` for the database name. This is INTENDED — the
8+
# vitest integration tests, playwright e2e tests, and `scripts/test-*`
9+
# shells all hard-code `openblog_test` so a developer can run them
10+
# in parallel with a running dev database on `openblog` without
11+
# colliding. Do not "normalize" this file's name to `openblog`.
12+
# ─────────────────────────────────────────────────────────────────────────────
13+
114
services:
215
postgres-test:
316
build:

0 commit comments

Comments
 (0)