No description
  • Go 62.9%
  • TypeScript 35.7%
  • CSS 0.7%
  • Dockerfile 0.3%
  • Shell 0.3%
Find a file
2026-06-04 14:19:10 +02:00
cmd/server Rewrite structured logging system 2026-06-04 14:19:10 +02:00
docker initial commit 2026-04-30 13:14:25 +02:00
internal Rewrite structured logging system 2026-06-04 14:19:10 +02:00
webapp Rewrite structured logging system 2026-06-04 14:19:10 +02:00
.gitignore initial commit 2026-04-30 13:14:25 +02:00
docker-compose.yml initial commit 2026-04-30 13:14:25 +02:00
README.md add README.md 2026-04-30 13:28:38 +02:00

GPB

GPB is a self-hosted Google Photos Backup control plane.

It provides a web dashboard for managing users, paired Android nodes, file activity, backup settings, logs, and runtime controls. Files can be ingested through Telegram, WebDAV, or SFTP, then queued for deduplication, node sync, verification, and cleanup.

Features

  • React + Vite web control panel
  • Go backend with Gin
  • SQLite database stored in data/gpb/gpb.db
  • File uploads stored in data/uploads
  • Web dashboard authentication with session cookies
  • Admin and user management
  • Node pairing through QR/token flow
  • File activity dashboard with status filters
  • Retry failed uploads and jobs
  • WebDAV ingestion endpoint
  • SFTP ingestion endpoint
  • Optional Telegram bot ingestion
  • Optional local telegram-bot-api runtime
  • Server-Sent Events for live UI updates
  • Health and readiness endpoints
  • Docker Compose deployment with Traefik labels

Tech Stack

Backend

  • Go
  • Gin
  • GORM
  • SQLite
  • WebDAV
  • SFTP server
  • Telegram Bot API integration

Frontend

  • React 18
  • TypeScript
  • Vite
  • Tailwind CSS
  • TanStack Query
  • React Router
  • Framer Motion
  • Lucide Icons
  • React QR Code

Repository Structure

.
├── cmd/
│   └── server/              # Backend entrypoint
├── docker/
│   ├── Dockerfile           # Multi-stage frontend/backend/runtime image
│   ├── example.env          # Example environment file
│   └── start.sh             # Container startup script
├── internal/
│   ├── adapters/            # DB, HTTP v3, WebDAV, SFTP, event bus adapters
│   ├── core/                # Domain models and ports
│   ├── service/             # Ingest, node, sync services
│   └── web/                 # Web handlers, middleware, React serving
├── webapp/                  # React control panel
├── data/                    # Runtime data, ignored by git
├── docker-compose.yml
└── README.md

Deployment

1. Clone the repository

git clone <your-repo-url>
cd <repo-name>

2. Create the environment file

cp docker/example.env docker/.env

Edit docker/.env:

TELEGRAM_API_ID=
TELEGRAM_API_HASH=
ADMIN_USERNAME=admin
ADMIN_PASSWORD=change-this-password
ADMIN_TELEGRAM_USER_ID=
SESSION_SECRET=change-this-to-a-long-random-secret
TELEGRAM_BOT_TOKEN=
DOMAIN_NAME=gpb.example.com
FORCE_SECURE_COOKIES=true

Generate a strong session secret:

openssl rand -hex 32

3. Create the external Traefik network

The compose file expects an existing Docker network named traefik_network.

docker network create traefik_network

Skip this command if the network already exists.

4. Update domains

By default, the compose file uses:

gpb.dtecx.dev
dav.dtecx.dev

Change these Traefik labels in docker-compose.yml to your own domains:

- "traefik.http.routers.gpb-ui.rule=Host(`gpb.example.com`)"
- "traefik.http.routers.gpb-webdav.rule=Host(`dav.example.com`)"

Also update:

DOMAIN_NAME=gpb.example.com

5. Start the stack

docker compose up -d --build

6. Check logs

docker logs -f gpb-backend

7. Check health

From inside the server:

curl http://127.0.0.1/readyz

Expected response:

{"ok":true}

Services and Ports

Service Internal Port External Exposure Purpose
Web UI / API 80 Traefik React app and backend API
WebDAV 8080 Traefik WebDAV file ingestion
SFTP 2222 Host port 2222 SFTP file ingestion
Local Telegram Bot API 8089 Internal only Optional local Telegram API runtime

Runtime Data

Runtime data is stored in:

