Skip to content

getautoflow/Repod-community

Repository files navigation

Repod — Community Edition

Self-hosted APT repository manager with built-in antivirus scanning, GPG signing, and a full web UI.
Free forever. No cloud dependency. Deploy in 5 minutes.

License: MIT Docker Docs


Table of contents

  1. What's included
  2. Requirements
  3. Quick start
  4. Configuration
  5. Distributions (multi-codename)
  6. GPG signing
  7. Upload a package
  8. Configure APT clients
  9. Import from an external APT repo
  10. REST API reference
  11. Ports & networking
  12. Upgrade to Enterprise
  13. Troubleshooting
  14. Contributing
  15. License

What's included

Feature Community Enterprise
APT repository hosting (reprepro)
Web UI (React dashboard)
Package upload — REST API + drag & drop
Antivirus scan on every upload
GPG auto-signing
Multiple distributions (jammy / noble / focal / bookworm)
Local user management
Import from external APT mirror
Health & service monitoring
CVE analysis + CVSS scoring + CISO review queue 🔒
Immutable audit trail (JSON export) 🔒
RBAC — 5 roles + per-distribution scoping 🔒
LDAP / Active Directory integration 🔒
SBOM export (SPDX · CycloneDX) 🔒
Download analytics 🔒
Email & webhook notifications 🔒
NIS2 Article 21 compliance mode 🔒
Priority support & SLA 🔒

Requirements

Dependency Minimum version
Docker 24+
Docker Compose v2.20+ (plugin, not standalone)
RAM 1 GB free
Disk 2 GB free (+ package storage)
OS Linux x86-64 (amd64) or arm64

Note — Internet access is required on first start to download the ClamAV signature database (~300 MB).
After that, Repod works fully air-gapped.


Quick start

# 1. Clone
git clone https://github.com/getautoflow/repod-community.git
cd repod-community

# 2. Copy and edit the configuration files
cp .env.example .env
cp backend.env.example backend.env

# 3. Generate a JWT secret and set a strong admin password (see Configuration below)
#    At minimum, change JWT_SECRET_KEY in backend.env

# 4. Start
docker compose up -d

# 5. Wait ~30 seconds for the antivirus engine to initialise, then open:
#    http://localhost:3103   →  Web UI  (admin / changeme)
#    http://localhost:8100   →  REST API
#    http://localhost:8180   →  APT repo  (add to sources.list)

First login — default credentials are admin / changeme.
Change the password immediately in Settings → Security or via the API.


Configuration

.env — ports and URLs

# Ports exposed on the host
APT_PORT=8180        # APT repo (nginx)
BACKEND_PORT=8100    # FastAPI backend
FRONTEND_PORT=3103   # React web UI

# URL the frontend JavaScript will use to reach the API
REACT_APP_API_URL=http://localhost:8100

# URL used in APT sources.list instructions shown in the UI
REACT_APP_REPO_URL=http://localhost:8180

If you run multiple instances or already occupy port 80, change the ports here — no rebuild needed.

backend.env — secrets and auth

Variable Required Description
JWT_SECRET_KEY Random secret for JWT signing. Generate with python3 -c "import secrets; print(secrets.token_hex(32))"
JWT_EXPIRE_MINUTES Token lifetime in minutes (default: 60)
ADMIN_USERNAME Initial admin username (default: admin)
ADMIN_PASSWORD_HASH bcrypt hash of the admin password — escape every $ as $$
CORS_ORIGINS Comma-separated allowed origins for the API
AUTH_RATELIMIT_PER_MINUTE Login attempts per minute per IP (default: 10)

Generating a bcrypt hash

python3 -c "
from passlib.hash import bcrypt
import getpass
pw = getpass.getpass('Password: ')
h = bcrypt.hash(pw)
# Escape $ for Docker Compose env_file
print(h.replace('\$', '\$\$'))
"

Copy the output into ADMIN_PASSWORD_HASH= in backend.env.


Distributions

Repod supports four distributions out of the box:

