Fornacast is a small self-hosted Git forge built with Elixir, Phoenix, Erlang/OTP SSH, Ecto on ExTurso/Turso by default, Concord-backed key/value app config, optional PostgreSQL, and Rust NIFs over gitoxide.
The first release target is intentionally narrow: create users and repositories, authenticate Git over SSH with user SSH keys, push/clone/fetch with a normal Git client, and browse repositories in the web UI.
Implemented first-release paths:
- Local users with password login.
- First-admin bootstrap task.
- SSH public key management.
- Private repository creation.
- Filesystem-backed bare Git storage.
- Erlang/OTP Git-over-SSH daemon.
git ls-remote,git clone,git fetch, and basicgit push.- Initial branch push, fast-forward branch update, new branch push, tag creation, and force-push rejection.
- Repository overview, README rendering, source tree, file view, raw file, commits, commit detail, diffs, branches, and tags.
/healthendpoint.- First-admin setup wizard and automatic boot migrations.
Out of scope for this release: issues, pull requests, CI, packages, LFS, mirrors, forks, smart HTTP Git transport, and Forgejo/Gitea API compatibility.
Prerequisites:
- Elixir 1.20 with Erlang/OTP 29.
- Rust 1.96 or newer.
- Git and OpenSSH client tools for compatibility tests.
Setup:
mix deps.get
mix ecto.setup
mix testRun locally:
mix fornacast.runOn a fresh install this prints a setup URL. Open http://localhost:4000/setup to create the first admin account, then log in.
Default local endpoints:
- Web:
http://localhost:4000 - SSH:
ssh://USER@localhost:2222/USER/REPO.git
Alternatively, create the first admin headlessly without the web wizard:
mix fornacast.admin.create \
--username alice \
--email alice@example.com \
--password "correct horse battery staple"Create an environment file:
cp .env.example .env
mix phx.gen.secretSet SECRET_KEY_BASE in .env to the generated value.
By default Docker Compose uses a local Turso-compatible Ecto database file at /data/fornacast.db and a separate Concord key/value config database at /data/fornacast_config.db.
Replace POSTGRES_PASSWORD only when using the optional PostgreSQL profile.
Build and start:
docker compose up --build -dTo build and run a PostgreSQL-backed image instead, set FORNACAST_DATABASE_ADAPTER=postgres and DATABASE_URL, then start the optional Postgres profile:
FORNACAST_DATABASE_ADAPTER=postgres \
DATABASE_URL=ecto://fornacast:$POSTGRES_PASSWORD@db/fornacast_prod \
docker compose --profile postgres up --build -dMigrations run automatically on container start. Open http://localhost:4000/setup to create the first admin account.
Alternatively, create the first admin headlessly in the running container without the web wizard:
docker compose exec app /app/bin/fornacast eval \
'ForgeAccounts.create_first_admin(%{username: "alice", email: "alice@example.com", password: "correct horse battery staple"})'Then log in, add an SSH key, and create a repository.
After creating a repository named demo for user alice:
git init demo
cd demo
echo "# Demo" > README.md
git add README.md
git commit -m "Initial commit"
git branch -M main
git remote add origin ssh://alice@localhost:2222/alice/demo.git
git push -u origin main
git clone ssh://alice@localhost:2222/alice/demo.git ../demo-cloneSupported write-side policy for v0.1:
- Allow branch creation.
- Allow fast-forward branch updates.
- Allow tag creation.
- Reject force pushes.
- Reject branch and tag deletion.
Production environment variables:
SECRET_KEY_BASEFORNACAST_DATABASE_ADAPTER, defaultturso; usepostgresfor PostgreSQL buildsFORNACAST_DATABASE_PATH, default/data/fornacast.dbin production Turso modeTURSO_DATABASE_URL, optional remote Turso/libSQL URI for the Ecto databaseTURSO_AUTH_TOKEN, optional Turso auth token for the Ecto databaseFORNACAST_CONFIG_DATABASE_PATH, default/data/fornacast_config.dbfor the Concord key/value config databaseFORNACAST_CONFIG_TURSO_DATABASE_URL, optional remote Turso/libSQL URI for Concord-backed app configFORNACAST_CONFIG_TURSO_AUTH_TOKEN, optional Turso auth token for Concord-backed app configDATABASE_URL, required only when built withFORNACAST_DATABASE_ADAPTER=postgresFORNACAST_BASE_URLFORNACAST_REPO_STORAGE_ROOTFORNACAST_SSH_HOSTFORNACAST_SSH_PORTFORNACAST_SSH_SYSTEM_DIRPORTfor the HTTP listener, default4000POOL_SIZE, optional, default10
Development and test also honor:
FORNACAST_DATABASE_PATH, defaultfornacast_dev.dbFORNACAST_TEST_DATABASE_PATH, defaultfornacast_test.dbFORNACAST_CONFIG_DATABASE_PATH, defaultfornacast_config_dev.dbFORNACAST_TEST_CONFIG_DATABASE_PATH, defaultfornacast_config_test.dbFORNACAST_SSH_BIND_IPFORNACAST_SSH_ENABLED
The Ecto adapter is selected at compile time. Build or recompile with FORNACAST_DATABASE_ADAPTER=postgres to use PostgreSQL; omit it for the default ExTurso/Turso-compatible backend. Concord is used separately for app-level key/value config through Fornacast.ConfigStore.
The first visit to a fresh instance serves an unauthenticated setup page that creates the first administrator. Do not expose an un-set-up instance to untrusted networks; complete setup immediately after first boot.
Fornacast stores domain state in the configured Ecto database, app-level key/value config in Concord, and bare Git repositories under FORNACAST_REPO_STORAGE_ROOT.
Back up both together:
cp "$FORNACAST_DATABASE_PATH" fornacast.db
cp "$FORNACAST_CONFIG_DATABASE_PATH" fornacast_config.db
tar -C "$FORNACAST_REPO_STORAGE_ROOT" -czf fornacast-repos.tgz .
tar -C "$FORNACAST_SSH_SYSTEM_DIR" -czf fornacast-ssh.tgz .For remote Turso databases, use Turso's backup/export workflow for the database and config store, and back up the repository and SSH directories separately.
For PostgreSQL deployments, use pg_dump "$DATABASE_URL" > fornacast.sql.
For default Docker Compose deployments, back up the named data volume:
docker run --rm -v fornacast_fornacast-data:/data -v "$PWD":/backup debian:bookworm-slim \
tar -C /data -czf /backup/fornacast-data.tgz .Restore requires the database dump and the repository/SSH data from the same point in time.
Before tagging v0.1, Fornacast should host this repository as a normal remote for at least one development cycle:
git remote add fornacast ssh://alice@HOST:2222/alice/fornacast.git
git push fornacast main
git clone ssh://alice@HOST:2222/alice/fornacast.git fornacast-cloneThen verify the web UI can browse the source tree, README, commit list, commit details, branches, tags, raw files, and diffs for the pushed repository.