macOS or Windows
Docker Desktop
- Download it from docker.com and install.
- On Windows it uses WSL 2. If prompted, enable it and restart.
- Open Docker Desktop and wait until it says it's running.
Setup guide
Install Docker, unzip Skint, and open it at localhost:8080. Each step stands on its own, so jump straight to where you are.
Skint runs in Docker. Pick the option for your system. You only need one.
docker --version
docker compose version
docker run --rm hello-worldUse docker compose with a space. The older docker-compose command isn't needed.
Get the single zip. It contains the app source, the Dockerfile, docker-compose.yml and .env.example.
Unzip it into a new folder, then open a terminal in that folder for the next steps.
Copy the example settings file, then edit it in any text editor.
cp .env.example .env| Setting | What it does |
|---|---|
APP_PASSWORD | Turns on the sign-in screen. Leave it empty to run without one. |
APP_USER | The username for the sign-in screen. Defaults to admin. |
ALLOWED_HOSTS | Domain names the app answers to, such as skint.example.com,localhost. Empty accepts any address. |
MFA_REMEMBER_DAYS | Days a trusted browser stays signed in without a code. Defaults to 7. Set 0 to ask every time. |
ALLOWED_HOSTS, include localhost too if you'll open Skint from the same machine.Run this in the folder with docker-compose.yml. The first build takes a minute or two.
docker compose up -d --buildThen open http://localhost:8080 in your browser.
Useful commands
docker compose ps # check the container is running
docker compose logs -f skint # follow the app's log
docker compose restart skint # restart after changing .env
docker compose down # stop the app (your data is kept)On the first run the dashboard offers Import spreadsheet. Choose your Expenditure.xlsx in Settings and the data loads.
Prefer to start fresh? Skip the import and add bills from the Bills page.
Add each person in Settings → People. Everyone then sets up two-step sign-in: they scan a QR code with an authenticator app, enter the first code, and save their eight recovery codes.
Skint listens on port 8000 inside its container. The default setup publishes that as port 8080. If you already run Traefik or nginx, put Skint on your proxy network instead and let the proxy handle HTTPS. Replace skint.example.com with your domain in each example.
Traefik
Assumes Traefik has a websecure entrypoint, a letsencrypt certificate resolver, and an external Docker network called proxy. The app's own compose file is not in the download.
services:
skint:
build: .
container_name: skint
restart: unless-stopped
networks:
- proxy
environment:
APP_USER: ${APP_USER:-admin}
APP_PASSWORD: ${APP_PASSWORD:-}
ALLOWED_HOSTS: skint.example.com
MFA_REMEMBER_DAYS: ${MFA_REMEMBER_DAYS:-7}
volumes:
- skint-data:/data
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.skint.rule=Host(`skint.example.com`)"
- "traefik.http.routers.skint.entrypoints=websecure"
- "traefik.http.routers.skint.tls.certresolver=letsencrypt"
- "traefik.http.services.skint.loadbalancer.server.port=8000"
networks:
proxy:
external: true
volumes:
skint-data:nginx
Skint and nginx share a private network. Skint publishes no port, so only nginx can reach it. Put your certificate and key where the paths in nginx.conf point.
services:
skint:
build: .
container_name: skint
restart: unless-stopped
networks:
- web
environment:
APP_USER: ${APP_USER:-admin}
APP_PASSWORD: ${APP_PASSWORD:-}
ALLOWED_HOSTS: skint.example.com
MFA_REMEMBER_DAYS: ${MFA_REMEMBER_DAYS:-7}
volumes:
- skint-data:/data
nginx:
image: nginx:stable
container_name: skint-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/skint.conf:ro
- ./certs:/etc/nginx/certs:ro
networks:
- web
depends_on:
- skint
networks:
web:
volumes:
skint-data:nginx.conf
server {
listen 80;
server_name skint.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name skint.example.com;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
location / {
proxy_pass http://skint:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}