Important
This is self-hosted software. There is no public/hosted instance — you must run your own (see Install).
The repo.koder.wtf links in the docs are a personal demo you can read from, but not publish to.
- Maven repositories, Docker/OCI registries and npm registries in one instance, sharing users, permissions and tokens
- Public and private repositories with per-user read/write grants
- Access tokens for Gradle/Maven,
docker loginand.npmrc, scoped to specific repositories - Web UI to browse artifacts, search packages, inspect images, tags and package versions, and manage users, repos and tokens
- H2 (embedded) or PostgreSQL database
- Local filesystem or S3-compatible storage
Live demo: https://repo.koder.wtf/#/ (example repository: https://repo.koder.wtf/#/repo/releases)
Docker:
docker run -d -p 8080:8080 \
-v artifact-forge-data:/app/data \
-e SESSION_SECRET=change-me-to-a-long-random-value \
ghcr.io/invalidjoker/artifact-forge:latestOr Docker Compose:
services:
artifact-forge:
image: ghcr.io/invalidjoker/artifact-forge:latest
ports:
- "8080:8080"
environment:
SESSION_SECRET: change-me-to-a-long-random-value
volumes:
- forge-data:/app/data
restart: unless-stopped
volumes:
forge-data:The initial admin password is generated and printed once to the logs on first boot:
docker logs <container> | grep -A6 "admin account"Open http://localhost:8080 and sign in as admin.
The project was renamed to Artifact Forge, and the image and two defaults moved with it:
- Image:
ghcr.io/invalidjoker/maven-repo→ghcr.io/invalidjoker/artifact-forge. - H2 database: the default file is now
./data/artifact-forge(was./data/maven-repo). Either renamemaven-repo.mv.dbtoartifact-forge.mv.dbin your data volume, or keep the old path by settingDATABASE_H2_FILE=./data/maven-repo. Without one of the two, the instance starts with an empty database. - PostgreSQL: the compose sample now uses the database
artifact_forgeand the userforge. An existing database needs no migration — keep pointing at it withDATABASE_NAME/DATABASE_USER/DATABASE_PASSWORD.
Artifacts, images and instance branding under /app/data are untouched, and an instance that already has a
display name keeps it — the new default only applies to fresh installs.
All settings are optional environment variables.
| Variable | Default | Description |
|---|---|---|
SESSION_SECRET |
(insecure default) | Key used to sign session cookies. Set this in production. |
SESSION_MAX_AGE |
604800 |
Session cookie lifetime in seconds (default 7 days). |
DATA_PATH |
./data/instance |
Folder for instance settings (name, icon), stored as files. |
DEMO |
false |
Set to true to show a "self-host required, no public instance" banner in the UI. |
| Variable | Default | Description |
|---|---|---|
ADMIN_USERNAME |
admin |
Username of the seeded admin. |
ADMIN_PASSWORD |
(generated) | Password for the seeded admin. If unset, a random one is generated and printed to the logs once. |
ADMIN_RESET_PASSWORD |
false |
Set to true for one boot to reset (and reprint) the admin password. |
| Variable | Default | Description |
|---|---|---|
DATABASE_TYPE |
h2 |
h2 (embedded file) or postgres. |
DATABASE_H2_FILE |
./data/artifact-forge |
H2 database file path (used when DATABASE_TYPE=h2). |
DATABASE_HOST / DATABASE_PORT / DATABASE_NAME / DATABASE_USER / DATABASE_PASSWORD |
PostgreSQL connection settings. |
| Variable | Default | Description |
|---|---|---|
STORAGE_TYPE |
local |
local (data volume) or s3. |
STORAGE_PATH |
./data/repositories |
Artifact directory (used when STORAGE_TYPE=local). |
UPLOAD_PATH |
./data/uploads |
Scratch space for in-flight Docker layer uploads. Cleared on boot. |
S3_BUCKET / S3_REGION / S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY |
S3 storage settings. | |
S3_ENDPOINT |
(AWS) | Custom endpoint for S3-compatible stores (MinIO, R2, Backblaze). |
Optional OpenID Connect login for providers like Authentik, Pocket ID or Keycloak. Leave OIDC_CLIENT_ID blank to disable. Uses the authorization-code flow with PKCE; endpoints are discovered from the issuer.
| Variable | Default | Description |
|---|---|---|
OIDC_ISSUER |
Issuer URL (must be reachable from the container; not localhost if dockerized). |
|
OIDC_CLIENT_ID |
OAuth client id. Setting this enables SSO. | |
OIDC_CLIENT_SECRET |
OAuth client secret. | |
OIDC_SCOPES |
openid profile email |
Space-separated scopes. |
OIDC_BUTTON_LABEL |
Sign in with SSO |
Label of the login button. |
Register the redirect URI <base-url>/auth/oidc/callback with your provider. On first login a local user is created (matched by the preferred_username claim) with no password; promote users to admin under Admin > Users.
Data (H2 database, local artifacts, instance branding) is stored under /app/data — keep it on a volume. Behind a reverse proxy, forward X-Forwarded-Proto and X-Forwarded-Host so redirects and OIDC callbacks use the correct public URL.
See USAGE.md for setting up repositories, consuming artifacts, and publishing.
Requires JDK 21 and bun.
./gradlew :backend:run # run locally on :8080
./gradlew :backend:shadowJar # fat jar at backend/build/libs/backend-all.jar
docker build -t artifact-forge . # container image