lordofsunshine / monoforge
monoforge
PublicMonoForge helps you publish repositories, upload folders, read README files, discuss tasks and find public projects without a noisy interface.
README
MonoForge
Minimal monochrome GitHub-like forge for repositories, files, README covers, issues, stars, activity and storage discipline.
MonoForge is built for small servers. It stores file metadata in PostgreSQL, stores file bytes on disk under /storage, deduplicates blobs by SHA-256, compresses text with zstd, and creates optimized image previews with sharp.
Features
- Auth.js email/password login and registration.
- User profiles and profile settings.
- Public/private repositories.
- File upload, delete, file tree and raw/download streaming.
RepositoryFilemetadata plus deduplicatedFileBlobstorage.- SHA-256 hash-based storage:
/storage/blobs/aa/bb/<sha256>.zst. - zstd compression for text-like files.
- sharp-powered image preview and thumbnail variants.
- README preview as a project cover.
- Markdown rendering with GFM and XSS-safe defaults.
- Code viewer with syntax highlighting, metadata, raw/download/copy actions.
- Issues, comments, labels, board and maintainer notes.
- Stars with optimistic UI and strict monochrome counters.
- Activity feed and activity pulse.
- Storage quota, storage savings and repo health metrics.
- Global search and terminal-style command palette.
- Light/dark theme and focus-mode hooks.
- Docker Compose deployment for a small VPS.
Tech Stack
- Next.js App Router
- React
- TypeScript strict
- Tailwind CSS v4
- PostgreSQL
- Prisma ORM
- Auth.js / NextAuth
- zod
- zstd CLI
- sharp
- Docker Compose
Copy .env.example to .env and change secrets.
DATABASE_URL="postgresql://monoforge:monoforge@localhost:5432/monoforge?schema=public"
AUTH_SECRET="replace-with-a-strong-random-secret-at-least-32-chars"
NEXTAUTH_URL="http://localhost:3000"
STORAGE_PATH="./storage"
MAX_UPLOAD_SIZE_MB="10"
MAX_REPO_SIZE_MB="200"
MAX_USER_STORAGE_MB="1024"
MAX_FILES_PER_REPO="1000"
MAX_CONCURRENT_UPLOADS="2"
ZSTD_LEVEL="3"
IMAGE_MAX_WIDTH="1600"
IMAGE_QUALITY="82"
Local Development
npm install
npm run prisma:generate
npm run prisma:migrate
npm run prisma:seed
npm run dev
Open http://localhost:3000.
Docker Development
docker compose up -d --build
docker compose logs -f
docker compose exec app npm run prisma:migrate
docker compose exec app npm run prisma:seed
Production Deployment
- Create
.envfrom.env.example. - Set a strong
AUTH_SECRET. - Point DNS/SSL reverse proxy to the app.
- Run:
docker compose up -d --build
docker compose exec app npm run prisma:migrate
deploy/Caddyfile contains a small reverse-proxy example with upload size, compression and security headers.
Database Migrations
npm run prisma:generate
npm run prisma:migrate
For local schema iteration:
npm run db:migrate
Backup And Restore
Database backup:
scripts/backup-db.sh
Storage backup:
tar -czf backups/monoforge-storage-$(date +%Y%m%d-%H%M%S).tar.gz storage
Restore database:
scripts/restore-db.sh backups/monoforge-db.sql
Restore storage:
tar -xzf backups/monoforge-storage.tar.gz
Back up PostgreSQL and storage close together so database metadata matches blobs.
Cleanup
npm run cleanup:tmp
npm run cleanup:orphan-blobs
npm run storage:stats
Docker:
docker compose exec app npm run cleanup:tmp
docker compose exec app npm run cleanup:orphan-blobs
docker compose exec app npm run storage:stats
GitHub Mirror Crawler
A temporary, admin-toggleable worker that scans newly created public GitHub repositories, keeps only those under a permissive license, and mirrors each one into MonoForge: it creates a non-login bot account named after the GitHub owner, creates a repository named after the GitHub repository, and imports all files. A separate ledger (MirroredRepository) records every processed GitHub repository id so nothing is imported twice.
Run the worker:
npm run mirror:worker
Docker:
docker compose exec app npm run mirror:worker
Control:
- Enable or disable it from the admin page (
/admin). The worker polls the flag each cycle, so it pauses and resumes without a restart. It starts disabled. - Without
GITHUB_TOKENthe GitHub API allows ~60 requests/hour, so throughput is roughly 50 repositories/hour. SetGITHUB_TOKENto raise the limit to 5000 requests/hour. - Allowed licenses are defined in
server/mirror/licenses.ts. Copyleft licenses are skipped by default. - Mirror accounts have no password and cannot sign in. Each mirrored repository keeps its
LICENSEfile and stores the original GitHub URL as attribution.
Relevant environment variables: GITHUB_TOKEN, GITHUB_API_USER_AGENT, MIRROR_INTERVAL_MS, MIRROR_BATCH_SIZE, MIRROR_MAX_REPO_MB, MIRROR_MAX_FILE_MB, MIRROR_MIN_RATE_BUDGET.
Roadmap
- Real Git push/pull via system
git/simple-git. - Bare repositories in
/storage/git/<owner>/<repo>.git. - Branches, commit browser and diff viewer.
- Pull requests.
- SSH keys and deploy tokens.
- Collaborators and organization-like spaces.
- CI/CD hooks.
Troubleshooting
- If zstd compression fails, install the
zstdbinary on the host or use Docker. - If image previews fail, check sharp native dependencies and storage permissions.
- If Prisma cannot connect, verify
DATABASE_URLand Postgres health. - If raw/download returns 404, check repository visibility and
RepositoryFile.blobId. - If storage looks inconsistent, run
npm run storage:statsandnpm run cleanup:orphan-blobs.