Wallos is a free, open-source, self-hosted subscription tracker. Add every streaming service, app, domain and gym membership you pay for and Wallos shows what they really cost you per month and per year, across multiple currencies, with logos, categories and payment methods. It can also remind you before each payment by email, Discord, Telegram, Gotify, Pushover or webhook, so a forgotten free trial never turns into a year's charge again.
In this guide we will run Wallos in Docker using the official image, create your account and set up notifications, then put it behind a reverse proxy.
bellamy/wallos.✅ Before you start
- A Linux host with Docker and Docker Compose v2 installed (
docker compose versionshould work). Usedocker composewith a space: the old Pythondocker-composev1 can crash on modern Docker. - One free port,
8282, for the web UI. - Optional: a reverse proxy such as Traefik or Nginx Proxy Manager and a domain, if you want to reach it from outside your home network.
STEP 1: User and group IDs (and your secrets)
Wallos does not use PUID/PGID, and it has no secrets to generate: it is a single container with a SQLite database, and you create your login in the browser.
STEP 2: Create the folders
I keep every app's files under one parent folder so a backup is a single job. Create the folders for Wallos:
mkdir -p /path/to/appdata/wallos/{db,logos}When you are done, the layout should look like this:
/path/to/appdata/wallos/
docker-compose.yml
db/ # SQLite database
logos/ # uploaded subscription logosFolder layout
Finally, I give every web app that sits behind my reverse proxy one shared Docker network called proxy. Wallos joins it so Traefik or Nginx Proxy Manager can reach it by container name, while its database and helpers stay on the stack's own private network. Create it once (if it already exists, Docker just tells you so):
docker network create proxySTEP 3: The compose file
Create /path/to/appdata/wallos/docker-compose.yml and paste in the following. It is the official compose file with my paths, time zone and the shared proxy network added. Use the copy button in the top right corner of the block.
services:
wallos:
container_name: wallos
image: bellamy/wallos:latest
restart: unless-stopped
ports:
- "8282:80/tcp"
environment:
TZ: 'Europe/London'
volumes:
- /path/to/appdata/wallos/db:/var/www/html/db
- /path/to/appdata/wallos/logos:/var/www/html/images/uploads/logos
networks:
- proxy
networks:
proxy:
external: truedocker-compose.yml
STEP 4: The settings explained
| Setting | What it does |
|---|---|
8282:80/tcp |
Wallos serves its web UI on port 80 inside the container; you reach it on 8282. |
TZ |
Your time zone. Wallos runs scheduled jobs inside the container (next payment dates, exchange rates, notifications), so this decides when reminders go out. List of zones. |
/var/www/html/db |
The SQLite database: all your subscriptions and settings. Back up this folder. |
/var/www/html/images/uploads/logos |
Logos you upload or fetch for your subscriptions. |
OIDC_* (optional) |
Single sign-on with Authelia, Authentik and others. The official compose file lists every variable; you can also set it up on the Admin page. |
STEP 5: Start Wallos
From the folder containing your compose file:
cd /path/to/appdata/wallos
docker compose up -d
docker compose logs -fWait until the logs settle down (press Ctrl+C to stop following them; the container keeps running), then check it is up:
docker ps --filter name=wallosYou should see wallos listed as Up. The image has a health check, so after a few seconds it shows (healthy).
STEP 6: First-run setup
- Open
http://192.168.1.20:8282. On the first run, Wallos asks you to create a user account: this is your admin account. - Choose your main currency and language, then add your subscriptions: name, price, currency, billing cycle and next payment date. Search for a logo or upload your own.
- Under Settings, add household members, categories and payment methods, and a free Fixer API key if you want automatic exchange rates.
- Set up Notifications (email, Discord, Telegram, Gotify, Pushover or webhooks) and choose how many days before each payment you want a reminder.
- Check the Statistics page. It is usually a sobering moment.
Wallos blocks webhook, SMTP and OIDC URLs on private addresses by default (it protects against SSRF). Add your internal hosts, such as
192.168.1.20:8080, to the allowlist under the Admin page's security settings, or set SSRF_ALLOWLIST in the compose file.STEP 7: Put Wallos behind a reverse proxy
Use a dedicated hostname such as wallos.example.com.
Option A: Traefik (Docker labels)
If Traefik runs on the same Docker host and is attached to the proxy network, add these labels to the wallos service. They assume your HTTPS entry point is called websecure and your certificate resolver is called cloudflare; change them to match your Traefik config.
labels:
- traefik.enable=true
- traefik.http.routers.wallos.rule=Host(`wallos.example.com`)
- traefik.http.routers.wallos.entrypoints=websecure
- traefik.http.routers.wallos.tls.certresolver=cloudflare
- traefik.http.services.wallos.loadbalancer.server.port=80docker-compose.yml (extra lines)
Option B: Traefik (file provider)
If Traefik runs on a different machine, add a router and service to your dynamic config file instead:
http:
routers:
wallos:
rule: Host(`wallos.example.com`)
entryPoints:
- websecure
tls:
certResolver: cloudflare
service: wallos
services:
wallos:
loadBalancer:
servers:
- url: http://192.168.1.20:8282dynamic.yml
Option C: Nginx Proxy Manager
Add a Proxy Host for wallos.example.com with scheme http, forward hostname wallos (if NPM is on the proxy network) or 192.168.1.20, and forward port 80 (or 8282 if you use the host IP). Request a certificate on the SSL tab and tick Force SSL.
Once everything goes through the proxy, you can remove the ports: section, or limit it to the host with "127.0.0.1:8282:80".
Updating Wallos
The latest tag always follows the newest stable release. To update:
cd /path/to/appdata/wallos
docker compose pull
docker compose up -d
docker image prune -fdocker exec wallos php /var/www/html/endpoints/db/migrate.php. Back up the db folder first.Troubleshooting
Reminders arrive at the wrong time, or not at all. Check TZ, and test the notification method from the Settings page. For a self-hosted target, add it to the SSRF allowlist.
Exchange rates never update. You need a Fixer API key under Settings.
Lost everything after recreating the container. The db folder was not mounted. Check the volumes: paths.
The container shows unhealthy on old Docker. The README notes the health check needs Docker 25 or newer; add healthcheck: { disable: true } on older versions, or better, update Docker.
That's it! Every subscription in one place. Now go and cancel the ones you forgot about. 💸