Steps for Act Runner with self-signed Root CA

I run Gitea on my internal network and wanted to start running CICD jobs for a couple of my repos (build docker images and then use them to build binaries). I ended up doing a bunch of searching on this forum and elsewhere to get this working (and it is!).

Here are the steps I took. I didn’t find a similar post in this category or in the Gitea documentation. Please let me know if there is a better place to post this.

I hope this shortens the spin-up time for others.

Assumptions

  • Gitea server is installed, running, and is accessed over HTTPS with a self-signed Root CA. For the purposes of these steps, Gitea URL is: https://gitea.mydomain.com.

Steps

Machine Creation, Certificate Install

  • Start with a clean Ubuntu Server 24.04.1. I used 8GB RAM, 4 CPU cores, 100GB root partition, connected to my internal network.

  • Copy the Root CA to /usr/local/share/ca-certificates, make sure file ends with .crt. Example:

# Change extension to .crt
mv rootca.pem rootca.crt

#Copy to folder
sudo cp rootca.crt /usr/local/share/ca-certificates
  • Run command sudo update-ca-certificates (it should show at least one certificate was added)

  • Example command to verify Root CA is working

openssl s_client -connect gitea.mydomain.com:443 -CApath /etc/ssl/certs
  • “Good” output looks like this:
... truncated output ...

SSL handshake has read 5819 bytes and written 431 bytes
Verification: OK   <<--- This is good

... truncated output ...

    Start Time: 1677365219
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)   <<--- This is good
    Extended master secret: yes

Install and Configure Docker

# Make directory with name of gitea server
sudo mkdir -p /etc/docker/certs.d/gitea.mydomain.com
sudo cp rootca.crt /etc/docker/certs.d/gitea.mydomain.com/ca.crt

# Note: the certificate file Docker expects is ca.crt

Side note…

For jobs that build and push Docker containers to the Gitea registry, I found the “docker login” step (docker/login-action@v2) requires the host machine’s Docker to be aware of the Root CA (which the above steps ensure).

Also when building containers, the docker/setup-buildx-action@v2 steps needs to look like this:

- name: Setup BuildX
  uses: docker/setup-buildx-action@v2
  with:
    config-inline: |
      [registry."gitea.mydomain.com"]
        ca=["/etc/ssl/certs/ca-certificates.crt"]   

Leave out http = true or insecure = true in this case. The subsequent build and push (docker/build-push-action@v4) occurs over HTTPS successfully.

I found this Gitea blog post very helpful: “Automating Release Versioning with Gitea Actions to the Gitea Package Registry”.


Setup and Start Act Runner

  • In home directory, create folder gitea_runner (full path: /home/myuser/gitea_runner)

  • Create docker-compose.yaml from the Gitea documentation

  • Make the following modifications (full example):

services:
  runner:
    image: docker.io/gitea/act_runner:latest
    environment:
      CONFIG_FILE: /config.yaml
      GITEA_INSTANCE_URL: "${INSTANCE_URL}"
      GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}"
      GITEA_RUNNER_NAME: "${RUNNER_NAME}"
      # GITEA_RUNNER_LABELS: "${RUNNER_LABELS}"  <<<--- Defined in config.yaml
    restart: always   <<<--- The runner will start on system boot
    volumes:
      - ./config.yaml:/config.yaml
      - ./data:/data
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro   <<<--- Mount *only* the certificate file read-only
  • Get a Runner registration token from Gitea

  • Create .env and populate as required (example):

INSTANCE_URL="https://gitea.mydomain.com"
RUNNER_NAME=mynewrunner
REGISTRATION_TOKEN=1234abcd   <<<--- Paste registration token
  • Generate default config.yaml
docker run --entrypoint="" --rm -it docker.io/gitea/act_runner:latest act_runner generate-config > config.yaml
  • Modify as follows (truncated example)
