- Local Self-Hosted Runner using Docker Compose
- Adding a Local Docker Registry
- Add Self-Hosted Apache Maven Registry
This post describes the procedure for adding a self-hosted Maven registry to our evolving Docker Compose stack.

Reposilite will be used as the Maven host.
Configure Authentication for Reposilite Host
- Generate an access token by interactively running a reposilite container (a docker volume is used to persist data):
$ docker run -it --name reposilite -v reposilite-data:/app/data -p 80:8080 dzikoysk/reposilite:nightly
- Once the following message is displayed
INFO | Latest version of Reposilite: 3.5.12
INFO |
INFO | For help, type 'help' or '?'
generate an access token by entering,
token-generate admin-token m
- This should create a management token (‘m‘) named: admin-token:
INFO | Generated new access token for admin-token with 'm' permissions. Secret:
INFO | /NXCrAC5*******************aTQejFHM5zhW5Syv/g8v7g3Z49lv
To login to the dashboard
- navigate to http://localhost
- choose “Sign in“
- enter admin-token for Name
- enter the management token generated as the secret

- Stop the server
INFO | For help, type 'help' or '?'
stop
- remove the container
$ docker container remove reposilite
Add Reposilite Service to Docker Compose
Add reposilite service and volume definitions to the docker compose file.
docker-compose.yml
version: "3.8"
services:
self-hosted-runner:
image: ubuntu-self-hosted-gh-runner:latest
container_name: self-hosted-runner
privileged: true
volumes:
- var-lib-docker:/var/lib/docker
networks:
- local-net
environment:
- REPO_OWNER=<git-repo-owner>
- REPOSITORY=<git-repo-name>
- RUNNER_ADMIN_TOKEN=<classic personal access token>
- RUNNER_LABELS={"labels":["self-hosted","jammy-amd64"]}
- RUNNER_NAME=self-hosted-jammy-amd64
- RUNNER_CONFIG_ARGS=--unattended --replace --disableupdate --no-default-labels
registry:
image: registry:latest
container_name: registry
hostname: registry
volumes:
- ./auth:/auth
- var-lib-registry:/var/lib/registry
ports:
- "5000:5000"
networks:
- local-net
environment:
- REGISTRY_AUTH=htpasswd
- REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm"
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
- REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry
reposilite:
image: dzikoysk/reposilite:nightly
hostname: reposilite
container_name: reposilite
volumes:
- reposilite-data:/app/data
ports:
- "80:8080"
networks:
- local-net
networks:
local-net:
name: local-net
volumes:
var-lib-docker:
name: var-lib-docker
var-lib-registry:
name: var-lib-registry
reposilite-data:
name: reposilite-data
Test by using Maven to Build a Sample Java App
Couple of things to note before moving on to testing. The Maven (mvn
) binary will need to be installed onto the self-hosted runner OS. Alternatively, a Maven action can be used if installing onto the runner OS is not a feasible option.
Examples in subsequent sections assume Maven 3.8.8 has been installed.
A basic workflow will be used to perform the following steps:
- build a Java app using Maven
- publish components to our local reposilite Maven host
All components referenced be located in GitHub repository:
https://github.com/techtoaster-io/github-self-hosted-runner-maven-java
Before moving onto the next section, start the docker compose stack and check to ensure the 3 services/containers launch without error.
Obtain Maven Repository Metadata
- Login to reposilite
http://localhost
using token name (admin-token) and corresponding secret value, as generated in previous sections - Navigate to the
private
Maven repository and note down the corresponding xml metadata

- Metadata should appears as follows
<repository>
<id>reposilite-repository-private</id>
<name>Reposilite Repository</name>
<url>http://localhost/private</url>
</repository>
- The reposilite service definition in our
docker-compose.yml
was defined usinghostname:reposilite
, and internal docker compose port8080
, therefore theurl
in the repository metadata will need to be updated:
<repository>
<id>reposilite-repository-private</id>
<name>Reposilite Repository</name>
<url>http://reposilite/private:8080</url>
</repository>
Prepare POM.xml
Substitute the xml repository definition above into the <distributionManagement>
section of the project’ pom.xml
file.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.techtoaster.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<name>my-app</name>
<url>https://github.com/techtoaster-io/github-self-hosted-runner-maven-java</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<distributionManagement>
<repository>
<id>reposilite-repository-private</id>
<name>Reposilite Repository</name>
<url>http://reposilite:8080/private</url>
</repository>
</distributionManagement>
</project>
Define Repository Variable to Store Contents of Maven settings.xml
Define a new repository variable named MAVEN_SETTINGS_XML
with the following contents:
<?xml version="1.0" encoding="UTF-8"?>
<settings xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd" xmlns="http://maven.apache.org/SETTINGS/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<servers>
<server>
<id>reposilite-repository-private</id>
<username>${env.MAVEN_REPOSILITE_USERNAME}</username>
<password>${env.MAVEN_REPOSILITE_TOKEN}</password>
</server>
</servers>
</settings>

Server username and password have been replaced with environment variables, respectively as
${env.MAVEN_REPOSILITE_USERNAME}
${env.MAVEN_REPOSILITE_TOKEN}
Repository secrets will need to be defined to store the values of both variables.
Define Repository Secrets
Create the following repository secrets to store the reposilite server username/secret token:
Secret name: MAVEN_REPOSILITE_USERNAME
Secret: admin-token
Secret name: MAVEN_REPOSILITE_TOKEN
Secret: <value as generated in section Configure Authentication for Reposilite Host"

Run Workflow
The sample GHA workflow below builds the sample Java project using Maven and publishes the output package to the reposilite repository:
name: Sample Workflow to Build Java App with Maven
on:
workflow_dispatch:
jobs:
build:
runs-on: [self-hosted]
steps:
# reference : https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#publishing-using-apache-maven
# NOTE: The settings.xml file is created in the Actions $HOME/.m2 directory.
# If you have an existing settings.xml file at that location, it will be overwritten.
# See below for using the settings-path to change your settings.xml file location.
# If you don't want to overwrite the settings.xml file, you can set overwrite-settings: false
- name: checkout
uses: actions/checkout@v4
- name: Retrieve var MAVEN_SETTINGS_XML and write to file
run: |
echo -e '${{ vars.MAVEN_SETTINGS_XML }}' > ${{ github.workspace }}/settings.xml
cat ${{ github.workspace }}/settings.xml
- name: Setup Maven Action
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "temurin"
settings-path: ${{ github.workspace }} # refer previous step
overwrite-settings: false
server-id: reposilite-repository-private # Value of the distributionManagement/repository/id field of the pom.xml
server-username: MAVEN_REPOSILITE_USERNAME # env variable for username in deploy
server-password: MAVEN_REPOSILITE_TOKEN # env variable for token in deploy
- name: Publish to Reposilite
run: |
mvn --settings ${{ github.workspace }}/settings.xml clean dependency:copy-dependencies package
mvn --settings ${{ github.workspace }}/settings.xml package
mvn --settings ${{ github.workspace }}/settings.xml deploy
env:
MAVEN_REPOSILITE_USERNAME: ${{ secrets.MAVEN_REPOSILITE_USERNAME }}
MAVEN_REPOSILITE_TOKEN: ${{ secrets.MAVEN_REPOSILITE_TOKEN }}
Output log:

Check the reposilite host to ensure the package was uploaded successfully.
