Skip to main content
Version: 1.10.0

Deploy Gitea with a custom builder image

While you likely won't use Epinio to build and deploy Gitea, we are using it to show how to build a more complex application with Epinio.

Gitea is a self-hosted Git service. It is written in Go and Node.js.

At the time of writing the Paketo Go buildpack doesn't support Node.js asset compilation (see issue #671), so we need to create a custom builder.

This builder will just check the needed Go and Node dependencies, and execute the make command to build both the frontend and the backend.

The code used during this guide is available in the example-builder-gitea repository.

git clone
git submodule update --init --recursive
cd example-builder-gitea

Basic Concepts and prerequisites

Before starting it is useful to know some basic concepts around Buildpacks, and have some tools already installed.

You can find in the Buildpack documentation what stacks, builders, and buildpacks are. You should also have pack installed, along with docker and skopeo (to manage OCI artifacts).

Create the stack

Unfortunately we were not able to reuse the Paketo Full Stack because of a missing dependency in the run image. To make it simpler we just forked this stack and added git to the run packages (see 408e949).

We had to fork and/or reuse the same stack ID in order to reuse some Paketo buildpacks, that are going to work only with these stacks (see

Build the stack and publish the image

To build the stack:


This will create two OCI images in the stacks/bionic-full-stack/build folder:

  • build.oci
  • run.oci

From this folder we can untar the OCI artifacts

cd stacks/bionic-full-stack/build
mkdir build && tar -xf build.oci -C build
mkdir run && tar -xf run.oci -C run

use skopeo to copy the artifacts into our local Docker registry

skopeo -v copy oci:build
skopeo -v copy oci:run

and push them to a public registry

docker push
docker push

Create the make buildpack

To build the Gitea application we created a make buildpack.


During the detect phase the bin/detect script it will check the needed dependencies.

It will check for the existance of the Makefile

if [[ ! -f Makefile ]]; then
echo Makefile not found
exit 100

and it will write to the plan.toml file that this buildpack requires Go and Node.js

cat >> "${plan_path}" <<EOL
name = "node"
# version = "*"

build = true

name = "go"

build = true


During the build phase the buildpack will run the proper make command to build the application

TAGS="bindata" make build

setup the app configuration changing the listening port in the app.ini file

cp custom/conf/app.example.ini custom/conf/app.ini
sed -i "s/;HTTP_PORT = 3000/HTTP_PORT = 8080/" custom/conf/app.ini

and defining the launch process in the launch.toml file

cat >> "${layers_dir}/launch.toml" <<EOL
type = "web"
command = "./gitea"
default = true

Create and publish the builder

The builder.toml file contains the buildpacks references and their execution order/groups.

We are referencing our make buildpack locally

id = "make"
version = "0.0.1"
uri = "../../buildpacks/make"

and we are also using the Paketo node-engine and go-dist buildpacks

uri = "docker://"
version = "1.3.0"

uri = "docker://"
version = "2.3.0"

These buildpacks will provide the Node.js and Go dependencies

We can finally create the builder image with pack

pack builder create --config builders/gitea-builder/builder.toml

and push it to a public registry

docker push

Deploy Gitea

To deploy Gitea we can download the code from the reposotory, or refer directly to it.

We would like to deploy a stable release, so let's find the commit of the v1.19.0 with a couple of curls:

export GITEA_VERSION=v1.19.0
export GITEA_TAG_OBJECT_URL=$(curl -s$GITEA_VERSION | jq -r '.object.url')
export GITEA_TAG_COMMIT_SHA=$(curl -s $GITEA_TAG_OBJECT_URL | jq -r '.object.sha')

We can now deply Gitea with a simple epinio push:

epinio push --name gitea \

and then it should be available on your cluster (i.e. https://gitea.<SYSTEM_DOMAIN>)!

Create and bind the database

We can go a step further, creating and binding the mysql database to our application:

epinio service create mysql-dev mydb

We can check the status of the service

-> % epinio service show mydb            

🚢 Showing Service...

✔️ Details:
| Name | mydb |
| Created | 2023-04-04 15:56:20 +0200 CEST |
| Catalog Service | mysql-dev |
| Version | 8.0.31 |
| Status | deployed |
| Used-By | |
| Internal Routes | xcca9aa0f19a036fb6389474a7be0-mysql-headless.workspace.svc.cluster.local:3306, |
| | xcca9aa0f19a036fb6389474a7be0-mysql.workspace.svc.cluster.local:3306 |

We can use the internal route xcca9aa0f19a036fb6389474a7be0-mysql.workspace.svc.cluster.local:3306 to reach our DB.

Let's bind it to the Gitea application with epinio service bind mydb gitea.

And we can now check the username and passwords in the configuration:

-> % epinio configuration list

🚢 Listing configurations
Namespace: workspace

✔️ Epinio Configurations:
| xcca9aa0f19a036fb6389474a7be0-mysql | 2023-04-04 15:56:22 +0200 CEST | service | mydb | gitea (migrate to new access |
| | | | | paths) |
-> % epinio configuration show xcca9aa0f19a036fb6389474a7be0-mysql 

🚢 Configuration Details
Name: xcca9aa0f19a036fb6389474a7be0-mysql
Namespace: workspace

Created: 2023-04-04 15:56:22 +0200 CEST
Type: service
Origin: mydb
Used-By: gitea

⚠️ Attention: Migrate bound apps to new access paths
| mysql-password | 6oUDWVHVcv | /configurations/mydb/mysql-password |
| mysql-root-password | eG83csnOLe | /configurations/mydb/mysql-root-password |

⚠️ Beware, the shown access paths are only available in the application's container

We can use these credential to access the database. Access the first time Gitea configuration from your browser and fill the database fields with the host, username and password. The database name is my_database, that is the default value for the Bitnami charts that Epinio is using for its sample services.