Accessing the Forgejo Web UI

How to open the Forgejo web interface of a parallel-services environment, whether it's running locally under Docker Compose or on AWS (EKS). Forgejo is the worked example from the parallel-services-guide.md; the same approach applies to any HTTP service in the environment.

Locally (Docker Compose)

When you run the app's docker-compose services on your machine, Forgejo is reachable on whatever host port the compose file maps to its container port (3000). For example, a ports: ["3080:3000"] mapping gives:

http://localhost:3080

On AWS (parallel namespace)

On AWS the service runs in the isolated namespace wbsp-svc-‹tenant›-‹env› and is internal-only — there is no public URL, and a NetworkPolicy denies all ingress except the allow-listed apps. To reach it from your machine, port-forward the cluster service. kubectl port-forward tunnels through the Kubernetes API server, so it works regardless of the NetworkPolicy:

export AWS_PROFILE=<profile>
aws eks update-kubeconfig --name <cluster> --region <region>   # once

kubectl -n wbsp-svc-‹tenant›-‹env› port-forward svc/forgejo 3080:3000

Then open:

http://localhost:3080

Git access (clone / push / pull)

Forgejo serves git over HTTP (on its web port, 3000) and SSH (on port 22). You clone/push against whatever host and port you actually reach Forgejo on — the forwarded local port — regardless of the URL Forgejo displays in its UI (that reflects its configured ROOT_URL).

HTTP

# Locally (web port mapped to, e.g., 3080)
git clone http://localhost:3080/‹owner›/‹repo›.git

# On AWS — forward the web port first, then clone
kubectl -n wbsp-svc-‹tenant›-‹env› port-forward svc/forgejo 3080:3000
git clone http://localhost:3080/‹owner›/‹repo›.git

Pushing over HTTP requires credentials. Use a Forgejo username with a personal access token (or password) — either let git prompt, or inline it:

git clone http://‹user›:‹token›@localhost:3080/‹owner›/‹repo›.git

SSH

SSH needs the container's port 22 exposed. Locally that's whatever your compose file maps it to (e.g. "2222:22"); on AWS, port-forward it. The SSH user is always git, and your public key must be registered in Forgejo first (User Settings → SSH / GPG Keys).

# Locally (SSH mapped to, e.g., 2222)
git clone ssh://git@localhost:2222/‹owner›/‹repo›.git

# On AWS — forward the SSH port, then clone
kubectl -n wbsp-svc-‹tenant›-‹env› port-forward svc/forgejo 2222:22
git clone ssh://git@localhost:2222/‹owner›/‹repo›.git

Once cloned, the remote stays pointed at the forwarded address, so git push / git pull work as long as the relevant kubectl port-forward is running. You can forward the web and SSH ports at the same time (in separate shells).

Notes

  • First visit on AWS may show the install page. Don't complete it via the web form (see Troubleshooting). Instead configure Forgejo with FORGEJO__* environment variables in the compose service and set FORGEJO__security__INSTALL_LOCK=true so it skips the installer entirely.
  • Ephemeral storage. If the environment definition sets ephemeral_storage: true (used when the cluster has no persistent-volume provisioner), any state in the AWS Forgejo's /data volume is lost on pod restart. With env-based config this is fine — Forgejo regenerates its app.ini from the env on each start; persistent state lives in the database.

Troubleshooting

The database settings are invalid: dial tcp 127.0.0.1:5432: connect: connection refused

Forgejo is trying to reach Postgres on 127.0.0.1, but Postgres is a separate container/podlocalhost inside Forgejo is Forgejo itself. The DB connection is made server-side (from the Forgejo pod), so point it at the service name, not the address you reach the UI on:

  • Host: postgres:5432 (the compose service / Kubernetes Service name in the same network/namespace) — not 127.0.0.1.
  • Username / Password / Database: the values the compose postgres service provisions for Forgejo (e.g. forgejo / forgejo / forgejo).

Failed to save configuration: open /data/gitea/conf/app.ini: is a directory

The installer needs to write app.ini, but in a parallel-services environment a bind-mounted config file is mounted as a read-only ConfigMap, so Forgejo can't write it (the read-only mount surfaces as is a directory).

Don't use the web installer. Configure Forgejo via environment variables and remove the app.ini bind-mount, so Forgejo writes its own config into its writable /data volume at startup:

forgejo:
  environment:
    - FORGEJO__database__DB_TYPE=postgres
    - FORGEJO__database__HOST=postgres:5432
    - FORGEJO__database__NAME=forgejo
    - FORGEJO__database__USER=forgejo
    - FORGEJO__database__PASSWD=forgejo
    - FORGEJO__security__INSTALL_LOCK=true
    - FORGEJO__server__ROOT_URL=http://localhost:3080/
  volumes:
    - forgejo-data:/data
    # - ./docker/forgejo/app.ini:/data/gitea/conf/app.ini   ← remove this line

The Forgejo image's entrypoint runs environment-to-ini, writing those FORGEJO__section__key values into app.ini on the writable volume; this works both locally and in the parallel namespace. Re-apply and restart:

wbsp-app services up --config <env-def>.yaml --prune
kubectl -n wbsp-svc-‹tenant›-‹env› rollout restart deploy/forgejo

This reflects a parallel-services limitation: bind-mounted config files are mounted read-only, which suits files an app only reads but breaks apps that need to write their config file (like Forgejo's app.ini). Driving config through env vars avoids the mount entirely.

See also: parallel-services-guide.md · useful-commands.md.