Files
qrknit/INSTALL.md
T
Jason Stedwell 48d3445b09 docs: document new features, ops env vars, and API surface; refresh roadmap
- README: feature map updated (redirect types, protected links, QR vector
  export, audience analytics, API keys, admin observability, operations);
  API reference covers new endpoints and params. Roadmap now lists
  self-serve accounts, security hardening (rate limiting/CSRF/SSRF guard),
  Stripe billing, custom domains, and remaining power features.
- INSTALL: new environment variables (WEBHOOK_URL, GEOIP_DB_PATH,
  GEO_API_FALLBACK, IP_ANONYMIZE, CLICK_RETENTION_DAYS, BACKUPS,
  BACKUP_DIR, BACKUP_KEEP) with GeoLite2 setup notes and the ip-api.com
  licensing caveat.
- api-docs page: API-key authentication, new link/analytics/QR params,
  aggregate analytics, admin overview/audit/keys/purge, unlock route.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 01:40:44 -05:00

7.3 KiB

QRknit — Installation & Configuration

Prerequisites

  • Docker installed and running
  • A domain or subdomain pointed at your server (for public access)

Generate a strong SECRET_KEY before you begin:

python3 -c "import secrets; print(secrets.token_hex(32))"

Option A — Docker run (quickest)

1. Get the source

git clone https://git.qrknit.com/qrknit.git
cd qrknit

2. Build the image

docker build -t qrknit:latest .

3. Run the container

docker run -d \
  --name qrknit \
  --restart unless-stopped \
  -p 5000:5000 \
  -v qrknit-data:/app/data \
  -e BASE_URL=https://yourdomain.com \
  -e APP_NAME=My.Links \
  -e SECRET_KEY=your-generated-key-here \
  -e ADMIN_PASSWORD=your-strong-password \
  qrknit:latest

Open http://localhost:5000 (or your domain) and log in with admin / your ADMIN_PASSWORD.


Option B — Docker Compose

1. Get the source

git clone https://git.qrknit.com/qrknit.git
cd qrknit

2. Edit docker-compose.yml — set at minimum:

- BASE_URL=https://yourdomain.com
- APP_NAME=My.Links
- SECRET_KEY=your-generated-key-here
- ADMIN_PASSWORD=your-strong-password

3. Build and start

docker compose up -d --build

Option C — Unraid (fresh install)

Step 1 — Get the source onto Unraid

Open the Unraid terminal and run:

cd /mnt/user/appdata
git clone https://git.qrknit.com/qrknit.git qrknit-src  # credentials provided with your Pro/Team licence

Or upload the source files manually to /mnt/user/appdata/qrknit-src/.

Step 2 — Build the image

cd /mnt/user/appdata/qrknit-src
docker build -t qrknit:latest .

Private instance access (source repository credentials and licence key) is included with Pro and Team plans. Contact support if you have not received yours.

Step 3 — Add the container in the Unraid Docker UI

Go to Docker tab → Add Container and fill in:

Field Value
Name qrknit
Repository qrknit:latest
Network Type br0 (macvlan) or Bridge
Port Mapping Host 5000 → Container 5000 (not needed for macvlan)
Path (Volume) Host /mnt/user/appdata/qrknit → Container /app/data

Add the following Environment Variables:

Variable Value Notes
BASE_URL https://yourdomain.com Your public domain or subdomain
APP_NAME My.Links Display name shown in the UI — names with a dot (e.g. to.mysite.io) are split and styled automatically
SECRET_KEY (generated above) Required — signs session cookies
ADMIN_PASSWORD (your password) Required — admin account password
ADMIN_USERNAME admin Admin username (default: admin)
COOKIE_SECURE false Keep false behind Cloudflare or NPM. Set true only if Flask receives HTTPS directly.
DEBUG false Keep false in production

Click Apply.

Step 4 — Set up a reverse proxy (optional but recommended)

