Zublo

Self-hosted subscription tracking with AI that is actually useful.

Open source. Docker-first. Built for self-hosters, homelabs, and people who want control over recurring payments.

Deploy in minutes · See the demo section · Read the architecture

Apache 2.0 License GitHub stars GitHub issues Docker deployment PocketBase AI built in Self-hosted

Zublo is an open source subscription tracker for people who want every recurring payment in one place, full control over their data, and a deployment flow that takes minutes instead of a weekend. It gives you a clean web UI, recurring payment visibility, reminders, calendar and statistics views, API access, and a Docker-first setup built for self-hosters. It also has one of the most differentiated parts of the product built in: an AI layer that can analyze spending, power chat-based workflows, and connect to multiple LLM providers instead of locking you into a single vendor. If you want a focused alternative to bloated finance software or closed SaaS trackers, this is the repo. ## Why This Repo Gets Attention - It solves a real problem with a narrow, practical scope - It is self-hosted, so your data stays under your control - It is easy to deploy and easy to understand - It uses a compact stack instead of a pile of infrastructure - It is useful on day one, even if you never touch the code ## At A Glance | What matters | Why it lands | |---|---| | One job, done well | Track recurring payments without turning into a full finance suite | | Fast deployment | A simple Docker setup gets the app running quickly | | Real ownership | Your data lives on your infrastructure | | AI that is actually useful | Chat, recommendations, and provider flexibility are part of the product | | Compact architecture | React frontend, PocketBase runtime, no unnecessary platform sprawl | | Forkable codebase | Small enough to understand, practical enough to extend | ## Perfect For | Use case | Why Zublo fits | |---|---| | Self-hosters | One container, SQLite persistence, no heavy platform requirements | | Homelab users | Small footprint, easy backup story, easy reverse proxy integration | | Privacy-minded users | Your subscription data stays on your own infrastructure | | Indie builders | Compact full-stack codebase that is practical to fork and extend | | Teams tracking shared spend | Clear recurring cost visibility without adopting a full finance suite | ## Demo Demo screenshots

Zublo dashboard demo

Subscriptions view

Calendar view

Statistics view

Chat view

