diff --git a/.circleci/config.yml b/.circleci/config.yml index fc63a4f76..ba4d84be3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,7 +14,7 @@ executors: PGHOST: 127.0.0.1 PGUSER: postgres RAILS_ENV: test - - image: cimg/postgres:10.18 + - image: cimg/postgres:18.6 environment: POSTGRES_USER: postgres POSTGRES_DB: app_test diff --git a/.tool-versions b/.tool-versions index 9ffab1b44..1522e74a2 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ ruby 4.0.7 nodejs 26.8.2 -postgres 16.8 +postgres 18.6 pnpm 12.5.1 diff --git a/AGENTS.md b/AGENTS.md index 4adde9f37..0798b0a3d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ Stringer is a self-hosted, anti-social RSS reader: a Rails 8.1 app (Ruby 4.0) ba ## Commands -Toolchain versions are pinned in `.tool-versions` (Ruby 4.0.5, Node 26.3.0, Postgres 16.8, pnpm 10.5.2). +Toolchain versions (Ruby, Node, Postgres, pnpm) are pinned in `.tool-versions`; check that file rather than relying on numbers quoted here. - **Setup:** `bin/setup` (runs `bundle install`, `db:prepare`, clears logs/tmp, then launches the dev server). Pass `--skip-server` to stop before launching. - **Run dev server:** `bin/dev` (foreman against `Procfile.dev` — boots Puma on port 3000 plus `js`/`css` esbuild watchers). The app is at `http://localhost:3000`. diff --git a/docker-compose.yml b/docker-compose.yml index f93f33a37..f78bdf784 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,7 @@ services: command: ["/app/docker/init_or_update_env.rb"] stringer-postgres: - image: postgres:16-alpine + image: postgres:18-alpine container_name: stringer-postgres restart: always depends_on: @@ -22,7 +22,9 @@ services: - stringer-network volumes: - ./.env:/app/.env - - /srv/stringer/data:/var/lib/postgresql/data + # Postgres 18+ images expect a single mount here and store the database + # in a version-named subdirectory. See docs/Docker.md for upgrade steps. + - /srv/stringer/data:/var/lib/postgresql env_file: .env stringer: diff --git a/docs/Docker.md b/docs/Docker.md index a146bd741..3de89d3a1 100644 --- a/docs/Docker.md +++ b/docs/Docker.md @@ -28,11 +28,11 @@ docker network create --driver bridge stringer-network docker run --detach \ --name stringer-postgres \ --restart always \ - --volume /srv/stringer/data:/var/lib/postgresql/data \ + --volume /srv/stringer/data:/var/lib/postgresql \ --net stringer-network \ -e POSTGRES_PASSWORD=myPassword \ -e POSTGRES_DB=stringer \ - postgres:16-alpine + postgres:18-alpine ``` 3. Run the Stringer Docker image: @@ -56,6 +56,53 @@ docker run --detach \ That's it! You now have a fully working Stringer instance up and running! +## Upgrading Postgres + +The setup above moved from Postgres 16 to Postgres 18. Two things changed: + +- A Postgres major version cannot read data files written by an older one. +- The official 18+ image expects a single mount at `/var/lib/postgresql` (not `/var/lib/postgresql/data`) and stores the database in a version-named subdirectory inside it. + +If you start the 18 image against an existing 16 data directory it refuses to start and prints an explanation, so nothing is lost. But you do need to migrate by hand. Stringer databases are small, so the simplest route is to dump and restore. + +1. With the old container still running, dump everything: + +```sh +docker compose exec stringer-postgres sh -c 'pg_dumpall -U "$POSTGRES_USER"' > stringer-pg16.sql +``` + +2. Stop the stack and move the old data directory aside: + +```sh +docker compose down +sudo mv /srv/stringer/data /srv/stringer/data-pg16 +``` + +3. Update `docker-compose.yml` (or re-download it): change the image to `postgres:18-alpine` and the volume to `/srv/stringer/data:/var/lib/postgresql`. + +4. Start only the database and wait for it to accept connections: + +```sh +docker compose up -d stringer-postgres +until docker compose exec stringer-postgres pg_isready -h localhost; do sleep 1; done +``` + +5. Restore the dump. Errors saying a role or database "already exists" are expected and harmless, because the fresh container already created them: + +```sh +docker compose exec -T stringer-postgres sh -c 'psql -U "$POSTGRES_USER" -d postgres' < stringer-pg16.sql +``` + +6. Start the rest of the stack and check that your feeds and stories are there: + +```sh +docker compose up -d +``` + +7. Once you are happy, delete `/srv/stringer/data-pg16` and `stringer-pg16.sql`. + +If you used the manual setup instead of docker-compose, run the same commands with `docker exec stringer-postgres` in place of `docker compose exec stringer-postgres`, and recreate the Postgres container with the new image and volume path in step 3. + For production use it's recommended to put a reverse proxy in front of Stringer. Caddy (https://caddyserver.com/):