Cloudflare:

  • Point your DNS A record to your Unraid IP
  • Enable Always Use HTTPS in Cloudflare dashboard (SSL/TLS → Edge Certificates)
  • Keep COOKIE_SECURE=false — Cloudflare terminates TLS before Flask sees the request
  • CF-IPCountry header is forwarded automatically — no extra configuration needed for geographic analytics

Nginx Proxy Manager:

  • Add a proxy host: your domain → unraid-lan-ip:5000
  • Issue a Let's Encrypt certificate on the SSL tab
  • Keep COOKIE_SECURE=false — same reason as Cloudflare
  • For country analytics without Cloudflare, mount a free MaxMind GeoLite2-Country database at GEOIP_DB_PATH (see Environment Variables), or set GEO_API_FALLBACK=true for non-commercial deployments

Step 5 — Verify

docker inspect --format='{{.State.Health.Status}}' qrknit
# healthy

curl https://yourdomain.com/api/health
# {"status":"ok"}

Updating

Your data lives in the Docker volume and is preserved across updates.

Docker / Docker Compose:

cd /path/to/qrknit-src
git pull
docker build -t qrknit:latest .
docker stop qrknit && docker rm qrknit
# Re-run the same docker run command from installation

Unraid:

cd /mnt/user/appdata/qrknit-src
git pull
docker build -t qrknit:latest .

Then click Force Update on the container in the Docker tab.

Sessions survive restarts as long as SECRET_KEY stays the same. Changing SECRET_KEY invalidates all active sessions — users will need to log in again.


Environment Variables

Variable Default Description
BASE_URL http://localhost:5000 Public URL of your instance — used in short links and QR codes
APP_NAME My.Links Display name in the header, hero, login modal, and page title. Names with a dot are split and styled automatically.
SECRET_KEY (required) Signs session cookies — use a long random string
ADMIN_PASSWORD (required) Admin account password — upserted on every startup
ADMIN_USERNAME admin Admin account username
PORT 5000 Port Gunicorn listens on
DEBUG false Flask debug mode — keep false in production
COOKIE_SECURE false Set true only if Flask receives HTTPS directly (not behind a proxy)
DB_PATH /app/data/qrknit.db SQLite file path — leave as-is when using a Docker volume
WEBHOOK_URL (empty) Slack/Discord-compatible webhook — notified on new contact messages
GEOIP_DB_PATH /app/data/GeoLite2-Country.mmdb Local MaxMind GeoLite2 country database for click geolocation. Download from maxmind.com (free account) and mount into the data volume. Preferred over any network lookup.
GEO_API_FALLBACK false Enable ip-api.com lookups when no GeoLite2 DB is present. Their free tier is licensed for non-commercial use only and rate-limited (~45 req/min) — behind Cloudflare you don't need this (the CF-IPCountry header is used automatically).
IP_ANONYMIZE none Privacy policy for stored click IPs: none, truncate (zero the host part), or hash (SHA-256 — unique-visitor counting still works)
CLICK_RETENTION_DAYS 0 Purge click events older than N days (0 = keep forever)
BACKUPS true Daily SQLite backup via VACUUM INTO
BACKUP_DIR <db dir>/backups Where daily backups are written
BACKUP_KEEP 7 Number of daily backups to retain

Project Structure

qrknit/
├── app.py              # Flask backend — all routes and logic
├── index.html          # App SPA (inline CSS + JS, served at /app)
├── landing.html        # SaaS-focused landing page (default route /)
├── landing-os.html     # Private Instance landing page (served at /landing-os)
├── static/
│   └── qk-ico.png      # App icon (served at /static/qk-ico.png)
├── requirements.txt    # Python dependencies
├── Dockerfile          # Multi-stage Docker build
├── docker-compose.yml  # For non-Unraid deployments
├── .dockerignore
├── NOTICES.md
├── INSTALL.md
└── README.md

© 2025 QRknit. All rights reserved. This document and the accompanying software are proprietary. Redistribution or disclosure without a valid QRknit licence is prohibited.