data/
├── gpb/
│   └── gpb.db
├── uploads/
├── sftp/
│   └── host_rsa
└── telegram-bot-api/

The data/ directory is ignored by git and mounted into the container as:

./data:/app/data

Environment Variables

Variable Required Description
ADMIN_USERNAME Recommended Bootstrap admin username
ADMIN_PASSWORD Recommended Bootstrap admin password
ADMIN_TELEGRAM_USER_ID Optional Telegram ID for the admin user
SESSION_SECRET Yes Secret used for session cookie signing
DOMAIN_NAME Recommended Public web domain, used for secure cookie behavior
FORCE_SECURE_COOKIES Recommended Set to true for HTTPS deployments
TELEGRAM_BOT_TOKEN Optional Enables Telegram bot ingestion
TELEGRAM_API_ID Optional Enables local telegram-bot-api mode
TELEGRAM_API_HASH Optional Enables local telegram-bot-api mode

If TELEGRAM_API_ID and TELEGRAM_API_HASH are not set, the bot uses the public Telegram Bot API.

Web UI

Open:

https://gpb.example.com

The UI includes:

  • Dashboard
  • File activity
  • Node/fleet overview
  • Settings
  • Admin user management
  • Logs
  • Pairing QR code generation
  • Runtime controls

The app loads a custom logo from:

/gpb-logo.png

Place your logo in the frontend public assets so it is included in the final Vite build.

API Overview

Health

GET /healthz
GET /readyz

Web API

POST /api/web/auth/login
GET  /api/web/auth/me
POST /api/web/auth/logout

GET  /api/web/dashboard
GET  /api/web/files
GET  /api/web/files/stats
POST /api/web/files/retry-failed

GET  /api/web/nodes
GET  /api/web/events
GET  /api/web/settings
PUT  /api/web/settings/profile
PUT  /api/web/settings/account
GET  /api/web/settings/accounts
GET  /api/web/node/pairing-qr

Admin API

GET    /api/web/admin/users
POST   /api/web/admin/users
GET    /api/web/admin/logs
PUT    /api/web/admin/node-policy
PUT    /api/web/admin/server-policy
POST   /api/web/admin/toggle-servers
POST   /api/web/admin/toggle-node-service
POST   /api/web/admin/clear-db
POST   /api/web/admin/clear-failed
POST   /api/web/admin/nuke-runtime
DELETE /api/web/admin/nodes/:id

Node API v3

POST /api/v3/node/pair
POST /api/v3/node/unpair
POST /api/v3/node/sync
GET  /api/v3/files/:id/content

WebDAV

WebDAV is exposed through the separate WebDAV server port.

With the default compose labels:

https://dav.example.com

Authentication uses GPB user credentials.

SFTP

SFTP is exposed directly on port 2222.

Example:

sftp -P 2222 username@your-server-ip

Authentication uses GPB user credentials.

Uploaded files are ingested into the GPB pipeline and associated with the authenticated user.

Frontend Development

Install dependencies:

cd webapp
npm install

Start Vite:

npm run dev

Build frontend:

npm run build

The frontend expects the backend API to be available on the same origin in production. For local frontend-only development, run the backend separately or add a Vite proxy if needed.

Docker Build

The production image is built in three stages:

  1. Node builder builds the React/Vite frontend.
  2. Go builder compiles the backend server.
  3. Runtime image includes:
    • gpb-server
    • built frontend assets
    • startup script
    • optional telegram-bot-api binary

Manual build:

docker compose build

Run:

docker compose up -d

Security Notes

Change these before exposing the service publicly:

ADMIN_PASSWORD=
SESSION_SECRET=
DOMAIN_NAME=
FORCE_SECURE_COOKIES=true

Do not use the default bootstrap password in production.

The app sets secure session cookie behavior when FORCE_SECURE_COOKIES=true or when DOMAIN_NAME is a non-localhost domain.

Backup

Back up the data/ directory:

tar -czf gpb-backup.tar.gz data/

Restore by placing the directory back before starting the container:

tar -xzf gpb-backup.tar.gz
docker compose up -d

Useful Commands

Start:

docker compose up -d

Rebuild:

docker compose up -d --build

Stop:

docker compose down

View logs:

docker logs -f gpb-backend

Shell into container:

docker exec -it gpb-backend sh

Check database files:

ls -lah data/gpb

Check uploads:

ls -lah data/uploads

Git Ignore Notes

The repository ignores:

data/
.env
.env.*
getcode.py
*.txt

This keeps runtime data, secrets, and temporary code-dump files out of git.