Troubleshooting¶
Common issues and how to resolve them. Check the backend logs first:
Startup issues¶
Backend fails to start — JWT_SECRET_KEY missing¶
Symptom: Container exits immediately with:
Cause: The JWT_SECRET_KEY variable is empty or missing from backend.env.
Fix:
# Generate a strong key
openssl rand -hex 32
# Add to backend.env:
JWT_SECRET_KEY=<generated-value>
docker compose up -d backend-api
ClamAV takes 60+ seconds to start¶
Symptom: The health endpoint returns "clamav": {"ok": false} for up to
2 minutes after startup.
Cause: ClamAV loads ~800 MB of signatures into memory on first start. This is normal behavior.
Fix: Wait. Subsequent starts are faster because the database is cached in
the repos/clamav-db/ volume. If the problem persists after 5 minutes, check:
Database error: attempt to write a readonly database¶
Symptom:
Cause: A file in repos/auth/ or repos/package-index/ is owned by root
instead of appuser (UID 1000). This typically happens after running docker exec
commands as root that create files.
Fix:
# Fix auth database
docker exec -u root backend-api chown appuser:appuser /repos/auth/users.db
# Fix package index database (RPM edition)
docker exec -u root backend-api chown appuser:appuser /repos/package-index/packages.db
# Permanent fix: restart (entrypoint.sh re-applies ownership on each start)
docker compose restart backend-api
Upload failures¶
"Erreur serveur" on package upload¶
Symptom: The web interface shows "Erreur serveur" after selecting a file.
Cause: Nginx's client_max_body_size is set below the file size. The default
in some configurations is 1 MB, which blocks any real package upload.
Diagnosis:
docker compose logs frontend-ui | grep 413
# Or check in the browser Network tab — look for HTTP 413 on the upload request
Fix: The nginx.conf in frontend/nginx.conf should contain:
Upload rejected — "Erreur réseau: NetworkError"¶
Symptom: Upload fails with a network error, before the server even receives the file.
Cause (most common): The frontend was built with REACT_APP_API_URL=http://localhost:8000,
causing the browser to try to reach localhost:8000 on the client machine rather
than the server.
Diagnosis:
Fix: Set the correct URL in .env and rebuild:
# .env
REACT_APP_API_URL=http://192.168.1.100:8000 # or your server's actual address
docker compose build frontend-ui
docker compose up -d frontend-ui
Package stuck in pending_review¶
Symptom: A package was uploaded successfully but does not appear in the APT/RPM
repository. The web interface shows Status: pending_review.
Cause: The CVE scan found vulnerabilities matching the configured review policy.
The package is stored but not published until approved.
Fix: 1. Open Security → Review queue in the web interface 2. Review the CVE findings for the package 3. Click Approve to publish, or Reject to remove from the queue
Alternatively via API:
curl -X POST http://localhost:8000/api/v1/security/packages/mypackage/1.0.0/decide \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"decision":"approve","justification":"Vulnerability does not apply to our use case"}'
APT client issues¶
apt update fails — NO_PUBKEY¶
Symptom:
W: GPG error: http://repod.example.com:80 jammy InRelease: The following signatures
couldn't be verified because the public key is not available: NO_PUBKEY ABCD1234...
Cause: The repository's GPG public key is not trusted by the client machine.
Fix:
# Re-import the key from the repository
curl -fsSL http://repod.example.com:80/repos/dists/jammy/InRelease \
| gpg --dearmor \
| sudo tee /etc/apt/trusted.gpg.d/repod.gpg > /dev/null
sudo apt update
apt update fails — 404 Not Found¶
Symptom:
Cause: The distribution was not initialized, or the distribution name in
sources.list does not match a supported codename.
Fix:
# Re-initialize distributions
curl -X POST http://localhost:8000/api/v1/distributions/init \
-H "Authorization: Bearer $TOKEN"
# Verify the distribution exists
ls /repos/dists/
RPM client issues¶
dnf install fails — GPG key retrieval failed¶
Symptom:
warning: /var/cache/dnf/repod/packages/mypackage-1.0.0.rpm: Header V4 RSA/SHA256
Signature, key ID ABCD1234: NOKEY
Cause: The GPG key was not imported before enabling gpgcheck=1.
Fix:
createrepo_c errors in backend logs¶
Symptom:
Cause: The RPM distribution directory does not exist or has wrong permissions.
Fix:
# Re-initialize RPM distributions
curl -X POST http://localhost:8000/api/v1/distributions/init \
-H "Authorization: Bearer $TOKEN"
# Check permissions
docker exec backend-api ls -la /repos/almalinux9/
Sync / import issues¶
"Erreur inconnue" during sync (ImportPage)¶
Symptom: The sync stream shows "Erreur inconnue" immediately when started.
Cause (common): The frontend was built with an older bundle that used incorrect
API URLs (missing /api/v1 prefix). The browser is cached on the old build.
Fix: Hard-refresh the browser (Ctrl+Shift+R / Cmd+Shift+R). If the problem
persists, clear the browser cache or rebuild the frontend:
Index sync returns 0 packages¶
Symptom: The sync completes without errors but no packages appear in the catalog.
Cause (APT): The external source's Release file cannot be fetched (network
restriction, wrong URL, or missing GPG key for the source).
Cause (RPM): The source's repodata/repomd.xml is unreachable, or the SQLite
package index database is locked/corrupted.
Diagnosis:
Fix (SQLite lock):
docker exec -u root backend-api chown appuser:appuser /repos/package-index/packages.db
docker compose restart backend-api
Authentication issues¶
Login fails with valid credentials¶
Symptom: The login page returns "Identifiants incorrects" despite using the correct username and password.
Possible causes:
1. The ADMIN_PASSWORD_HASH in backend.env contains unescaped $ signs
2. The users.db was not created (volume permission issue)
3. The account is disabled (is_active: false)
Diagnosis:
# Check if users.db exists and has content
docker exec backend-api python3 -c "
import sqlite3
conn = sqlite3.connect('/repos/auth/users.db')
print(conn.execute('SELECT username, is_active FROM users').fetchall())
"
Fix for hash escaping:
# In backend.env: replace every $ with $$
# Wrong: ADMIN_PASSWORD_HASH=$2b$12$...
# Correct: ADMIN_PASSWORD_HASH=$$2b$$12$$...
MFA code rejected¶
Symptom: The TOTP code entered during MFA authentication is rejected despite being generated by the correct authenticator app.
Cause: The server's system clock differs from the client's by more than 30 seconds. TOTP codes are time-based and fail if clocks are not synchronized.
Fix:
# Check server time
docker exec backend-api date
# Sync the host clock (if using NTP)
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd
Performance issues¶
Backend is slow or unresponsive¶
Symptom: API requests take more than 10 seconds, or the health endpoint times out.
Cause (most common): ClamAV or Grype is performing a database update. This is CPU-intensive and can saturate the container's CPU allocation.
Diagnosis:
Fix: The default resource limits in docker-compose.yaml are 1.5 CPUs and 2.5 GB RAM.
Increase if your hardware allows:
Viewing logs¶
# All containers
docker compose logs -f
# Backend only, last 200 lines
docker compose logs backend-api --tail=200
# Filter for errors
docker compose logs backend-api 2>&1 | grep -i "error\|exception\|traceback"
# Audit log (last 50 entries)
docker exec backend-api tail -n 50 /repos/audit/$(date +%Y-%m-%d).jsonl | python3 -m json.tool