## Feature Overview | Area | What you get | |---|---| | Subscriptions | Recurring billing cycles, due dates, payment context, change history with total spent | | Calendar | Upcoming payments in a calendar view | | Dashboard | High-level cost visibility and summary metrics | | Statistics | Spending breakdowns and trend visibility | | Currencies | Multi-currency handling with exchange-rate sync | | API access | REST usage through scoped API keys | | AI | Chat-based workflows, recommendations, and pluggable providers | | Authentication | TOTP-based 2FA | | Deployment | Single self-hosted app with Docker | ## AI Built In This is not a cosmetic AI checkbox. Zublo includes an AI layer that can work with your subscription data and support real product workflows: - AI-powered recommendations from your spending data - chat interface wired into app capabilities - support for multiple provider setups instead of a single locked vendor - compatibility with local or self-hosted inference paths Supported provider model includes: - Google Gemini - OpenAI - Ollama - OpenAI-compatible endpoints such as OpenRouter, Groq, Mistral, and similar gateways That makes Zublo interesting not only as a self-hosted subscription tracker, but also as a practical example of an AI-enabled product that still keeps deployment and ownership simple. ## Why It Feels Good To Self-Host | Characteristic | What that means in practice | |---|---| | Single app runtime | Frontend and backend ship together | | SQLite persistence | Simple backups and low operational overhead | | PocketBase core | Auth, data, and admin capabilities without a large backend stack | | Docker-first packaging | Easy to run on VPS, NAS, mini-PC, or homelab | | Narrow product scope | Less maintenance drag than a general finance platform | ## What Zublo Is Not - not a full accounting suite - not a bookkeeping platform - not a bank sync product - not a cloud-only SaaS That narrow scope is the point. ## Stack | Layer | Technology | |---|---| | Frontend | React 18, Vite, TypeScript, TanStack Router, React Query, Tailwind CSS | | Backend runtime | PocketBase | | Backend customization | PocketBase JS hooks and migrations | | Persistence | SQLite via PocketBase | | Packaging | Docker, Docker Compose, GHCR | ## Deploy In Minutes Create a `docker-compose.yml` like this: ```yaml services: zublo: image: ghcr.io/danielalves96/zublo:latest container_name: zublo restart: unless-stopped ports: - "9597:9597" environment: PB_ENCRYPTION_KEY: "change-me-in-production" volumes: - ./zublo-data:/pb/pb_data ``` Start it: ```bash docker compose up -d ``` Then open: - `http://localhost:9597` for the app - `http://localhost:9597/_/` for PocketBase admin - `http://localhost:9597/api/` for the REST API Important: - persist `/pb/pb_data` - set `PB_ENCRYPTION_KEY` in real deployments - the first registered user becomes the initial admin ### Running Behind A Reverse Proxy Zublo is a single PocketBase process, so any proxy that forwards plain HTTP to `9597` without buffering or rewriting the request body works. A minimal Caddy example: ``` zublo.example.com { reverse_proxy localhost:9597 } ``` If you enable MFA or update your profile and get unexpected `400` responses, the most common cause is a proxy directive that buffers, compresses, or rewrites the request body (large `client_max_body_size`/`request_body` tweaks, aggressive compression, or a `Content-Length`/chunked mismatch). Keep the proxy config as close to a plain passthrough as possible; there's no proxy-specific handling required on the Zublo side. ## Local Development If you want to work on the repo itself: ```bash bun install bun run dev ``` This starts: - Vite on `http://localhost:5173` - PocketBase on `http://127.0.0.1:8080` For non-Docker local development, the repository expects a PocketBase binary at `apps/backend/pocketbase`. ## Architecture At A Glance Zublo is intentionally compact. - `apps/web` contains the React application - `apps/backend` contains PocketBase hooks, migrations, runtime assets, and backend behavior - the frontend is built into `apps/backend/pb_public` for production serving - PocketBase serves both the API and the built frontend in production - mutable runtime data lives in `/pb/pb_data` In local development: - Vite serves the frontend - PocketBase serves the API - Vite proxies `/api` to PocketBase In production: - one container serves the frontend and backend together For the full repository-level architecture, see [ARCHITECTURE.md](./ARCHITECTURE.md). For frontend-specific structure and page composition rules, see [apps/web/ARCHITECTURE.md](./apps/web/ARCHITECTURE.md). ## Repository Layout ```text . ├── apps/ │ ├── backend/ # PocketBase hooks, migrations, runtime assets │ └── web/ # React application ├── scripts/ # Maintainer utilities ├── Dockerfile ├── docker-compose.yml ├── Makefile └── README.md ``` ## Who This Repository Is For - self-hosters - homelab users - contributors who want a small, understandable full-stack app - developers interested in PocketBase-backed products ## Why The Codebase Stays Approachable - React frontend and PocketBase backend live in the same repo - custom backend logic is grouped by domain in hook files - the production runtime is compact and easy to reason about - the deployment model is simple enough for solo operators - the product scope is intentionally constrained ## Contributing Zublo is still shaping its public open source surface. Good contributions right now are the ones that improve clarity, onboarding, maintainability, and narrowly scoped behavior. Start here: - [CONTRIBUTING.md](./CONTRIBUTING.md) - [SUPPORT.md](./SUPPORT.md) - [SECURITY.md](./SECURITY.md) - [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) ## Maintainer Zublo is maintained by Daniel Luiz Alves. GitHub: `@danielalves96` ## License Zublo is licensed under Apache License 2.0. Copyright Daniel Luiz Alves. See [LICENSE](./LICENSE) and [NOTICE](./NOTICE).