Codename OS Notes
jammy Ubuntu 22.04 LTS
noble Ubuntu 24.04 LTS
focal Ubuntu 20.04 LTS
bookworm Debian 12 Initialized at first start

After the first docker compose up -d, the bookworm distribution is automatically initialized by the apt-repo container. To initialize the remaining distributions (jammy, noble, focal), click "Init distributions" in the web UI under Distributions, or call the API:

curl -s -X POST http://localhost:8100/distributions/init \
  -H "Authorization: Bearer $TOKEN"

This writes the reprepro configuration and runs reprepro export for all codenames.


GPG signing

Repod generates a GPG key pair on first start inside the apt-repo container. The public key is exported to:

http://localhost:8180/repos/depot.gpg

Configure clients to trust your key

# Download and add the key
curl -fsSL http://your-repod-host/repos/depot.gpg | sudo gpg --dearmor -o /usr/share/keyrings/repod.gpg

# Then reference it in your sources.list entry (see next section)

Rotate the GPG key

  1. Remove repos/.gnupg/ and repos/gnupg/ on the host.
  2. Restart the apt-repo container — a new key is generated automatically.
  3. Re-export the public key to all clients.

Upload a package

Via the web UI

Go to Importer in the sidebar → drag & drop your .deb file → select a target distribution → click Import.

Every uploaded file is automatically scanned by ClamAV before being added to the repository.

Via the REST API