container:
  options: "-v /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro -e NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt"
  valid_volumes:
    - "/etc/ssl/certs/ca-certificates.crt"
  • What’s going on? (my understanding) When the the Act Runner runs a job, it creates a new job container. The options and valid_volume provide the Root CA to the job container. Explanation:

    • The -v makes the Root CA available to the job container. Needed for actions/checkout@v3.
    • The -e creates environment variable NODE_EXTRA_CA_CERTS. This is needed for node to successfully push artifacts back to Gitea with actions/upload-artifact@v3.
    • Must specify the certificate path in valid_volumes:. Act Runner won’t mount the volume into the job container without this.
  • Start the Runner

docker compose up -d
  • (optional) Follow logs
docker compose logs -f

Note: Logging defaults to info. Change to debug in config.yaml, then restart the Runner docker compose restart, then follow the logs docker compose logs -f.

  • Look at Gitea to see newly registered runner

  • The Runner is now ready to accept jobs

I have found existing threads addressing very similar issues. I’d amend my post: “Here are the steps I took. There are several forum posts addressing this topic. The notes below contain the pieces that made my setup work.”

While you’re at it, i’d suggest using docker swarm mode rather than docker- compose. Also maybe add the act_runner in the docker compose or in the swarm.

Also, i’d suggest to move away from using “latest”. e.g. docker.io/gitea/act_runner:latest.

so, pin it down as it is the best practice.

What about act_runner building docker images ?

You’re referencing things in the text that send the reader nowhere,
like

Create docker-compose.yaml from the Gitea documentation

There are several places, add a link, would be helpful to somebody following your steps. Or add the yaml at the end of the post.

Otherwise great job!

@mariusrugan, thank you for taking the time to critique my post.

Seems I need to learn about docker swarm mode. Will keep this in mind.

Recommendations on the best way to show this? Maybe a note below the file? I hesitate to put a specific version in the docker-compose.yaml example.

Maybe a separate post is best for the build images part? The docker/setup-buildx-action@v2 detail took me a good bit to figure out. Wanted to include what finally worked.

100% agree on adding more links. My local draft has all the links. I was limited to posting only 2 links (just joined). I plan to update as soon as I have enough reputation on this forum.

…attempted to edit the main post. It seems editing is locked out (completely) after a certain amount of time.

I know this will bump the topic again, but here is the main post with all the links and suggested improvements (thanks @mariusrugan!).

Steps for Act Runner with self-signed Root CA

I run Gitea on my internal network and wanted to start running CICD jobs for a couple of my repos (build docker images and then use them to build binaries). I ended up doing a bunch of searching on this forum and elsewhere to get this working (and it is!).

Here are the steps I took. There are several forum posts addressing this topic. The notes below contain the pieces that made my setup work.

I hope this shortens the spin-up time for others.

Assumptions

  • Gitea server is installed, running, and is accessed over HTTPS with a self-signed Root CA. For the purposes of these steps, Gitea URL is: https://gitea.mydomain.com.

Steps

Machine Creation, Certificate Install

  • Start with a clean Ubuntu Server 24.04.1. I used 8GB RAM, 4 CPU cores, 100GB root partition, connected to my internal network.

  • Copy the Root CA to /usr/local/share/ca-certificates, make sure file ends with .crt. Example:

# Change extension to .crt
mv rootca.pem rootca.crt

# Copy to folder
sudo cp rootca.crt /usr/local/share/ca-certificates
  • Run command sudo update-ca-certificates (it should show at least one certificate was added)

  • Example command to verify Root CA is working

openssl s_client -connect gitea.mydomain.com:443 -CApath /etc/ssl/certs
  • “Good” output looks like this:
... truncated output ...

SSL handshake has read 5819 bytes and written 431 bytes
Verification: OK   <<--- This is good

... truncated output ...

    Start Time: 1677365219
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)   <<--- This is good
    Extended master secret: yes

Install and Configure Docker

  • Follow Docker install steps for Ubuntu

  • (optional) Docker sometimes doesn’t see the Root CA (even after rebooting/restarting the docker service). Follow Docker’s certifiate instructions if needed. Example:

