SSH (Gitea) with Traefik V2

So for the last couple days I've been trying to get traefik and gitea to play nicely concerning the routing of gitea's ssh endpoint. It works if I don't route ssh via traefik at all, but as soon as I try to route it via traefik, I'll always get an error:

Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Here are my configs:
Traefik docker-compose.yml

version: "3"

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - 80:80
      - 443:443
      - 53:53/udp
      - 53:53/tcp
      - 8080:8080
      - 2222:2222/tcp
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/traefik.yml:ro
      - ./acme.json:/acme.json
      - ./config:/configurations
      - traefik-logs:/var/log/traefik
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=${TZ}
      - CF_API_EMAIL=${CF_API_EMAIL}
      - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
    labels:
      - traefik.enable=true
      - traefik.docker.network=proxy
      - traefik.http.routers.traefik-secure.entrypoints=websecure
      - traefik.http.routers.traefik-secure.rule=Host(`${FQDN}`)
      - traefik.http.routers.traefik-secure.service=api@internal
      - traefik.http.routers.traefik-secure.middlewares=user-auth@file,safe-ipwhitelist@file
      - traefik.http.routers.whoami-secure.service=noop@internal
      - traefik.http.routers.whoami-secure.tls.domains[0].main=${MAIN_DOMAIN}
      - traefik.http.routers.whoami-secure.tls.domains[0].sans=${SANS_DOMAIN}
      - traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://${AUTHELIA_FQDN}/
      - traefik.http.middlewares.authelia.forwardauth.trustforwardheader=true
      - traefik.http.middlewares.authelia.forwardauth.authresponseheaders=Remote-User, Remote-Groups

networks:
  proxy:
    external: true
volumes:
  traefik-logs:

Traefik traefik.yml (excerpt)

entryPoints:
  web:
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https

  websecure:
    address: :443
    http:
      middlewares:
        - secureHeaders@file
        - crowdsec-bouncer@file
      tls:
        certResolver: cloudflare

  ssh:
    address: :2222

Gitea docker-compose.yml

version: "3"

services:
  gitea-db:
    image: postgres:alpine
    container_name: gitea-db
    networks:
      - gitea
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    restart: unless-stopped
    environment:
      - TZ=${TZ}
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PW}
      - POSTGRES_DB=${DB_NAME}

  gitea:
    image: gitea/gitea:1.16.8
    container_name: gitea
    networks:
      - gitea
      - proxy
    environment:
      - TZ=${TZ}
      - DOMAIN=${FQDN}
      - ROOT_URL=https://${FQDN}
      - START_SSH_SERVER=true
      - SSH_DOMAIN=${FQDN}
      - SSH_PORT=22
      - SSH_LISTEN_PORT=2222
      - DB_TYPE=postgres
      - DB_HOST=${DB_HOST}
      - DB_NAME=${DB_NAME}
      - DB_USER=${DB_USER}
      - DB_PASSWD=${DB_PW}
    depends_on:
      - gitea-db
    volumes:
      - ./data/gitea:/data
    labels:
      - traefik.enable=true
      - traefik.docker.network=proxy
      - traefik.http.routers.gitea-secure.rule=Host(`${FQDN}`)
      - traefik.http.routers.gitea-secure.entrypoints=websecure
      - traefik.http.routers.gitea-secure.service=gitea
      - traefik.http.services.gitea.loadbalancer.server.port=3000
      - traefik.tcp.routers.gitea-ssh.rule=HostSNI(`*`)
      - traefik.tcp.routers.gitea-ssh.entrypoints=ssh
      - traefik.tcp.routers.gitea-ssh.service=gitea-ssh-svc
      - traefik.tcp.services.gitea-ssh-svc.loadbalancer.server.port=2222

networks:
  gitea:
  proxy:
    external: true

With this, I can access gitea via my browser and get clone links that look like this

git@gitea.mydomain.com:choque/Test.git

But when I try to clone it via

git clone git@gitea.mydomain.com:choque/Test.git

I get the error posted at the beginning. And yes, the ssh key is added to my profile and like I said, it works when I don't route gitea's ssh service through traefik.

Any help is appreciated!

Pretty sure this is gitea configuration related:

Serving on :222 working configuration

  gitea:
    image: gitea/gitea
    container_name: gitea
    deploy:
      replicas: 1
      labels:
        traefik.enable: "true"
        traefik.http.routers.gitea.rule: Host(`gitea.example.com`)
        traefik.http.services.gitea.loadBalancer.server.port: 3000
        traefik.tcp.routers.gitea-ssh.entrypoints: git
        traefik.tcp.routers.gitea-ssh.rule: HostSNI(`*`)
        traefik.tcp.services.gitea-ssh.loadbalancer.server.port: 22
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__repository__ENABLE_PUSH_CREATE_ORG=true
      - GITEA__server__OFFLINE_MODE=true
      - GITEA__server__ROOT_URL=https://gitea.example.com/
      - GITEA__server__SSH_PORT=222
      - GITEA__service__DISABLE_REGISTRATION=true
      - GITEA__service__REQUIRE_SIGNIN_VIEW=true
      - GITEA__service__DEFAULT_ALLOW_CREATE_ORGANIZATION=false
      - GITEA__service__DEFAULT_ENABLE_TIMETRACKING=false
      - GITEA__oauth2_client__ENABLE_AUTO_REGISTRATION=true
      - GITEA__oauth2_client__OPENID_CONNECT_SCOPES=email profile
      - GITEA__oauth2_client__USERNAME=email
      - GITEA__openid__ENABLE_OPENID_SIGNIN=false
2 Likes

Thanks for the reply @cakiwi . It works that way but as a result the git urls have ssh:// and the port added to them. So they look like this

ssh://git@gitea.mydomain.com:2222/choque/Test.git

When you set GITEA__server__SSH_PORT to 22 it results in much nicer URLs

git@gitea.mydomain.com:choque/Test.git

That's why I tried setting GITEA__server__SSH_PORT to 22 and GITEA__server__SSH_LISTEN_PORT to 2222. But I can't get it to work that way. I even tried using the built in ssh server via setting GITEA__server__START_SSH_SERVER to true

Anyone got an idea or a working configuration that does what I described?