I am almost giving up, Traefik 2 and gitea ssh

I’ve spent days trying to figure out how to make gitea ssh work with traefik.
I’ve read many posts about this, still theese didn’t help me.
I am not even sure it’s a traefik issue at this point, probably i am just too dumb to make it work.

My goal is to use port 22 on gitea, avoidoing ssh:// urls.
My docker host have sshd configured to listen on 2222 so there should’t be conflict.

Preassumption:
a public ssh key added to gitea which matches the private key on my local machine.
My local ssh config looks like this:

Host gitea
  HostName gitea.example.com
  User git
  port 22
IdentityFile ~/.ssh/gitea

Now, if i did understood this correctly, when i push to a repo git@gitea.example.com:giteadmin/test.git through ssh, this should happen:

my local machine → traefik → traefik redirect to gitea domain gitea.example.com:22 → gitea ssh server accepting the connection.

I get this error:

ssh: connect to host gitea.example.com port 22: Connection refused
fatal: Could not read from remote repository.

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

Which leads me to believe that i can in fact reach Gitea with ssh

my docker-compose for gitea:

networks:
  gitea:
    external: false
  traefik:
    external: true

services:
  server:
    image: gitea/gitea:1.19.0
    container_name: gitea
    env_file:
      - stack.env
    restart: always
    networks:
      - gitea
      - traefik
    volumes:
      - /cpd/gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    depends_on:
      - db
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.gitea-web.rule=Host(`gitea.example.com`)"
      - "traefik.http.routers.gitea-web.entrypoints=websecure"
      - "traefik.http.routers.gitea-web.middlewares=secureHeaders@file"
      - "traefik.http.routers.gitea-web.tls=true"
      - "traefik.http.routers.gitea-web.service=gitea-web-svc"
      - "traefik.http.services.gitea-web-svc.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.address=gitea.example.com:22"
      
  db:
    image: mysql:8
    container_name: giteadb
    restart: always
    env_file:
      - stack.env
    networks:
      - gitea
    volumes:
      - /cpd/gitea/mysql:/var/lib/mysql

my traefk static config

log:
  level: DEBUG
api:
  dashboard: true
entryPoints:
  web:
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure
  websecure:
    address: :443
  ssh:
    address: :22
serversTransport:
  insecureSkipVerify: true
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    network: traefik
  file:
    directory: /dconfig
    watch: true
certificatesResolvers:
  cloudflare:
    acme:
      email: xxx
      storage: /acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

my traefik docker-compose

version: "2.2"
services:
  traefik:
    image: traefik:2.10
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - traefik
    ports:
      - 80:80
      - 443:443
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro 
      - ./config/traefik.yml:/traefik.yml:ro  
      - ./config/dconfig:/dconfig  
      - ./config/acme.json:/data/ 
    environment:
      - CF_API_EMAIL= xxx
      - CF_DNS_API_TOKEN= xxx
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik-secure.entrypoints=websecure"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.traefik-secure.service=api@internal"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
      - 'traefik.http.routers.traefik-secure.tls.domains[0].main=example.com'
      - 'traefik.http.routers.traefik-secure.tls.domains[0].sans=*.example.com'   

networks:
  traefik:
    external: true
    name: traefik

For the love of god, help me please, point me in the right direction, give me some light in this dark moment.

p.s
I’ve also reached letsencrypt limit restarting traefik… now i have to wait till the 5th of may…
yes i forgot to seput the staging envirorment.

Shouldn’t traefik expose port 22:22 in your configuration? Also, I don’t see why you don’t just expose port 22:22 right on Gitea container (I don’t have much experience with Docker, but putting it behind traefik doesn’t seem to add any security).

Hello Jake, thank you.

To my understanding ( i may be wrong ), once you put a service behind a proxy you have to route in some way clients connecting to those services, to any port they expose.
Since gitea.example.com has now the ip of the proxy, i have to pass through it whether i connect to port 3000 or to port 22, so when i am kind of forced to pass through traefik.

I will try to bind port 22 to traefik, it makes sense.