# Make directory with name of gitea server
sudo mkdir -p /etc/docker/certs.d/gitea.mydomain.com

# Copy Root CA into folder, ensure file name is "ca.crt"
sudo cp rootca.crt /etc/docker/certs.d/gitea.mydomain.com/ca.crt

Setup and Start Act Runner

  • In home directory, create folder gitea_runner (full path: /home/myuser/gitea_runner)

  • Create docker-compose.yaml from the Gitea documentation

  • Make the following modifications (full example):

services:
  runner:
    image: docker.io/gitea/act_runner:latest
    environment:
      CONFIG_FILE: /config.yaml
      GITEA_INSTANCE_URL: "${INSTANCE_URL}"
      GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}"
      GITEA_RUNNER_NAME: "${RUNNER_NAME}"
      # GITEA_RUNNER_LABELS: "${RUNNER_LABELS}"  <<<--- Defined in config.yaml
    restart: always   <<<--- The runner will start on system boot
    volumes:
      - ./config.yaml:/config.yaml
      - ./data:/data
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro   <<<--- Mount *only* the certificate file read-only

Note: Subfolders of read-only volume mounts may be writable. Hence the comment to “Mount only the certificate file read-only” in the example above. I want to protect my certificates from modification by any running jobs. Link to documentation if you’d like to delve deeper: options for bind mounts.

Note: It is best practice to “pin” the act_runner version, especially in production environments. This helps increase stability and consistency. Read the changelogs on the Releases page for gitea/act_runner to determine which version to “pin.” Be aware the release tag (v0.2.11) may not match the container tag (0.2.11). Find the correct container tag on Docker Hub gitea/act_runner. Example: gitea/act_runner:0.2.11.

  • Get a Runner registration token from Gitea

  • Create a file named .env and populate as required (example):

INSTANCE_URL="https://gitea.mydomain.com"
RUNNER_NAME=mynewrunner
REGISTRATION_TOKEN=1234abcd   <<<--- Paste registration token
docker run --entrypoint="" --rm -it docker.io/gitea/act_runner:latest act_runner generate-config > config.yaml
  • Modify as follows (truncated example)
container:
  options: "-v /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro -e NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt"
  valid_volumes:
    - "/etc/ssl/certs/ca-certificates.crt"
  • What’s going on? (my understanding) When the the Act Runner runs a job, it creates a new job container. The options and valid_volume provide the Root CA to the job container. Explanation:

    • The -v makes the Root CA available to the job container. Needed for actions/checkout@v3.

    • The -e creates environment variable NODE_EXTRA_CA_CERTS. This is needed for node to successfully push artifacts back to Gitea with actions/upload-artifact@v3.

    • Must specify the certificate path in valid_volumes. Act Runner won’t mount the volume into the job container without this.

  • Folder structure should now look like this:

gitea_runner
├── config.yaml
├── docker-compose.yaml
└── .env
  • Start the Runner
docker compose up -d
  • (optional) Follow logs
docker compose logs -f

Note: Log level is defined in config.yaml. This is usually set to info. To see more detail change to debug, then restart the Runner docker compose restart, then follow the logs docker compose logs -f.

  • Look at Gitea to see newly registered runner

  • The Runner is now ready to accept jobs

Additional Notes

For jobs that build and push Docker containers to the Gitea registry, I found the “docker login” step (docker/login-action@v2) requires the host machine’s Docker to be aware of the Root CA (which Install and Configure Docker steps above ensure).

I found this Gitea blog post very helpful: Automating Release Versioning with Gitea Actions to the Gitea Package Registry.

From the blog post, the docker/setup-buildx-action@v2 step looks like this for me:

- name: Set up Docker BuildX
  uses: docker/setup-buildx-action@v2
  with:
    config-inline: |
      [registry."gitea.mydomain.com"]
        ca=["/etc/ssl/certs/ca-certificates.crt"]   

Options http = true and insecure = true are not needed for my case. Build and push (docker/build-push-action@v4) occur over HTTPS successfully.