Skip to content

Commit 71a341f

Browse files
Service: Add fusion rss feed reader (#398)
Fusion RSS is another feed reader with support for rss, atom, and JSON feeds. It's an alternative to FreshRSS with slightly less functionality and specifically only supports a single tenant (user) which keeps it quite simple. This adapts my own docker compose file that I use in my setup, for the ScaleTail project.
1 parent b90b7fa commit 71a341f

4 files changed

Lines changed: 148 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ Every stack starts from the same [standard setup](documentation/standard-setup.m
117117
| **BookLore** | Book manager and browser reader, with Kobo and KOReader sync. | [Details](services/booklore) |
118118
| **Configarr** | Tool that applies YAML settings and TRaSH Guides profiles to Radarr and Sonarr, then exits. | [Details](services/configarr) |
119119
| **FreshRSS** | Feed reader for RSS and Atom, with themes, extensions, and no separate database server. | [Details](services/freshrss) |
120+
| **Fusion** | Lightweight feed reader for RSS, Atom, and JSON feeds, with a Fever API for mobile clients. | [Details](services/fusion) |
120121
| **Hytale** | Hytale game server in a community image, for players on your Tailnet. | [Details](services/hytale) |
121122
| **Immich** | Photo and video library that backs up mobile media, with search and sharing. | [Details](services/immich) |
122123
| **Jellyfin** | Media server that organizes and streams your movies, series, and music. | [Details](services/jellyfin) |

‎services/fusion/.env‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#URL=https://github.com/tailscale-dev/ScaleTail
2+
# To run a second copy, copy the folder under another name and change SERVICE.
3+
4+
# Service Configuration
5+
# Service name (e.g., adguard). Used as hostname in Tailscale and for container naming.
6+
SERVICE=fusion
7+
# Docker image URL from container registry (e.g., adguard/adguardhome:latest).
8+
IMAGE_URL=ghcr.io/0x2e/fusion:latest
9+
10+
# Network Configuration
11+
# Port to expose to local network. Uncomment the "ports:" section in compose.yaml to enable.
12+
SERVICEPORT=8080
13+
# Preferred DNS server for Tailscale. Uncomment the "dns:" section in compose.yaml to enable.
14+
DNS_SERVER=9.9.9.9
15+
16+
# Tailscale Configuration
17+
# Auth key from https://console.tailscale.com/admin/settings/keys. See: https://tailscale.com/kb/1085/auth-keys#generate-an-auth-key for instructions.
18+
TS_AUTHKEY=
19+
20+
# Time Zone setting for containers. See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
21+
TZ=Europe/Amsterdam
22+
23+
# Any Container environment variables are declared below. See https://docs.docker.com/compose/how-tos/environment-variables/
24+
25+
# Required: your Tailnet name, the part between the service name and ".ts.net" in https://fusion.<tailnet name>.ts.net, for example tail1234.
26+
TAILNET_NAME=
27+
# Required: password of the web interface. Generate it with: openssl rand -hex 32
28+
FUSION_PASSWORD=
29+
30+
# Optional single sign-on. Set these three values and uncomment the FUSION_OIDC lines in compose.yaml.
31+
#FUSION_OIDC_ISSUER=
32+
#FUSION_OIDC_CLIENT_ID=
33+
#FUSION_OIDC_CLIENT_SECRET=

‎services/fusion/README.md‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Fusion
2+
3+
[Fusion](https://github.com/0x2E/fusion) is a lightweight feed reader for RSS, Atom, and JSON feeds. It keeps your feeds, articles, and read state in a single SQLite file, and serves third-party clients such as Reeder and Unread through its Fever API.
4+
5+
This stack runs Fusion with a Tailscale sidecar, as described in [the standard setup](../../documentation/standard-setup.md).
6+
7+
## At a glance
8+
9+
| Item | Value |
10+
| ------------- | ---------------------------------- |
11+
| Web interface | `https://fusion.<tailnet>.ts.net` |
12+
| Service port | `8080` |
13+
| Image | `ghcr.io/0x2e/fusion` |
14+
| Data | `./fusion-data/` (SQLite database) |
15+
16+
## Before you start
17+
18+
Set these values in `.env`. Compose stops with an error if one of them is empty.
19+
20+
- **`TAILNET_NAME`.** Your Tailnet name, the part between the service name and `.ts.net`, for example `tail1234`. `compose.yaml` builds the allowed browser origin `https://<SERVICE>.<TAILNET_NAME>.ts.net` from it.
21+
- **`FUSION_PASSWORD`.** The password of the web interface. Generate one with `openssl rand -hex 32`. Fusion reads it at every start and never stores it, so you change the password by changing this value and running `docker compose up -d --force-recreate`. That also ends every open session, because Fusion keeps sessions in memory.
22+
23+
## Deviations from the standard setup
24+
25+
- **Allowed browser origin.** `FUSION_CORS_ALLOWED_ORIGINS` in `compose.yaml` holds the Tailnet address of the service, built from `SERVICE` and `TAILNET_NAME`. Fusion answers `403 Forbidden` to any request that carries another `Origin` header, so a browser can only use the service at that address. An empty value would accept every origin instead. For the same reason the optional `ports` block alone does not give access from your local network: the login request from a page on the address of the Docker host is rejected. To use that address as well, add it to the comma-separated list.
26+
27+
## First run
28+
29+
Open the web interface and log in with the password from `FUSION_PASSWORD`. Fusion has no user accounts, so the login form asks for the password only. A session lasts 30 days.
30+
31+
Add your first feed with the Add button. Fusion discovers the feed of a site when you give it the address of the page itself, and it pulls every feed every 30 minutes.
32+
33+
## Configuration
34+
35+
- **Single sign-on.** Fusion can add a login through an OIDC provider. Set `FUSION_OIDC_ISSUER`, `FUSION_OIDC_CLIENT_ID`, and `FUSION_OIDC_CLIENT_SECRET` in `.env`, then uncomment the four `FUSION_OIDC` lines in `compose.yaml`. Register `https://fusion.<tailnet>.ts.net/api/oidc/callback` as the redirect URI with your provider, because it must match the value that `compose.yaml` sends. Your provider must be reachable from the Fusion container, and from the browser you log in with. The password login stays available next to it, and `FUSION_PASSWORD` stays required: Fusion refuses to start with an empty password unless you also set `FUSION_ALLOW_EMPTY_PASSWORD=true`.
36+
- **Fever API clients.** Reeder, Unread, and other Fever clients use `https://fusion.<tailnet>.ts.net` as the server address, with the account type Fever, the username `fusion`, and your password. A client that asks for the endpoint itself takes `https://fusion.<tailnet>.ts.net/fever`. The device must be connected to your Tailnet. Fusion derives the Fever API key from the username and `FUSION_PASSWORD`, so a new password also means a new key in every client.
37+
- **Feed pulling.** `FUSION_PULL_INTERVAL`, `FUSION_PULL_TIMEOUT`, and `FUSION_PULL_CONCURRENCY` change how often and how fast Fusion pulls feeds. The [variable reference](https://github.com/0x2E/fusion/blob/main/.env.example) lists the defaults.
38+
39+
## Links
40+
41+
- [Fusion documentation and source code](https://github.com/0x2E/fusion)
42+
- [Fever API guide](https://github.com/0x2E/fusion/blob/main/docs/fever-api.md)

‎services/fusion/compose.yaml‎

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
configs:
2+
ts-serve:
3+
content: |
4+
{"TCP":{"443":{"HTTPS":true}},
5+
"Web":{"$${TS_CERT_DOMAIN}:443":
6+
{"Handlers":{"/":
7+
{"Proxy":"http://127.0.0.1:8080"}}}},
8+
"AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}}
9+
10+
services:
11+
# Make sure you have updated/checked the .env file with the correct variables.
12+
# Every variable used in this file must be defined there, unless it has a default such as ${VAR:-value}.
13+
# Tailscale Sidecar Configuration
14+
tailscale:
15+
image: tailscale/tailscale:latest # Image to be used
16+
container_name: tailscale-${SERVICE} # Name for local container management
17+
hostname: ${SERVICE} # Name used within your Tailscale environment
18+
environment:
19+
- TS_AUTHKEY=${TS_AUTHKEY}
20+
- TS_STATE_DIR=/var/lib/tailscale
21+
- TS_SERVE_CONFIG=/config/serve.json # Tailscale Serve configuration to expose the web interface on your local Tailnet - remove this line if not required
22+
- TS_USERSPACE=false
23+
- TS_ENABLE_HEALTH_CHECK=true # Enable healthcheck endpoint: "/healthz"
24+
- TS_LOCAL_ADDR_PORT=127.0.0.1:41234 # The <addr>:<port> for the healthz endpoint
25+
#- TS_ACCEPT_DNS=true # Uncomment only if the service must resolve MagicDNS names - this replaces Docker DNS, so Compose service names no longer resolve
26+
- TS_AUTH_ONCE=true
27+
configs:
28+
- source: ts-serve
29+
target: /config/serve.json
30+
volumes:
31+
- ./config:/config # Config folder used to store Tailscale files - you may need to change the path
32+
- ./ts/state:/var/lib/tailscale # Tailscale requirement - you may need to change the path
33+
devices:
34+
- /dev/net/tun:/dev/net/tun # Network configuration for Tailscale to work
35+
cap_add:
36+
- net_admin # Tailscale requirement
37+
#ports:
38+
# - 0.0.0.0:${SERVICEPORT}:${SERVICEPORT} # Binding the service port to the local network - may be removed if only exposure to your Tailnet is required
39+
# If any DNS issues arise, use your preferred DNS provider by uncommenting the config below
40+
#dns:
41+
# - ${DNS_SERVER}
42+
healthcheck:
43+
test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"] # Check Tailscale has a Tailnet IP and is operational
44+
interval: 1m # How often to perform the check
45+
timeout: 10s # Time to wait for the check to succeed
46+
retries: 3 # Number of retries before marking as unhealthy
47+
start_period: 10s # Time to wait before starting health checks
48+
restart: always
49+
50+
# Application
51+
application:
52+
image: ${IMAGE_URL} # Image to be used
53+
network_mode: service:tailscale # Sidecar configuration to route the service through Tailscale
54+
container_name: app-${SERVICE} # Name for local container management
55+
environment: # Variables are declared in .env file.
56+
- TZ=${TZ}
57+
- FUSION_DB_PATH=/data/fusion.db # SQLite database, kept in the mounted data folder
58+
- FUSION_PASSWORD=${FUSION_PASSWORD:?Set FUSION_PASSWORD in .env}
59+
- FUSION_CORS_ALLOWED_ORIGINS=https://${SERVICE}.${TAILNET_NAME:?Set TAILNET_NAME in .env}.ts.net # Only the Tailnet address may call the API from a browser; an empty value would allow any origin
60+
- FUSION_TRUSTED_PROXIES=127.0.0.1 # Tailscale Serve reaches Fusion over the shared loopback, so trust its X-Forwarded-For for the login rate limit
61+
# Optional single sign-on. Uncomment all four lines and set the three values in .env - see "Configuration" in the README.
62+
#- FUSION_OIDC_ISSUER=${FUSION_OIDC_ISSUER}
63+
#- FUSION_OIDC_CLIENT_ID=${FUSION_OIDC_CLIENT_ID}
64+
#- FUSION_OIDC_CLIENT_SECRET=${FUSION_OIDC_CLIENT_SECRET}
65+
#- FUSION_OIDC_REDIRECT_URI=https://${SERVICE}.${TAILNET_NAME}.ts.net/api/oidc/callback
66+
volumes:
67+
- ./${SERVICE}-data:/data # SQLite database with the feeds, articles, and settings
68+
depends_on:
69+
tailscale:
70+
condition: service_healthy
71+
# Healthcheck: defined by the image (wget against /api/oidc/enabled), so this file does not override it.
72+
restart: always

0 commit comments

Comments
 (0)