Create, save, and organize sale ads with multiple images, then copy content wherever you need.
2.6K
MarketBridge is a self-hosted web app (Next.js) to prepare sale listings once, store them locally with multiple images, and quickly reuse them across marketplaces.
The app is designed for personal use or small teams on private infrastructure.
better-sqlite3jszipDefault persistent paths:
data/marketbridge.dbdata/uploads/In the provided Docker setup, all data/ content is mounted to the Docker named volume marketbridge_data (container path: /app/data).
20.xnpm install
npm run dev
Open: http://localhost:3000
Available scripts:
npm run dev: development servernpm run build: production buildnpm run start: run production buildnpm run lint: ESLint checksnpm run typecheck: TypeScript checksdocker compose up --build
Open: http://localhost:3001
Ready-to-use images are also available:
ghcr.io/gioxx/marketbridge:latestgfsolone/marketbridge:latestdocker run (GHCR)docker run -d \
--name marketbridge \
-p 3001:3000 \
-e NODE_ENV=production \
-e NEXT_TELEMETRY_DISABLED=1 \
-e SQLITE_PATH=/app/data/marketbridge.db \
-v marketbridge_data:/app/data \
--restart unless-stopped \
ghcr.io/gioxx/marketbridge:latest
docker run (Docker Hub)docker run -d \
--name marketbridge \
-p 3001:3000 \
-e NODE_ENV=production \
-e NEXT_TELEMETRY_DISABLED=1 \
-e SQLITE_PATH=/app/data/marketbridge.db \
-v marketbridge_data:/app/data \
--restart unless-stopped \
gfsolone/marketbridge:latest
docker compose (use pre-built image)services:
marketbridge:
container_name: marketbridge
image: ghcr.io/gioxx/marketbridge:latest
environment:
NODE_ENV: production
NEXT_TELEMETRY_DISABLED: "1"
PORT: "3000"
SQLITE_PATH: /app/data/marketbridge.db
# Optional dangerous action:
# MARKETBRIDGE_ENABLE_PURGE_ALL: "1"
ports:
- "3001:3000"
volumes:
- data:/app/data
restart: unless-stopped
volumes:
data:
name: marketbridge_data
You can switch to Docker Hub by replacing:
image: ghcr.io/gioxx/marketbridge:latest
with:image: gfsolone/marketbridge:latestSupported variables:
| Variable | Default | Description |
|---|---|---|
NODE_ENV | production (in Docker) | Node runtime mode |
NEXT_TELEMETRY_DISABLED | 1 | Disable Next.js telemetry |
PORT | 3000 | Internal app port |
SQLITE_PATH | ./data/marketbridge.db | SQLite database path |
MARKETBRIDGE_ENABLE_PURGE_ALL | unset | If declared, enables UI button and API for full purge |
About MARKETBRIDGE_ENABLE_PURGE_ALL: any declared value enables it. If unset, full purge is disabled and API returns 403.
These routes are used by the UI and do not include built-in authentication.
GET /api/listings: list listingsPOST /api/listings: create listing (multipart/form-data)PUT /api/listings/:id: update listingDELETE /api/listings/:id: delete listing and linked imagesGET /api/uploads/:name: serve stored imageGET /api/backup/export: export ZIP backupPOST /api/backup/import?mode=replace|merge: import ZIP backupGET /api/maintenance/purge: full purge feature statusDELETE /api/maintenance/purge: full purge (only if enabled)Backup structure:
manifest.jsonlistings.jsonimages/ folder with all linked imagesKey constraints:
50 MBreplace mode: fully replaces current datamerge mode: merges backup data into current dataOperational recommendation:
MarketBridge does not include built-in authentication, authorization, or user roles.
If you expose the app publicly without protection, anyone can:
For production, run MarketBridge behind:
Example Caddyfile:
marketbridge.example.com {
encode zstd gzip
basic_auth {
admin $2a$14$REPLACE_WITH_BCRYPT_HASH
}
reverse_proxy 127.0.0.1:3001
}
Generate bcrypt hash with Caddy:
caddy hash-password --plaintext 'STRONG_PASSWORD'
Example server block:
server {
listen 443 ssl http2;
server_name marketbridge.example.com;
ssl_certificate /etc/letsencrypt/live/marketbridge.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/marketbridge.example.com/privkey.pem;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Create .htpasswd (example):
htpasswd -c /etc/nginx/.htpasswd admin
3001 directly to the public InternetMARKETBRIDGE_ENABLE_PURGE_ALL only when truly neededIf you declare this in docker-compose.yml:
environment:
MARKETBRIDGE_ENABLE_PURGE_ALL: "1"
the UI shows a dangerous action button that removes:
data/uploads/Use only in controlled environments.
src/app/page.tsx: main UIsrc/app/api/listings/route.ts: listing list + createsrc/app/api/listings/[id]/route.ts: listing update + deletesrc/app/api/uploads/[name]/route.ts: image servingsrc/app/api/backup/export/route.ts: backup exportsrc/app/api/backup/import/route.ts: backup importsrc/app/api/maintenance/purge/route.ts: feature flag + full purgesrc/lib/db.ts: SQLite accesssrc/lib/uploads.ts: image file managementdocker-compose.yml: container deployment + persistent volumepublic/manifest.webmanifestpublic/sw.jsFor reliable install behavior on mobile, HTTPS is required.
See LICENSE.
Content type
Image
Digest
sha256:e54ced0bb…
Size
164.3 MB
Last updated
6 months ago
docker pull gfsolone/marketbridge