IPCR Forge
From git push to docker pull on any server, without a central
service. Code lives on Radicle, this node builds it with GitHub-style workflows, and IPCR serves
the image from IPFS.
How it works
git push rad a v* tag to the Radicle networkact runs the repo's .github/workflows/ and pushes the imageipcr.localhost:4767/ipns/…Steps 2 to 4 are automatic and usually take a few minutes. The very first build on this server takes longer (about 5 to 10 minutes) while it downloads its build images. A repository needs no configuration beyond committing a workflow. There is no second copy of it anywhere: the build reads the commit straight from this node. Builds of the default branch and of patches also write their result back into the repository, signed by the node, as a Radicle job.
Only changes signed by one of the repository's delegates are built: release tags, the default branch and their patches. A build can publish an image, so it gets the trust of a release.
Published images
Loading…
Publish a project
- Install Radicle on your machine and create an identity: see
radicle.xyz, then
rad auth. Start your own node, which carries your pushes:rad node start. - Connect to this server's node so your pushes reach it:
rad node connect <node-id>@<this server>:8776 - Publish the repository. It has to be a Git repository with at least one commit:
git init -b main git add -A git commit -m "First commit" rad initrad initprints the repository ID (rad:z…). - Let this node seed it. The node only keeps repositories it is told to (seeding policy
block). In this server's Terminal app or over SSH:
It ends withdocker exec radicle-node rad seed rad:z… --scope all✗ Target not met: could not fetch from […]. That is about the public Radicle seeds, not this server, and can be ignored. The repository is in place once it shows in the Radicle explorer. - Add a workflow at
.github/workflows/build.yml, as on GitHub. This one builds theDockerfileat the root and publishes it for everyv*tag.vars.IMAGEis set for every repository (this node's staging registry plus the repository's name); there is no secret to configure. Two lines differ from a GitHub-hosted workflow:context: .(builds the checkout, not a GitHub URL) and buildx'snetwork=host(so its builder can reach the staging registry). Commit it (git add .github && git commit -m "Build the image").on: push: tags: ['v*'] jobs: image: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: docker/metadata-action@v5 id: meta with: images: ${{ vars.IMAGE }} tags: | type=semver,pattern={{version}} type=raw,value=latest - uses: docker/setup-buildx-action@v3 with: driver-opts: network=host - uses: docker/build-push-action@v6 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - Release:
Follow the build under CI runs. A minute after it finishes, the tag appears under Published images.git tag -a v1.0.0 -m v1.0.0 git push rad main v1.0.0
Use an image
Copy the line from Published images into a compose file. It works on this server and on any server running IPCR:
services:
myapp:
image: ipcr.localhost:4767/ipns/k51qzi5uqu5d…:1.0.0 # a tag: follows new builds of 1.0.0
# image: ipcr.localhost:4767/ipfs/bafkrei… # a CID: this exact image, forever
/ipns/<name>:<tag> is a name the publisher can move to a new build.
/ipfs/<cid> is the image's content address and can never change.
For a readable name, point a name you own at this forge's publisher name
(k51…), which holds every image it builds:
- ENS: set the content hash of
example.ethtoipns://k51…(one transaction, once). Images are thenipcr.localhost:4767/ipns/example.eth/<repo>:1.0.0. - DNS: add a TXT record
_dnslink.example.com=dnslink=/ipns/k51…. Images are thenipcr.localhost:4767/ipns/example.com/<repo>:1.0.0.
New releases need no change to either record: they update the publisher name.
Pull from another server
Any server with IPCR resolves the same lines and fetches the image from the IPFS network, from this server and from every other server that already pulled it.
On a Yundera server
Install IPCR from the App Store. There is nothing to configure.
On any Linux server with Docker 29+
mkdir -p /DATA/AppData/ipcr && cd /DATA/AppData/ipcr
curl -fsSLO https://raw.githubusercontent.com/Yundera/ipcr/main/Apps/IPCR/docker-compose.yml
install -d -m 0700 -o 1000 -g 1000 kubo && install -d -o 1000 -g 1000 init.d
curl -fsSL -o init.d/01-ipcr-node.sh https://raw.githubusercontent.com/Yundera/ipcr/main/Apps/IPCR/seed/init.d/01-ipcr-node.sh
chmod 0755 init.d/01-ipcr-node.sh
printf 'PUID=1000\nPGID=1000\nTZ=UTC\nAppID=ipcr\n' > .env
docker compose up -d
IPCR listens on 127.0.0.1:4767 only, and trusts itself through
/etc/docker/certs.d/ipcr.localhost:4767/ca.crt. It publishes port 4768 (TCP and UDP)
for IPFS peers. Details: github.com/Yundera/ipcr.
Addresses on this server
| Address | What |
|---|---|
| Radicle explorer (public) | |
| Radicle API and read-only git over HTTPS (public) | |
| ipcr-forge-…/ci/ | CI runs and their logs (public) |
ipcr.localhost:4767 | IPCR registry, for this server's Docker only |
| TCP 8776 · TCP/UDP 4768 | Radicle peers · IPFS peers |