Add workflow_dispatch to backfill releases for existing tags.
PicHost
Lightweight personal image hosting · Simple uploads, clean management
Self-hosted / Multi-user / Docker / API / Twikoo · Zero-config setup
Quick Start · Screenshots · Features · Tech Stack · Roadmap · 简体中文
Screenshots
| Login | Upload |
|---|---|
![]() |
![]() |
| Upload preferences | Stats & gallery |
|---|---|
![]() |
![]() |
| Settings | |
|---|---|
![]() |
Features
- Drag, click, or Ctrl+V paste to upload; admins can use custom
folderpaths - Server-side WebP (sharp), Referer hotlink protection, configurable public base URL
- Multi-user — username/password login; optional registration; users see only their images
- Upload preferences (card flip UI): client-side compression, auto-copy links, per-user auto-delete
- Gallery — browse, search, batch delete; admin sees uploader badges
- Stats — upload/delete metrics, folder breakdown; admin sees registered user count
- API — global token (admin) + per-user tokens; in-app cURL snippets
- Twikoo —
POST /api/index.php(image+token) - Zero-config Docker — first-run web wizard, no secrets required upfront
Quick Start
Docker (recommended)
docker run -d \
--name pichost \
-p 6892:6892 \
-v ./data:/data \
--restart unless-stopped \
muxui/pichost:latest
Default port: 6892. Open http://<host>:6892 in your browser and complete the setup wizard.
If you cloned the repo, you can also use docker compose up -d (see docker-compose.yml).
Local development
npm install
cp .env.example .env # optional
npm run dev
Open http://localhost:3000/setup to create the admin account. Data defaults to ./data.
Legacy migration
If you only had ADMIN_SECRET and no user table, log in with the secret once and follow the migration wizard.
Tech Stack
| Layer | Technology |
|---|---|
| Frontend | Nuxt 4, Vue 3, Nuxt UI 4, Tailwind CSS 4 |
| Backend | Nitro (Node.js), SQLite |
| Images | sharp (WebP transcoding & compression) |
| Auth | Session cookie, scrypt password hashing, API tokens |
| Storage | Local disk (DATA_DIR) |
| Deploy | Docker (amd64 / arm64), docker compose |
| Tests | Vitest |
Environment variables
| Variable | Description |
|---|---|
API_UPLOAD_TOKEN |
Global upload token (Auth-Token header); can be generated in the API page |
ALLOWED_REFERER_HOSTS |
Hotlink allowlist (comma-separated hostnames) |
IMAGE_BASE_URL |
Public base URL for image links |
WEBP_QUALITY |
Server WebP quality 1–100, default 80 |
AUTO_DELETE_DAYS |
Global auto-delete days (0 = off); admin + orphan images only |
DATA_DIR |
Data directory, default /data (container) or ./data (local) |
ADMIN_SECRET |
Legacy v1.0 migration only |
DEV_BYPASS_ACCESS |
Dev only — bypass auth (never in production) |
Environment variables override database settings. See .env.example.
Users & permissions
| Scenario | Auth | Ownership / visibility |
|---|---|---|
| Web upload | Session | Current user |
| API upload + user token | Auth-Token |
Token owner |
| API upload + global token | Auth-Token |
Admin (userId null) |
Twikoo /api/index.php |
form token |
Same as global token |
| Gallery list / search / delete | Session or token | Users: own only; admin: all |
Direct link GET /images/... |
None (Referer rules) | Public if URL is known |
Regular users are limited to the images/ folder; custom folder requires admin or global token.
Storage layout
/data
├── pichost.db # SQLite: users, sessions, settings, logs
├── images/ # Default upload folder
├── blog/ # Example custom folder
└── twikoo/ # Twikoo comment images
Pattern: folder/YYYY/MM/randomId.webp + .meta.json. Back up the entire /data directory.
API overview
| Method | Path | Description |
|---|---|---|
| POST | /api/images/upload |
Upload image |
| GET | /api/images |
Paginated list |
| DELETE | /api/images |
Delete one (key) |
| POST | /api/index.php |
Twikoo / EasyImage 2.0 |
Upload example:
curl -X POST "https://pic.example.com/api/images/upload" \
-H "Auth-Token: YOUR_TOKEN" \
-F "folder=blog" \
-F "image=@./demo.png"
Full docs and copyable cURL snippets are on the API page after deployment.
Twikoo
| Setting | Value |
|---|---|
IMAGE_CDN |
easyimage |
IMAGE_CDN_URL |
https://your-domain/api/index.php |
IMAGE_CDN_TOKEN |
Same as API_UPLOAD_TOKEN |
Reverse proxy
- Proxy to port 6892; HTTPS recommended
- Nginx:
client_max_body_size≥ 12m - Set
IMAGE_BASE_URLfor public access
Development
npm run dev # Dev server
npm run build # Production build
npm run start # Run .output
npm run lint # ESLint
npm run typecheck # Type check
npm test # Unit tests
Roadmap
| Version | Plan |
|---|---|
| v1.0.1 | Settings version display, mobile upload preferences layout fix (current) |
| v1.0.0 | Local storage, multi-user, API, Twikoo |
| v1.1.0 | S3, Cloudflare R2, and more object storage backends |





