Self-Hosted Services and ProductivityService Portals and MediaIntermediate60-120 minutesLab

Build a Lightweight Internal Git and Script Catalog with Gitea

Run a small Gitea instance from the current rootless container image, keep the web service behind an internal HTTPS boundary, and prove the catalog by creating, cloning, and...

Last reviewed8/19/2026
Gitea script catalogs
Gitea 1.27Docker Compose v2GitHTTPS reverse proxy

Expected Outcome

A working internal Gitea script catalog with persistent data/config volumes, a private repository, and a validated clone-edit-push workflow over the intended internal URL.

Assumptions

  • A Linux host with Docker Engine and Docker Compose v2.

  • An internal DNS name such as `git.example.internal` and an HTTPS reverse proxy if the catalog will be used from other machines.

  • Git installed on a separate workstation for clone/push validation.

  • Enough storage to retain Gitea repositories and configuration outside the container lifecycle.

Bill of Materials

  • Current Gitea rootless container image from `docker.gitea.com`.

  • An internal TLS certificate path trusted by the workstations that will use the catalog.

  • One small non-sensitive test script and README.

Build Steps

  1. Verify Compose v2 and create the service directory

    Gitea's current Docker documentation uses Compose v2. Do not install the retired standalone docker-compose package.

    Changes system state: review before running

    docker --version
    docker compose version
    mkdir -p ~/gitea-script-catalog && cd ~/gitea-script-catalog
  2. Create a rootless Gitea Compose definition

    Use the current stable rootless Gitea image and named volumes so Docker owns volume permissions. Bind the web port to localhost and let an internal reverse proxy provide HTTPS. Replace the example domain if you will use the service remotely.

    Read-only command: verify target and scope

    cat > compose.yaml <<'EOF'
    services:
      server:
        image: docker.gitea.com/gitea:1.27.1-rootless
        restart: unless-stopped
        environment:
          GITEA__server__DOMAIN: git.example.internal
          GITEA__server__ROOT_URL: https://git.example.internal/
        volumes:
          - gitea-data:/var/lib/gitea
          - gitea-config:/etc/gitea
        ports:
          - "127.0.0.1:3000:3000"
    volumes:
      gitea-data:
      gitea-config:
    EOF
    docker compose config --quiet
  3. Start Gitea and validate the local service

    Start the container and confirm Gitea responds locally before configuring DNS, TLS, or repositories.

    Changes system state: review before running

    docker compose pull
    docker compose up -d
    docker compose ps
    curl -I http://127.0.0.1:3000/
  4. Complete the initial Gitea setup

    Open the service through the intended internal HTTPS URL once the reverse proxy is configured. For this small Lab, use the built-in SQLite database, create the administrator account, and keep self-registration disabled unless you explicitly need it. Record the chosen site URL and data/config volume names as part of the Lab evidence.

  5. Create a private scripts repository

    Create a repository such as ops-scripts, mark it private, and add a short description that states what kinds of scripts belong there. Avoid placing live passwords, API tokens, private keys, or unredacted production exports in the repository.

  6. Clone and initialize the catalog from a workstation

    Clone over the HTTPS URL trusted by the workstation. Create a README and one harmless script, explicitly normalize the branch to main, then push the first commit.

    Changes system state: review before running

    git clone https://git.example.internal/<user>/ops-scripts.git
    cd ops-scripts
    printf '# Ops Scripts\n\nSmall reviewed scripts for the internal Lab catalog.\n' > README.md
    printf '#!/usr/bin/env bash\nprintf \"catalog validation\\n\"\n' > catalog-check.sh
    chmod +x catalog-check.sh
    git add README.md catalog-check.sh
    git commit -m 'Add initial catalog example'
    git branch -M main
    git push -u origin main
  7. Prove the repository is usable from a clean path

    Clone the repository into a second temporary directory and run the harmless test script. This catches URL, authentication, certificate, repository visibility, and branch mistakes that the Gitea dashboard alone cannot prove.

    Changes system state: review before running

    cd ..
    git clone https://git.example.internal/<user>/ops-scripts.git ops-scripts-validation
    cd ops-scripts-validation
    git status --short --branch
    ./catalog-check.sh
  8. Record the persistent-state boundary

    Gitea's repositories, database, secrets, and configuration live in the persistent data/config volumes, not in the disposable container image. Before upgrades or migration, back up those volumes according to your Docker/storage platform and preserve Gitea's generated security secrets with the configuration.

Validation

  • `docker compose ps` shows the Gitea service running and the local HTTP endpoint responds.

  • The internal HTTPS URL presents a trusted certificate when used from another workstation.

  • The `ops-scripts` repository is private and can be cloned by an authorized user.

  • A commit pushed to `main` appears in Gitea and a clean second clone can run the harmless validation script.

  • The operator can identify the Gitea data/config volumes that must be protected before upgrades or host replacement.

Troubleshooting

  • If Gitea starts but clients receive redirects to the wrong host or scheme, verify `GITEA__server__DOMAIN`, `GITEA__server__ROOT_URL`, and the reverse-proxy forwarding configuration before changing repository settings.

  • If HTTPS Git operations fail but the web UI works, inspect the workstation's certificate trust and the exact clone URL before weakening TLS verification.

    Read-only command: verify target and scope

    git remote -v
    curl -I https://git.example.internal/
  • If the container cannot write its storage, inspect the named volume/mount configuration and Gitea logs. Do not solve a volume problem with `chmod 777`.

    Read-only command: verify target and scope

    docker compose logs --tail=120 server
    docker volume ls | grep gitea

Cleanup or Rollback

  • Remove the temporary `ops-scripts-validation` clone after the Lab if it is not needed.

  • Stop the service with `docker compose down` when the Lab is not in use; do not add `-v` unless you deliberately intend to destroy the persistent repositories/configuration.

  • Before deleting the Lab, preserve a tested backup of the Gitea data/config volumes if the script catalog matters.

Next Improvements

  • Add repository templates, CODEOWNERS/review practices, or issue labels only after the basic clone/push workflow is stable.

  • Add scheduled backup and restore testing for Gitea persistent state.

  • Integrate CI only for scripts whose test and execution boundaries are understood.

References

Keep Moving

Build on what you just completed

Continue with a related Lab or return to this build path for a different implementation.