{"id":50942332,"url":"https://github.com/rmdes/newsdiff-deploy","last_synced_at":"2026-06-17T16:10:25.917Z","repository":{"id":347308348,"uuid":"1193549030","full_name":"rmdes/newsdiff-deploy","owner":"rmdes","description":"Docker Compose deployment for NewsDiff — self-hosted news article diff tracker","archived":false,"fork":false,"pushed_at":"2026-06-09T17:26:50.000Z","size":13,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-09T19:15:01.274Z","etag":null,"topics":["diffengine","docker","docker-compose","newsdiffs","really-simple-sydication","rss","rss-feed","rss-reader"],"latest_commit_sha":null,"homepage":"https://diff.rmendes.net/about","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rmdes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-27T10:47:05.000Z","updated_at":"2026-06-09T17:31:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rmdes/newsdiff-deploy","commit_stats":null,"previous_names":["rmdes/newsdiff-deploy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rmdes/newsdiff-deploy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdes%2Fnewsdiff-deploy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdes%2Fnewsdiff-deploy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdes%2Fnewsdiff-deploy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdes%2Fnewsdiff-deploy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rmdes","download_url":"https://codeload.github.com/rmdes/newsdiff-deploy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmdes%2Fnewsdiff-deploy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34453638,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-17T02:00:05.408Z","response_time":127,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["diffengine","docker","docker-compose","newsdiffs","really-simple-sydication","rss","rss-feed","rss-reader"],"created_at":"2026-06-17T16:10:25.356Z","updated_at":"2026-06-17T16:10:25.911Z","avatar_url":"https://github.com/rmdes.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# newsdiff-deploy\n\nDocker Compose deployment for [NewsDiff](https://github.com/rmdes/newsdiff) — self-hosted news article diff tracker.\n\n## Architecture\n\n```\n              :8080 (LISTEN_PORT)\n                │\n           ┌────▼────┐\n           │  nginx   │ reverse proxy\n           └────┬─────┘\n       ┌────────┴────────┐\n       │ AP paths        │ everything else\n       ▼                 ▼\n  ┌─────────┐      ┌─────────┐\n  │   bot   │      │   app   │  SvelteKit + workers\n  │  :8001  │      │  :3000  │\n  └────┬────┘      └────┬────┘\n       │                │\n       ▼                ▼\n  ┌─────────┐      ┌──────────┐\n  │  redis  │      │ postgres │\n  └─────────┘      └──────────┘\n```\n\n- **app** — SvelteKit web frontend, feed poller, syndicator workers\n- **bot** — ActivityPub server (Botkit/Fedify), handles incoming federation\n- **nginx** — routes `.well-known/webfinger`, `/ap/`, `/users/`, `/nodeinfo/` to bot; everything else to app\n- **migrate** — one-shot service that runs DB migrations on startup, then exits\n- **postgres** — database\n- **redis** — shared by app (BullMQ) and bot (Fedify KV + message queue)\n\nBoth `app` and `bot` use the same Docker image with different entrypoints.\n\n## Quick start\n\n```bash\ngit clone https://github.com/rmdes/newsdiff-deploy.git\ncd newsdiff-deploy\n\n# Configure\ncp .env.example .env\n# Edit .env — at minimum set ORIGIN and POSTGRES_PASSWORD\n\n# Start\ndocker compose up -d\n\n# Check logs\ndocker compose logs -f app bot\n```\n\nThe app listens on `LISTEN_PORT` (default: 8080). Put a TLS-terminating reverse proxy in front (Caddy, Traefik, nginx with certbot, etc.).\n\n## TLS setup\n\nNewsDiff requires HTTPS for ActivityPub federation. The simplest option is [Caddy](https://caddyserver.com/) as a front proxy with automatic HTTPS:\n\n```\n# Caddyfile\ndiff.yourdomain.com {\n    reverse_proxy localhost:8080\n}\n```\n\nOr add a Caddy service to `docker-compose.override.yml`:\n\n```yaml\nservices:\n  caddy:\n    image: caddy:alpine\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    volumes:\n      - ./Caddyfile:/etc/caddy/Caddyfile:ro\n      - caddy-data:/data\n    depends_on:\n      - nginx\n    restart: unless-stopped\n\nvolumes:\n  caddy-data:\n```\n\n## Configuration\n\nAll configuration is via environment variables in `.env`. See `.env.example` for the full list.\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `ORIGIN` | Yes | Public URL (e.g., `https://diff.yourdomain.com`) |\n| `POSTGRES_PASSWORD` | Yes | Database password |\n| `BOT_USERNAME` | No | ActivityPub bot username (default: `bot`) |\n| `BOT_NAME` | No | Bot display name (default: `NewsDiff Bot`) |\n| `BLUESKY_HANDLE` | No | Bluesky handle for syndication |\n| `BLUESKY_PASSWORD` | No | Bluesky app password |\n| `LISTEN_PORT` | No | Port nginx listens on (default: `8080`) |\n| `SYNDICATE_RATE_MS` | No | Min gap between posts in ms (default: `300000` = 5 min) |\n\n## Updating\n\n```bash\ndocker compose pull\ndocker compose up -d\n```\n\nThe `migrate` service runs automatically on every startup, applying any new database migrations.\n\n## Building from source\n\nIf you prefer to build the image locally instead of pulling from the registry:\n\n```bash\ngit clone https://github.com/rmdes/newsdiff.git\ndocker build -t newsdiff:local ./newsdiff\n\n# Then in docker-compose.yml, replace:\n#   image: ghcr.io/rmdes/newsdiff:latest\n# with:\n#   image: newsdiff:local\n```\n\n## Data\n\n| Volume | Contents |\n|--------|----------|\n| `postgres-data` | Database |\n| `redis-data` | Federation state, job queue |\n| `app-data` | Bot profile config, diff card images, uploaded images |\n\n## Backup\n\n```bash\n# Database\ndocker compose exec postgres pg_dump -U newsdiff newsdiff \u003e backup.sql\n\n# Restore\ndocker compose exec -T postgres psql -U newsdiff newsdiff \u003c backup.sql\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmdes%2Fnewsdiff-deploy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frmdes%2Fnewsdiff-deploy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmdes%2Fnewsdiff-deploy/lists"}