8.5 KiB
Administrator Guide
This guide covers everything needed to deploy and maintain a multi-user BincioActivity instance.
Before You Start
Multi-user Deployment has the complete step-by-step instructions. This guide focuses on day-to-day admin tasks once the instance is running.
Initializing an Instance
uv sync --extra serve
uv run bincio init \
--data-dir /var/bincio \
--handle your_admin_handle \
--display-name "Your Name" \
--name "Instance Name"
You'll be prompted for a password. This creates:
/var/bincio/instance.db— SQLite database (users, sessions, invites, reset codes)/var/bincio/index.json— root shard manifest ("private": trueby default)- Your admin user account
- A first invite code
bincio init is idempotent — safe to re-run.
Optional flags:
--max-users N— limit total registered users (0 or omitted = unlimited)--store-originals false— don't keep uploaded source files (defaults to true)
Inviting Users
Generate an invite code (as admin)
From the web UI at /invites/ (requires login as admin), or via CLI:
uv run python -c "
from pathlib import Path
from bincio.serve.db import open_db, create_invite
db = open_db(Path('/var/bincio'))
code = create_invite(db, 'your_handle')
print(f'https://yourdomain.com/register/?code={code}')
"
Invite limits
- Admins: unlimited invites
- Regular users: 3 invites each (configurable in
bincio/serve/db.pyas_MAX_USER_INVITES)
Share the invite link
Send the registration link to the user:
https://yourdomain.com/register/?code=ABCD1234
They create their own handle and password. After registration, they can:
- Upload activity files (GPX, FIT, TCX)
- Sync from Strava
- Edit activity titles, descriptions, photos
- Control privacy per activity
Password Reset
BincioActivity has no email system. Password resets work via admin-generated one-time codes.
Reset a user's password (as admin)
- Open
/admin/in the web UI (must be logged in as admin) - Find the user and click Reset password
- A code appears (monospace, click to copy)
- Send the code out-of-band (Signal, Telegram, WhatsApp, etc.)
The code is valid for 24 hours. Users reset their password at /reset-password/ by entering:
- Their handle
- The code
- Their new password
Reset code API (CLI)
To generate a reset code programmatically:
uv run python -c "
from pathlib import Path
from bincio.serve.db import open_db, create_reset_code
db = open_db(Path('/var/bincio'))
code, expires_in_hours = create_reset_code(db, 'user_handle', 'your_handle')
print(f'Code: {code} (expires in {expires_in_hours} hours)')
"
Monitoring Active Jobs
The /api/admin/jobs endpoint (admin-only) shows which uploads/syncs are in progress:
curl -b "bincio_session=$(cat /tmp/session.txt)" http://localhost:4041/api/admin/jobs
Returns:
[
{
"id": "a1b2c3d4",
"user": "alice",
"started_at": 1712345678,
"total": 50,
"done": 23,
"current": "activity_2026-03-15_120000Z.fit"
}
]
Triggering Rebuilds
bincio serve can trigger incremental rebuilds when you pass --site-dir:
uv run bincio serve \
--data-dir /var/bincio \
--site-dir /var/www/bincio/src/site
After any write operation (edit, upload, Strava sync), the affected user's shard is rebuilt automatically and the static site is updated.
To manually rebuild a single user's shard:
uv run bincio render \
--data-dir /var/bincio \
--handle alice
To rebuild everything (slow):
uv run bincio render --data-dir /var/bincio
Instance Settings
Settings are stored in instance.db and control instance-wide behavior:
| Setting | Default | Controls |
|---|---|---|
max_users |
unlimited | Maximum registered users allowed |
store_originals |
true |
Keep uploaded source files and Strava sync data |
Read/set settings via CLI:
uv run python -c "
from pathlib import Path
from bincio.serve.db import open_db, get_setting, set_setting
db = open_db(Path('/var/bincio'))
print(get_setting(db, 'max_users'))
set_setting(db, 'max_users', 100)
db.commit()
"
Or check the database directly:
sqlite3 /var/bincio/instance.db
> SELECT key, value FROM settings;
Instance Privacy
By default, new instances are private — only authenticated users can view anything. Edit the root index.json to toggle:
{
"private": false,
"shards": [...]
}
"private": true— all pages (except login/register) require authentication"private": false— public access to all activities; individual activities can still be marked private via theprivateflag in sidecars
After any change, run bincio render to apply it:
uv run bincio render --data-dir /var/bincio
Data Directory Layout
/var/bincio/
instance.db ← SQLite: users, sessions, invites, reset codes
index.json ← root shard manifest
{handle}/
index.json ← user's BAS feed (activities list)
_merged/ ← sidecar-merged output (served to browser)
activities/ ← extracted activity JSON files
{id}.json
...
edits/ ← user-made sidecar edits
{id}.md
images/{id}/
athlete.json ← profile (from Strava or manual)
strava_token.json ← OAuth token (if synced from Strava)
originals/ ← source files (if store_originals=true)
_feedback/ ← user feedback submissions
{handle}.json
{handle}/
{timestamp}_{id}_{filename}
Database Schema
instance.db contains:
users— handle, password hash, display_name, is_admin, created_atsessions— session_id, handle, created_at, expires_atinvites— code, created_by, created_at, used_by, used_atreset_codes— code, handle, created_by, created_at, expires_at, used_atsettings— key, value (instance config)user_preferences— handle, key, value (per-user settings)
Query the database directly:
sqlite3 /var/bincio/instance.db ".tables"
sqlite3 /var/bincio/instance.db "SELECT handle, is_admin FROM users;"
API Endpoints for Admins
The /api/admin/* endpoints require authentication and admin privileges:
GET /api/admin/users— List all usersPOST /api/admin/users/{handle}/reset-password-code— Generate a reset codeGET /api/admin/jobs— Show active uploads/syncsGET /api/stats— Community stats (public)
See API Reference for full details.
Explore the API with Swagger UI
When bincio serve is running, visit /api/docs to see an interactive Swagger UI. You can:
- Browse all endpoints with their parameters and response types
- Try out requests directly (if you're logged in as admin)
- See live examples of request/response bodies
ReDoc (another API documentation format) is also available at /api/redoc with a different UI.
Running as a systemd service
See Multi-user Deployment for the systemd unit file. Key points:
- Set
User=bincio(unprivileged user) - Set
WorkingDirectoryto the repo root - Use
--site-dirto enable incremental rebuilds - Restart policy:
Restart=on-failure
Monitor with:
systemctl status bincio
journalctl -u bincio -f
Troubleshooting
Activities not appearing after upload
- Check if the job is still running:
GET /api/admin/jobs - Check logs:
journalctl -u bincio -f - If
store_originals=true, verify the source file is readable in{handle}/originals/ - Re-trigger the merge:
uv run bincio render --data-dir /var/bincio --handle alice
Database locked
If you see "database is locked":
- Verify no other
bincioprocesses are running:ps aux | grep bincio - Kill any stuck processes:
pkill -f 'uv run bincio' - Restart the service:
systemctl restart bincio
High memory usage
The first rebuild on a large instance can be memory-intensive. Consider:
- Running
bincio renderduring off-hours - Rebuilding one user at a time:
uv run bincio render --data-dir /var/bincio --handle alice - Increasing swap or upgrading the machine
See also
- Multi-user Deployment — complete step-by-step setup
- Single-user Deployment — if you're hosting a read-only site
- API Reference — all HTTP endpoints