# 1. Get a token
TOKEN=$(curl -s -X POST http://localhost:8100/auth/token \
  -H 'Content-Type: application/json' \
  -d '{"username":"admin","password":"changeme"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# 2. Upload a .deb (JSON response)
curl -s -X POST http://localhost:8100/upload/ \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@./mypackage_1.0_amd64.deb" \
  -F "distribution=jammy"

# 2b. Upload with live progress (SSE stream)
curl -s -X POST http://localhost:8100/upload/stream \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@./mypackage_1.0_amd64.deb" \
  -F "distribution=jammy"

Supported architectures

amd64, arm64, i386


Configure APT clients

# /etc/apt/sources.list.d/repod.list
deb [arch=amd64 signed-by=/usr/share/keyrings/repod.gpg] http://your-repod-host/repos jammy main

Replace jammy with your target distribution codename.

sudo apt update
sudo apt install your-package

Import from an external APT repo

Go to Importer → Import depuis un dépôt externe in the web UI, or use the API.

Search the index first

# Search available packages in indexed sources
curl -s "http://localhost:8100/import/search?q=nginx" \
  -H "Authorization: Bearer $TOKEN"

# Resolve dependencies for a package
curl -s "http://localhost:8100/import/resolve/curl" \
  -H "Authorization: Bearer $TOKEN"

Import a single package (SSE stream)

curl -s -X POST http://localhost:8100/import/fetch \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"package": "curl", "distribution": "jammy"}'

Batch import (up to 50 packages)

curl -s -X POST http://localhost:8100/import/batch \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"packages": ["curl", "wget", "jq"], "distribution": "jammy"}'

Both import endpoints return a Server-Sent Events stream with real-time progress. Imported packages pass through the same antivirus scan as uploaded packages before being added to the pool.


REST API reference

Interactive documentation is available at:

http://localhost:8100/docs      (Swagger UI — development mode only)
http://localhost:8100/redoc     (ReDoc)

Key endpoints

Method Path Description
POST /auth/token Login — returns JWT ({"username":…,"password":…})
GET /auth/me Current user info
GET /auth/users List users (admin only)
POST /auth/users Create user (admin only)
PATCH /auth/users/{username} Update user role (admin only)
DELETE /auth/users/{username} Delete user (admin only)
POST /auth/change-password Change own password
GET /packages/ List all packages
POST /upload/ Upload a .deb — JSON response
POST /upload/stream Upload a .deb — SSE live progress
DELETE /artifacts/{name} Remove a package (all versions, maintainer+)
DELETE /artifacts/{name}/{version} Remove a specific version (maintainer+)
GET /distributions/ List distributions + package counts
GET /distributions/{codename}/packages Packages in a distribution
POST /distributions/promote Promote package to another distribution
POST /distributions/init Initialize / re-initialize reprepro
GET /import/search?q= Search indexed package sources
GET /import/resolve/{name} Resolve dependencies online
POST /import/fetch Import a single package (SSE stream)
POST /import/batch Import up to 50 packages (SSE stream)
POST /import/sync Re-sync all package index sources
GET /import/sync-status Sync status of indexed sources
GET /dashboard/stats Dashboard stats
GET /dashboard/history Upload history (last N days)
GET /health Full health check (no auth)
GET /health/live Liveness probe (no auth)
GET /health/ready Readiness probe (no auth)
GET /security/clamav/status Antivirus engine status & DB version
POST /security/clamav/update Force antivirus DB update (admin only)

Endpoints that return HTTP 402 are Enterprise-only features.


Ports & networking

Service Container port Default host port Purpose
apt-repo (nginx) 80 8180 APT repository served to apt clients
backend-api (FastAPI) 8000 8100 REST API + business logic
frontend-ui (nginx/React) 80 3103 Web dashboard

All three containers communicate over the internal Docker bridge. Only the ports listed above are exposed to the host.

Running alongside an existing stack

Edit .env to use different ports:

APT_PORT=9180
BACKEND_PORT=9100
FRONTEND_PORT=3203
REACT_APP_API_URL=http://your-host:9100
REACT_APP_REPO_URL=http://your-host:9180

Upgrade to Enterprise

The Community Edition is designed to grow with you. When you need:

  • CVE analysis + CVSS scoring on every upload
  • CISO approval workflow before promotion to production
  • Immutable audit trail for NIS2 / ISO 27001
  • RBAC with per-distribution scoping
  • LDAP / Active Directory
  • SBOM export (SPDX · CycloneDX)
  • Email & webhook alerts
  • Priority support and SLA

👉 Request a demo
📧 contact@getautoflow.dev

Migration from Community to Enterprise is in-place — same Docker Compose stack, same data, same ports. No data migration needed.


Troubleshooting

ClamAV takes a long time to start

Normal on first boot — ClamAV downloads its signature database (~300 MB). Subsequent starts use the cached database in repos/clamav-db/.

docker logs backend-api --follow | grep -i clam

"Init distributions" returns an error

The backend-api container must be running with the repos/conf, repos/dists, and repos/db volumes. Check:

docker inspect backend-api | python3 -c "
import sys, json
mounts = json.load(sys.stdin)[0]['Mounts']
for m in mounts:
    print(m['Source'], '->', m['Destination'])
"

If the volumes are missing, re-create the container:

docker compose up -d backend

Permission denied on repos/ directories

The backend runs as appuser (UID 1000). If you pulled repos/ from a backup as root, fix permissions:

sudo chown -R 1000:1000 repos/conf repos/dists repos/db repos/pool repos/manifests

Login returns 401

If you changed ADMIN_PASSWORD_HASH in backend.env, the running container still has the old value. Restart:

docker compose up -d backend

If the hash uses bare $ instead of $$, Docker Compose will silently strip the value. Re-generate the hash and escape every $ as $$.

Package upload returns 500 / AV error

ClamAV daemon may not be ready yet. Check:

curl http://localhost:8100/security/clamav/status

If daemon_running is false, wait 30–60 seconds and retry.

APT clients get "NO_PUBKEY" error

The GPG public key is not trusted on the client. Run:

curl -fsSL http://your-repod-host/repos/depot.gpg | sudo gpg --dearmor -o /usr/share/keyrings/repod.gpg

Then make sure your sources.list entry includes signed-by=/usr/share/keyrings/repod.gpg.


Contributing

Issues and pull requests are welcome.

# Dev mode (hot-reload, backend code mounted as volume)
docker compose -f docker-compose.yaml -f docker-compose.dev.yml up

Please open an issue before submitting a large pull request.


License

Copyright © 2026 NGANDO ARMEL — Getautoflow.

Community Edition source code is released under the MIT License — see LICENSE.
Enterprise Edition source code is proprietary.


repod.getautoflow.dev · Documentation · Contact

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors