- Go 75.5%
- HTML 20.1%
- CSS 3.2%
- Dockerfile 0.7%
- Shell 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| locales | ||
| scrshots | ||
| static | ||
| templates | ||
| .dockerignore | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| accents.go | ||
| access.go | ||
| audit.go | ||
| auth.go | ||
| cleanup.go | ||
| config.go | ||
| csrf.go | ||
| cups.go | ||
| cupsd.conf | ||
| database.go | ||
| docker-compose.yml | ||
| Dockerfile | ||
| entrypoint.sh | ||
| go.mod | ||
| go.sum | ||
| handlers_admin.go | ||
| handlers_api.go | ||
| handlers_auth.go | ||
| handlers_notifications.go | ||
| handlers_oidc.go | ||
| handlers_print.go | ||
| handlers_printers.go | ||
| handlers_settings.go | ||
| i18n.go | ||
| LICENSE | ||
| main.go | ||
| middleware.go | ||
| models.go | ||
| notify.go | ||
| print_defaults.go | ||
| README.md | ||
| sanitize.go | ||
| screenshot-mobile-1.jpg | ||
| screenshot-mobile-2.jpg | ||
| screenshot-mobile-3.jpg | ||
| webprint | ||
WebPrint
Your printers. On the web.
Self-hosted print server webUI · AGPLv3 · Docker
🖨️ WebPrint
A lightweight, self-hosted printing server WebUI with multi-user support, built with Go + HTMX powered by CUPS. Designed to be simple to deploy, configure, and use.
✨ Features
- Multi-user support - registration with admin approval workflow
- Print options - copies, duplex, color mode, orientation
- Print history - track all printed documents
- Admin panel - approve/reject users, promote/demote admins
- Healthcheck - get your container's health
- API - call the app to get current stats
- OIDC - register and authenticate via OIDC providers
- Multi-language UI - English, French, German, Finnish
- Runtime configuration - change settings via environment variables, no rebuilds needed
- Tiny footprint - ~40MB Docker image (and ~300MB for CUPS)
- CUPS integration - leverages the proven CUPS printing system
- Secure - JWT auth with secure cookies, HTTPS-ready
🖼️ Screenshots
Login page on mobile:
Print page on desktop with the upload button and options:
The admin page:
The printers page:
The settings page:
🚀 Quick Start
🐳 Pre-built Docker Image
Multi-arch image (amd64, arm64v8) available from the self-hosted registry:
image: https://forged.hel.alfredolin.eu/webprint:latest
Just use the docker-compose.yml file, grab the cups config file, prepare your .env file and from the folder do:
docker compose up
Build
# Clone the repo
git clone https://forgejo.hel.alfredolin.eu/Alfredolin/WebPrint.git
cd WebPrint
# Build and run
docker compose up -d --build
# Access the UI
# http://localhost:3001
# Default login: admin / (set ADMIN_PASS in docker-compose.yml)
⚙️ Configuration
All configuration is done via environment variables in .env, most important variables are:
| Variable | Default | Description |
|---|---|---|
JWT_SECRET |
"" |
Secret for JWT token signing. Default is empty, WebPrint won't start if you don't change it. |
ADMIN_USER |
admin |
Default admin username |
ADMIN_PASS |
change-this-password |
Default admin password |
HOST_URL |
"" |
https:// enables secure cookies, a path suffix (e.g. /print) enables subpath deployment. |
OIDC_ISSUER |
"" |
Optional, your OIDC provider's URL. If empty, OIDC options will not be displayed. |
OIDC_CLIENT_ID |
"" |
Your OIDC client ID |
OIDC_CLIENT_SECRET |
"" |
Your OIDC client secret |
OIDC_NAME |
"SSO" |
An arbitrary name to your OIDC provider |
AUTOLOGIN_USER |
"" |
Automatically logs in to a pre-set user. User should be configured beforehand and not be an admin account. |
No rebuild needed — change any variable and just restart the container.
API use example
You can use the API for example to display the status on Homepage (with docker socket access) by adding this labels in the docker compose:
labels:
- homepage.group=YourGroup
- homepage.name=WebPrint
- homepage.icon=https://forgejo.hel.alfredolin.eu/Alfredolin/WebPrint/raw/branch/phase7-dev/static/logo-dark.svg
- homepage.href=YourHostUrl
- homepage.description=Web UI for printers
- homepage.widgets[0].type=customapi
- homepage.widgets[0].url=YourHostUrl/api/stats
- homepage.widgets[0].refreshInterval=10000 # optional - in milliseconds, defaults to 10s
- homepage.widgets[0].headers.Authorization=Bearer YourApiTokenGeneratedInTheSettingsPage
- homepage.widgets[0].method=GET # optional, e.g. POST
- homepage.widgets[0].mappings[0].field=pagesToday
- homepage.widgets[0].mappings[0].label=Printed 📄
- homepage.widgets[0].mappings[0].format=number
- homepage.widgets[0].mappings[1].field=pendingUsers
- homepage.widgets[0].mappings[1].label=Pending 🧑🏽
- homepage.widgets[0].mappings[1].format=number
- homepage.widgets[0].mappings[2].field=printers
- homepage.widgets[0].mappings[2].label=🖨️
- homepage.widgets[0].mappings[2].format=number
🖨️ Printer Setup
Make sure your printer is configured in CUPS. You can use the CUPS web interface at http://localhost:631 or the command line:
Adding a Network Printer
-
Find your printer's IP address (check your router's DHCP table or the printer's built-in menu)
-
Enter the CUPS container:
docker compose exec cups bash -
Remove existing printer (if reconfiguring):
lpadmin -x YourPrinterName 2>/dev/null || true -
Add the printer using one of these protocols:
IPP (recommended for modern printers):
lpadmin -p YourPrinterName -E -v "ipp://192.168.1.50/ipp/print" -m everywhereSocket / JetDirect (HP and others):
lpadmin -p YourPrinterName -E -v "socket://192.168.1.50:9100" -m everywhereLPD (older printers):
lpadmin -p YourPrinterName -E -v "lpd://192.168.1.50/queue" -m everywhereReplace
192.168.1.50with your printer's actual IP address. The-m everywhereflag tells CUPS to auto-detect capabilities via IPP. The-Eflag tells CUPS to enable the printer and accept jobs. -
Set as system default (optional):
lpoptions -d YourPrinterName -
Verify the printer is working:
lpstat -p YourPrinterName -d lpoptions -p YourPrinterName -l -
Sync from WebPrint:
Either automatically on container start or go to Admin → Printers and click "Sync with CUPS" to import the printer into WebPrint.
🔧 Using Host CUPS (Without the Containerized CUPS Service)
If you already have CUPS installed on your host system, you can skip the
containerized cups service and mount the host socket directly.
1. Check your socket permissions
ls -la /run/cups/cups.sock
If permissions are srw-rw-rw- (666) → no LP_GID needed
If permissions are srw-rw---- (660) → continue to step 2
2. Find your host's lp group GID
getent group lp
# lp:x:7:
3. Configure WebPrint
Set LP_GID in your .env to match the GID above, and remove the cups service from your docker-compose.yml:
LP_GID=7
📄 Supported File Types
PDF, PNG, JPEG, TIFF, BMP, TXT (or at least in the theory. It actually depends on CUPS and your printer, this is still being tested)
🌍 Reverse Proxy Setup
Set HOST_URL to the public URL users type in their browser:
| Deployment | HOST_URL | Apache |
|---|---|---|
| Subdomain | https://printer.site.eu |
ProxyPass / http://localhost:3001/ |
| Subpath | https://site.eu/print |
ProxyPass /print http://localhost:3001/print |
| Local/dev | http://10.0.0.7:3001 |
no proxy needed |
Apache example with subdomain:
<VirtualHost *:80 [::]:80>
ServerName printer.domain.com
RewriteEngine On
RewriteCond %{SERVER_NAME} =printer.domain.com
RewriteCond %{HTTP_HOST} =printer.domain.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
<VirtualHost *:443 [::]:443>
ServerName printer.domain.com
ProxyPreserveHost On
ProxyPass / http://localhost:3001/
ProxyPassReverse / http://localhost:3001/
#managed by e.g. certbot
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/printer.domain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/printer.domain.com/privkey.pem
</VirtualHost>
Nginx example with subpath (no trailing slash):
location /printer {
proxy_pass http://127.0.0.1:3311/printer;
}
Contact
Please open issues in Forgejo or come ask questions on matrix in the space: #webprint:matrix.alfredolin.eu.
🌐 Languages
English, Français, Deutsch, Suomi
Add a new language by creating locales/xx.json and adding the code to the supported list in i18n.go.
🙏 Credits
- Akronae/self-hosted-printing-server — Original project inspiration
- CUPS — The standards-based, open-source printing system
- Pico.css — Minimal CSS framework
- HTMX — High-power HTML interactivity
- Lumo — Proton's AI
📝 License
This project is licensed under the GNU Affero General Public License v3.0 (AGPLv3). See LICENSE file for details.




