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 .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ruby 4.0.7
nodejs 26.8.2
postgres 16.8
postgres 18.6
pnpm 12.5.1
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
6 changes: 4 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
51 changes: 49 additions & 2 deletions docs/Docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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/):
Expand Down
Loading