Generate QR codes for 8 real-world use cases via a FastAPI backend, Debian-slim Docker image, and a responsive dark two-column web UI. Live preview, SVG + PNG export, error correction control, and custom colors — no external dependencies, no third-party services.
▸ 8 QR modes → Text/URL · WiFi · Contact · Email · SMS · Phone · Location · Event
▸ Live preview → QR updates as you type — no submit button
▸ SVG + PNG → Download both formats; smart filenames per mode
▸ Error correction → L / M / Q / H (default M — use H for logo overlays)
▸ Custom colors → Module color + background color pickers
▸ MeCard → Compact contact format natively recognized by iOS Camera
▸ Geo mode → "Use my location" button + optional label
▸ Event mode → Calendar event (VEVENT) with pre-filled start/end times
▸ Mini preview → Inline QR thumbnail in QR Options — visible while adjusting
▸ /qr API → PNG or SVG endpoint usable from curl, scripts, or any HTTP client
▸ Zero disk I/O → All QR codes generated in-memory
▸ Bind-mount → Edit code without rebuilding the container
qrforge
│
├── app/
│ ├── main.py # FastAPI server — / and /qr endpoints
│ ├── __init__.py
│ └── templates/
│ └── index.html # Dark UI — all payload building in client-side JS
│
├── Dockerfile # python:3.12-slim-bookworm base
├── docker-compose.yml # Bind-mount, port 8002, restart unless-stopped
├── requirements.txt
└── README.md
docker compose up --build --detachdocker compose pshttp://localhost:8002/
docker compose downLive reload: the compose file bind-mounts
./appinto the container. Editingmain.pyorindex.htmltakes effect immediately — no rebuild needed. Only rebuild ifrequirements.txtorDockerfilechanges.
docker build --tag qrforge:2.1.0 .docker run --rm --name qrforge --publish 8002:8002 qrforge:2.1.0http://localhost:8002/
docker stop qrforgeSelect a mode from the grid — the form updates instantly. QR preview refreshes as you type.
| Mode | Encodes | Scanned action |
|---|---|---|
| Text / URL | Any string or URL | Opens URL / displays text |
| WiFi | WPA/WPA2/WEP/nopass + hidden flag | Joins the network |
| Contact (vCard) | Full vCard 3.0 — name, org, title, phones, email, URL, address, note | Prompts "Add Contact" |
| Contact (MeCard) | Compact MeCard — same fields minus title | Prompts "Add Contact" (iOS Camera native) |
mailto: with To / Subject / Body |
Opens email app pre-filled | |
| SMS | smsto: with number + message |
Opens SMS app pre-filled |
| Phone | tel: number |
Opens dialer |
| Location | geo: lat/lng + optional label |
Opens Maps |
| Event | VEVENT — title, start, end, location, description | Offers to add to calendar |
All parameters are query string values.
| Parameter | Required | Default | Description |
|---|---|---|---|
data |
✅ | — | String to encode |
scale |
6 |
PNG scale factor (1–50). Each module is scale pixels wide. |
|
border |
4 |
Quiet-zone width in modules (0–20) | |
ec |
M |
Error correction: L 7% · M 15% · Q 25% · H 30% |
|
dark |
#000000 |
Module color — hex (#ff0000) or CSS name (darkred) |
|
light |
#ffffff |
Background color — hex or CSS name | |
fmt |
png |
Output format: png or svg |
curl -G --data-urlencode "data=https://example.com" \
http://localhost:8002/qr --output qr.pngcurl -G --data-urlencode "data=Hello" \
--data "scale=12&border=2&ec=H" \
http://localhost:8002/qr --output qr_large.pngcurl -G --data-urlencode "data=https://example.com" \
--data "dark=%23ff0000&light=%23000000" \
http://localhost:8002/qr --output qr_red.pngcurl -G --data-urlencode "data=https://example.com" \
--data "fmt=svg" \
http://localhost:8002/qr --output qr.svgcurl -G --data-urlencode "data=WIFI:T:WPA;S:MyNetwork;P:MyPass;H:false;;" \
http://localhost:8002/qr --output wifi.pngDATA="BEGIN:VCARD
VERSION:3.0
N:Smith;Jane;;;
FN:Jane Smith
TEL;TYPE=CELL:+15550000000
EMAIL:jane@example.com
END:VCARD"
curl -G --data-urlencode "data=${DATA}" \
http://localhost:8002/qr --output contact.pngFastAPI → Routing, HTML rendering, input validation
segno → QR generation (PNG + SVG, all error correction levels, custom colors)
Jinja2 → HTML templating
uvicorn → ASGI server
Browser → GET / → Jinja2 renders index.html
JS → builds payload → GET /qr?data=...&ec=M&dark=#000&fmt=png
segno → generates QR → in-memory BytesIO
FastAPI → returns bytes → image/png or image/svg+xml
Zero disk writes. Zero temp files. All QR generation is in-memory.
All mode payloads (vCard, WiFi, VEVENT, mailto:, smsto:, tel:, geo:) are built client-side in JavaScript. The /qr endpoint is format-agnostic — it encodes whatever string you pass.
8002
Edit ports in docker-compose.yml and the --port flag in Dockerfile CMD, then rebuild.
QRFORGE_ENV → "production" (set in docker-compose.yml)
docker compose up --build --detachExpose port 8002 via your firewall / reverse proxy.
Proxy localhost:8002 — the app is stateless and needs no sticky sessions.
Build → Push to registry → Deploy → Map port 8002 → Done
Stateless — horizontally scalable with no shared state.
docker compose logs -f qrforge
docker logs qrforgedocker compose logs qrforgedocker compose psIncrease error correction: use ec=Q or ec=H. Ensure sufficient contrast between module and background colors.
Increase scale: scale=12 or higher. For large-format print, use fmt=svg — infinitely scalable.
Ensure dark and light colors have sufficient contrast. Black on white (#000000 / #ffffff) is the most universally scannable combination.
The bind mount means you can edit files and see changes instantly:
# Start once
docker compose up --build --detach
# Edit app/main.py or app/templates/index.html
# Changes are live immediately — no restart needed
# View logs
docker compose logs -f qrforgeFeature branches:
git checkout -b feature/your-featureRebuild only when dependencies change:
docker compose up --build --detach- 🔒 Optional password protection / API key auth
- 📈 Health endpoint (
/health) - 📜 Session QR history
- 🖨️ Batch generation (CSV → multiple QR codes)
- 🖼️ Logo overlay (segno plugin support)
- 🌐 Docker Hub automated builds
This work is licensed under the GNU General Public License version 3. See LICENSE.
Software is provided AS-IS. Production security posture is your responsibility.
qr, qr code, qr-code, qr-generator, qr code generator, self-hosted qr, vcard qr, contact qr, mecard qr, wifi qr, wifi-qr, wifi password qr, wpa qr, email qr, sms qr, phone qr, geo qr, location qr, calendar qr, vevent qr, svg qr code, custom color qr, branded qr code, error correction qr, fastapi qr, docker qr, debian qr, segno, python qr generator, local-first qr service, web qr generator, self-hosted qr code generator
