|
2eca4eb…
|
ragelink
|
1 |
{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Fossilrepo","text":"<p>Self-hosted Fossil forge. One command, full-stack code hosting.</p> <p>Fossilrepo is an omnibus-style installer for a production Fossil SCM server. It packages Fossil, Caddy (SSL/routing), Litestream (S3 backups), and a Django management layer into a single deployable unit.</p> <p>Think GitLab Omnibus, but for Fossil.</p>"},{"location":"#why-fossil","title":"Why Fossil?","text":"<p>A Fossil repository is a single SQLite file containing the full VCS history, issue tracker, wiki, forum, and timeline. No external services. No rate limits. Portable -- hand the file to someone and they have everything.</p> <ul> <li>Single-file repos -- each <code>.fossil</code> file is the entire project</li> <li>Built-in everything -- issues, wiki, forum, timeline, web UI</li> <li>No API rate limits -- ideal for CI agents and automation</li> <li>Litestream replication -- continuous backup to S3 for free</li> </ul>"},{"location":"#what-you-get","title":"What You Get","text":"Component Role Fossil server Serves all repos from a single process Caddy SSL termination, subdomain-per-repo routing Litestream Continuous SQLite replication to S3/MinIO Django management UI Repository lifecycle, user management, dashboards Sync bridge Mirror Fossil repos to GitHub/GitLab (read-only) Celery workers Background sync, scheduled tasks"},{"location":"#quick-start","title":"Quick Start","text":"<pre><code># Clone the repo\ngit clone https://github.com/ConflictHQ/fossilrepo.git\ncd fossilrepo\n\n# Start the full stack\nmake build\n\n# Seed development data\nmake seed\n\n# Open the dashboard\nopen http://localhost:8000\n</code></pre>"},{"location":"#architecture","title":"Architecture","text":"<pre><code>Caddy (SSL termination, routing, subdomain per repo)\n +-- fossil server --repolist /data/repos/\n +-- /data/repos/\n |-- projecta.fossil\n |-- projectb.fossil\n +-- ...\n\nLitestream -> S3/MinIO (continuous replication, point-in-time recovery)\n</code></pre> <p>New project = <code>fossil init</code>. No restart, no config change. Litestream picks it up automatically.</p>"},{"location":"#license","title":"License","text":"<p>MIT License -- Copyright (c) 2026 CONFLICT LLC.</p>"},{"location":"architecture/overview/","title":"Architecture Overview","text":"<p>Fossilrepo is a thin orchestration layer around Fossil SCM. Fossil does the heavy lifting -- fossilrepo handles provisioning, routing, backups, and the management UI.</p>"},{"location":"architecture/overview/#system-diagram","title":"System Diagram","text":"<pre><code>graph TB\n subgraph Internet\n User[User / Browser]\n end\n\n subgraph Fossilrepo Server\n Caddy[Caddy<br/>SSL + Routing]\n Django[Django<br/>Management UI]\n Fossil[Fossil Server<br/>--repolist]\n Celery[Celery Workers]\n Redis[Redis]\n Postgres[(PostgreSQL)]\n Litestream[Litestream]\n end\n\n subgraph Storage\n Repos[\"/data/repos/<br/>*.fossil files\"]\n S3[(S3 / MinIO)]\n end\n\n subgraph Mirrors\n GitHub[GitHub]\n GitLab[GitLab]\n end\n\n User --> Caddy\n Caddy -->|\"app.domain.com\"| Django\n Caddy -->|\"repo.domain.com\"| Fossil\n Django --> Postgres\n Django --> Redis\n Celery --> Redis\n Celery -->|sync bridge| GitHub\n Celery -->|sync bridge| GitLab\n Fossil --> Repos\n Litestream --> Repos\n Litestream --> S3</code></pre>"},{"location":"architecture/overview/#components","title":"Components","text":""},{"location":"architecture/overview/#fossil-server","title":"Fossil Server","text":"<p>A single <code>fossil server --repolist /data/repos/</code> process serves all repositories. Each <code>.fossil</code> file is a self-contained SQLite database with VCS history, issues, wiki, and forum.</p> <p>Adding a new repo is just <code>fossil init /data/repos/name.fossil</code> -- no restart needed.</p>"},{"location":"architecture/overview/#caddy","title":"Caddy","text":"<p>Handles SSL termination and subdomain routing:</p> <ul> <li><code>your-domain.com</code> routes to the Django management UI</li> <li><code>reponame.your-domain.com</code> routes directly to Fossil's web UI</li> </ul> <p>Caddy automatically provisions and renews Let's Encrypt certificates.</p>"},{"location":"architecture/overview/#django-management-layer","title":"Django Management Layer","text":"<p>Provides the administrative interface:</p> <ul> <li>Repository lifecycle (create, configure, archive)</li> <li>User and organization management</li> <li>Dashboard and analytics</li> <li>Sync bridge configuration</li> </ul> <p>Django uses HTMX for interactive UI without a JavaScript framework.</p>"},{"location":"architecture/overview/#litestream","title":"Litestream","text":"<p>Continuously replicates every <code>.fossil</code> SQLite file to S3-compatible storage. Provides:</p> <ul> <li>Continuous backup -- WAL frames replicated in near-real-time</li> <li>Point-in-time recovery -- restore to any moment, not just snapshots</li> <li>Zero-config per repo -- new <code>.fossil</code> files are picked up automatically</li> </ul>"},{"location":"architecture/overview/#celery-workers","title":"Celery Workers","text":"<p>Handle background tasks:</p> <ul> <li>Sync bridge execution (Fossil to Git mirroring)</li> <li>Scheduled sync jobs</li> <li>Upstream pull operations</li> </ul>"},{"location":"architecture/overview/#data-flow","title":"Data Flow","text":"<ol> <li>User pushes to Fossil -- standard <code>fossil push</code> or <code>fossil sync</code></li> <li>Fossil writes to <code>.fossil</code> file -- SQLite transactions</li> <li>Litestream replicates -- WAL frames streamed to S3</li> <li>Sync bridge runs -- Celery task mirrors changes to Git remotes</li> <li>Django reflects state -- reads from Fossil SQLite for dashboards</li> </ol> <p>Fossil is always the source of truth. Everything else is derived.</p>"},{"location":"architecture/sync-bridge/","title":"Sync Bridge","text":"<p>The sync bridge mirrors Fossil repositories to GitHub and GitLab as downstream read-only copies.</p>"},{"location":"architecture/sync-bridge/#how-it-works","title":"How It Works","text":"<pre><code>flowchart LR\n Fossil[\"Fossil Repo<br/>(source of truth)\"] --> Bridge[\"Sync Bridge<br/>(Celery task)\"]\n Bridge --> Git[\"Git Export\"]\n Git --> GitHub[\"GitHub Mirror\"]\n Git --> GitLab[\"GitLab Mirror\"]</code></pre> <p>The bridge:</p> <ol> <li>Exports Fossil commits as Git commits</li> <li>Pushes to configured Git remotes</li> <li>Optionally syncs tickets to GitHub/GitLab Issues</li> <li>Optionally syncs wiki pages to repo docs</li> </ol>"},{"location":"architecture/sync-bridge/#what-gets-synced","title":"What Gets Synced","text":"Fossil Artifact Git Target Configurable Commits Git commits Always Tags Git tags Always Branches Git branches Always Tickets GitHub/GitLab Issues Optional Wiki Repository docs Optional"},{"location":"architecture/sync-bridge/#configuration","title":"Configuration","text":"<p>Set up mirroring through the Django management UI or environment variables:</p> <pre><code># GitHub mirror\nGITHUB_TOKEN=ghp_xxxxxxxxxxxx\n\n# GitLab mirror\nGITLAB_TOKEN=glpat-xxxxxxxxxxxx\n</code></pre> <p>Per-repository mirror configuration is managed in the dashboard under Repository Settings > Sync.</p>"},{"location":"architecture/sync-bridge/#sync-modes","title":"Sync Modes","text":""},{"location":"architecture/sync-bridge/#on-demand","title":"On-Demand","text":"<p>Trigger a sync manually from the dashboard or CLI:</p> <pre><code>docker compose exec django python manage.py fossil_sync my-project\n</code></pre>"},{"location":"architecture/sync-bridge/#scheduled","title":"Scheduled","text":"<p>Configure a Celery Beat schedule to sync at regular intervals:</p> <pre><code># Runs every 15 minutes\nCELERY_BEAT_SCHEDULE = {\n 'sync-all-repos': {\n 'task': 'fossil.tasks.sync_all',\n 'schedule': 900.0,\n },\n}\n</code></pre>"},{"location":"architecture/sync-bridge/#upstream-pull","title":"Upstream Pull","text":"<p>Pull updates from a remote Fossil server into your local instance:</p> <pre><code>docker compose exec django python manage.py fossil_pull my-project\n</code></pre> <p>Direction matters</p> <p>The sync bridge is one-way: Fossil to Git. Changes pushed directly to a Git mirror will be overwritten on the next sync. Always push to the Fossil repo.</p>"},{"location":"getting-started/configuration/","title":"Configuration","text":""},{"location":"getting-started/configuration/#environment-variables","title":"Environment Variables","text":"<p>All configuration is done through environment variables, loaded from <code>.env</code> in development.</p>"},{"location":"getting-started/configuration/#django-settings","title":"Django Settings","text":"Variable Default Description <code>SECRET_KEY</code> -- Django secret key (required) <code>DEBUG</code> <code>False</code> Enable debug mode <code>ALLOWED_HOSTS</code> <code>localhost</code> Comma-separated list of allowed hosts <code>TIME_ZONE</code> <code>UTC</code> Server timezone"},{"location":"getting-started/configuration/#database","title":"Database","text":"Variable Default Description <code>POSTGRES_DB</code> <code>fossilrepo</code> Database name <code>POSTGRES_USER</code> <code>fossilrepo</code> Database user <code>POSTGRES_PASSWORD</code> -- Database password (required) <code>POSTGRES_HOST</code> <code>postgres</code> Database host <code>POSTGRES_PORT</code> <code>5432</code> Database port"},{"location":"getting-started/configuration/#redis-celery","title":"Redis & Celery","text":"Variable Default Description <code>REDIS_URL</code> <code>redis://redis:6379/0</code> Redis connection URL <code>CELERY_BROKER_URL</code> <code>$REDIS_URL</code> Celery broker (defaults to Redis URL)"},{"location":"getting-started/configuration/#fossil","title":"Fossil","text":"Variable Default Description <code>FOSSIL_REPO_DIR</code> <code>/data/repos</code> Directory where <code>.fossil</code> files are stored <code>FOSSIL_BASE_URL</code> -- Base URL for Fossil web UI (e.g., <code>https://code.example.com</code>) <code>FOSSIL_BINARY</code> <code>fossil</code> Path to the Fossil binary"},{"location":"getting-started/configuration/#caddy-production","title":"Caddy (Production)","text":"Variable Default Description <code>CADDY_DOMAIN</code> -- Your domain (e.g., <code>example.com</code>) <code>CADDY_EMAIL</code> -- Email for Let's Encrypt certificates"},{"location":"getting-started/configuration/#litestream-backups","title":"Litestream (Backups)","text":"Variable Default Description <code>LITESTREAM_ACCESS_KEY_ID</code> -- S3 access key <code>LITESTREAM_SECRET_ACCESS_KEY</code> -- S3 secret key <code>LITESTREAM_BUCKET</code> -- S3 bucket name <code>LITESTREAM_ENDPOINT</code> -- S3 endpoint (for MinIO/B2) <code>LITESTREAM_REGION</code> <code>us-east-1</code> S3 region"},{"location":"getting-started/configuration/#sync-bridge","title":"Sync Bridge","text":"Variable Default Description <code>GITHUB_TOKEN</code> -- GitHub personal access token (for mirroring) <code>GITLAB_TOKEN</code> -- GitLab personal access token (for mirroring)"},{"location":"getting-started/configuration/#caddy-configuration","title":"Caddy Configuration","text":"<p>The Caddyfile controls SSL termination and subdomain routing. Each Fossil repo gets its own subdomain:</p> <pre><code>{$CADDY_DOMAIN} {\n reverse_proxy django:8000\n}\n\n*.{$CADDY_DOMAIN} {\n reverse_proxy fossil:8080\n}\n</code></pre> <p>Caddy automatically provisions Let's Encrypt certificates for all subdomains.</p>"},{"location":"getting-started/configuration/#litestream-configuration","title":"Litestream Configuration","text":"<p>Litestream continuously replicates every <code>.fossil</code> SQLite file to S3:</p> <pre><code>dbs:\n - path: /data/repos/*.fossil\n replicas:\n - type: s3\n bucket: ${LITESTREAM_BUCKET}\n endpoint: ${LITESTREAM_ENDPOINT}\n region: ${LITESTREAM_REGION}\n</code></pre> <p>Point-in-time recovery</p> <p>Litestream replicates WAL frames continuously. You can restore any <code>.fossil</code> file to any point in time, not just the latest snapshot.</p>"},{"location":"getting-started/first-repo/","title":"Creating Your First Repository","text":"<p>Once fossilrepo is running, you can create your first Fossil repository.</p>"},{"location":"getting-started/first-repo/#via-the-dashboard","title":"Via the Dashboard","text":"<ol> <li>Log in at <code>http://localhost:8000</code></li> <li>Navigate to Repositories in the sidebar</li> <li>Click Create Repository</li> <li>Enter a name (e.g., <code>my-project</code>)</li> <li>Click Create</li> </ol> <p>The repository is immediately available at <code>my-project.your-domain.com</code> (production) or through the local Fossil server (development).</p>"},{"location":"getting-started/first-repo/#via-the-cli","title":"Via the CLI","text":"<pre><code># Inside the fossilrepo container\ndocker compose exec django python manage.py fossil_create my-project\n</code></pre> <p>This runs <code>fossil init</code>, registers the repo in the database, and (in production) Caddy automatically routes the subdomain.</p>"},{"location":"getting-started/first-repo/#what-happens-under-the-hood","title":"What Happens Under the Hood","text":"<pre><code>sequenceDiagram\n participant User\n participant Django\n participant Fossil\n participant Litestream\n participant S3\n\n User->>Django: Create repo \"my-project\"\n Django->>Fossil: fossil init /data/repos/my-project.fossil\n Fossil-->>Django: Repository created\n Django->>Django: Register in database\n Litestream->>S3: Begin replicating my-project.fossil\n Django-->>User: Repository ready</code></pre>"},{"location":"getting-started/first-repo/#accessing-your-repository","title":"Accessing Your Repository","text":""},{"location":"getting-started/first-repo/#web-ui","title":"Web UI","text":"<p>Fossil includes a built-in web interface with:</p> <ul> <li>Timeline -- commit history with diffs</li> <li>Tickets -- issue tracker</li> <li>Wiki -- project documentation</li> <li>Forum -- discussions</li> </ul>"},{"location":"getting-started/first-repo/#clone-via-fossil","title":"Clone via Fossil","text":"<pre><code>fossil clone https://my-project.your-domain.com my-project.fossil\nfossil open my-project.fossil\n</code></pre>"},{"location":"getting-started/first-repo/#clone-via-git-mirror","title":"Clone via Git (Mirror)","text":"<p>If you've configured the sync bridge:</p> <pre><code>git clone https://github.com/your-org/my-project.git\n</code></pre> <p>Read-only mirror</p> <p>Git mirrors are downstream copies. Push changes to the Fossil repo -- they'll sync to Git automatically.</p>"},{"location":"getting-started/first-repo/#next-steps","title":"Next Steps","text":"<ul> <li>Configure the sync bridge to mirror to GitHub/GitLab</li> <li>Set up backups with Litestream</li> <li>Explore the architecture overview</li> </ul>"},{"location":"getting-started/installation/","title":"Installation","text":""},{"location":"getting-started/installation/#clone-the-repository","title":"Clone the Repository","text":"<pre><code>git clone https://github.com/ConflictHQ/fossilrepo.git\ncd fossilrepo\n</code></pre>"},{"location":"getting-started/installation/#environment-configuration","title":"Environment Configuration","text":"<p>Copy the example environment file and configure it:</p> <pre><code>cp .env.example .env\n</code></pre> <p>Edit <code>.env</code> with your settings:</p> <pre><code># Django\nSECRET_KEY=your-secret-key-here\nDEBUG=True\nALLOWED_HOSTS=localhost,127.0.0.1\n\n# Database\nPOSTGRES_DB=fossilrepo\nPOSTGRES_USER=fossilrepo\nPOSTGRES_PASSWORD=your-db-password\n\n# Redis\nREDIS_URL=redis://redis:6379/0\n\n# Fossil\nFOSSIL_REPO_DIR=/data/repos\nFOSSIL_BASE_URL=https://your-domain.com\n</code></pre>"},{"location":"getting-started/installation/#start-the-stack","title":"Start the Stack","text":""},{"location":"getting-started/installation/#development","title":"Development","text":"<pre><code># Build and start all services\nmake build\n\n# Run database migrations\nmake migrate\n\n# Create an admin user\nmake superuser\n\n# Load sample data (optional)\nmake seed\n</code></pre> <p>The development stack includes:</p> <ul> <li>Django dev server on <code>http://localhost:8000</code></li> <li>PostgreSQL 16</li> <li>Redis</li> <li>Celery worker + beat</li> <li>Mailpit on <code>http://localhost:8025</code></li> </ul>"},{"location":"getting-started/installation/#production","title":"Production","text":"<p>For production, you'll also configure Caddy and Litestream:</p> <pre><code># Copy production configs\ncp docker/Caddyfile.example docker/Caddyfile\ncp docker/litestream.yml.example docker/litestream.yml\n\n# Edit with your domain and S3 credentials\n# Then start with the production compose file\ndocker compose -f docker-compose.yml -f docker-compose.prod.yml up -d\n</code></pre>"},{"location":"getting-started/installation/#verify-installation","title":"Verify Installation","text":"<pre><code># Check all services are running\ndocker compose ps\n\n# Hit the health endpoint\ncurl http://localhost:8000/health/\n\n# Open the dashboard\nopen http://localhost:8000\n</code></pre> <p>You should see</p> <p>The fossilrepo dashboard with navigation, login page, and (after seeding) sample repositories.</p>"},{"location":"getting-started/installation/#common-issues","title":"Common Issues","text":"Port 8000 already in use <p>Change the Django port mapping in <code>docker-compose.yml</code>: <pre><code>ports:\n - \"8001:8000\"\n</code></pre></p> Database connection refused <p>Ensure PostgreSQL has started before Django: <pre><code>docker compose logs postgres\n</code></pre> The Django container waits for Postgres to be ready, but network issues on some Docker Desktop versions can cause timeouts. Restart with <code>make down && make up</code>.</p> Permission denied on /data/repos <p>The Fossil repo directory needs to be writable by the container user: <pre><code>sudo chown -R 1000:1000 /data/repos\n</code></pre></p>"},{"location":"getting-started/prerequisites/","title":"Prerequisites","text":"<p>Before installing fossilrepo, ensure your server meets these requirements.</p>"},{"location":"getting-started/prerequisites/#system-requirements","title":"System Requirements","text":"Requirement Minimum OS Linux (Ubuntu 22.04+, Debian 12+, RHEL 9+) or macOS 13+ CPU 1 vCPU RAM 1 GB Disk 10 GB (scales with repo count) Python 3.12+"},{"location":"getting-started/prerequisites/#required-software","title":"Required Software","text":""},{"location":"getting-started/prerequisites/#docker-docker-compose","title":"Docker & Docker Compose","text":"<p>Fossilrepo runs its infrastructure stack via Docker Compose.</p> Ubuntu/DebianmacOS <pre><code># Install Docker\ncurl -fsSL https://get.docker.com | sh\nsudo usermod -aG docker $USER\n\n# Verify\ndocker compose version\n</code></pre> <pre><code># Install Docker Desktop\nbrew install --cask docker\n\n# Verify\ndocker compose version\n</code></pre>"},{"location":"getting-started/prerequisites/#git","title":"Git","text":"<p>Required for the sync bridge (mirroring to GitHub/GitLab).</p> <pre><code>git --version # 2.30+\n</code></pre>"},{"location":"getting-started/prerequisites/#make","title":"Make","text":"<p>Used for running common commands.</p> <pre><code>make --version\n</code></pre>"},{"location":"getting-started/prerequisites/#optional-s3-compatible-storage","title":"Optional: S3-Compatible Storage","text":"<p>For continuous backups via Litestream, you need an S3-compatible bucket:</p> <ul> <li>AWS S3</li> <li>MinIO (self-hosted)</li> <li>Backblaze B2</li> <li>DigitalOcean Spaces</li> </ul> <p>Local development</p> <p>S3 is not required for local development. Litestream is disabled by default in the dev Docker Compose configuration.</p>"},{"location":"getting-started/prerequisites/#ports","title":"Ports","text":"<p>The following ports are used by the stack:</p> Port Service <code>8000</code> Django (management UI) <code>443</code> Caddy (HTTPS, production) <code>80</code> Caddy (HTTP redirect, production) <code>5432</code> PostgreSQL <code>6379</code> Redis <code>8025</code> Mailpit (dev only)"}]} |