Deploying Gitea with SSH on Pangolin + Newt

Guide: Deploying Gitea with SSH on Pangolin + Newt

1. Architecture

  • Client → connects to git.example.com over HTTPS or SSH.
  • Pangolin VPS → public‑facing reverse proxy, terminates TLS, manages identity & access.
  • Newt agent → runs inside your private infra (LXC/VM), establishes a WireGuard tunnel to Pangolin, and proxies traffic to local services.
  • Gitea → runs locally (Docker or native) on the same host as Newt, reachable only via the tunnel.

Flow:
Client → Pangolin (public) → WireGuard tunnel (Newt) → Gitea (private)


2. Run Gitea Locally

Example docker-compose.yml on your private LXC/VM:

networks:
  gitea:
    external: false

services:
  server:
    image: docker.gitea.com/gitea:1.24.6
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: unless-stopped
    networks:
      - gitea
    volumes:
      - /mnt/gitea/:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "2222:22"

3. Configure Gitea (app.ini)

[server]
DOMAIN           = git.example.com
ROOT_URL         = https://git.example.com/
SSH_DOMAIN       = git.example.com
DISABLE_SSH      = false
SSH_PORT         = 2222
SSH_LISTEN_PORT  = 22

4. Deploy Newt

Run Newt alongside Gitea. Example docker-compose.yml service:

services:
  newt:
    image: fosrl/newt
    container_name: newt
    restart: unless-stopped
    environment:
      - PANGOLIN_ENDPOINT=https://pangolin.example.com
      - NEWT_ID=<your-newt-id>
      - NEWT_SECRET=<your-newt-secret>
      - HEALTH_FILE=/tmp/healthy
  • NEWT_ID and NEWT_SECRET are generated in Pangolin when you register the Newt client.
  • Newt automatically sets up the WireGuard tunnel and proxies traffic to your local Gitea ports.

5. Configure Pangolin Resources

In Pangolin’s dashboard:

  • HTTP Resource

    • Domain: git.example.com
    • Target: newt://gitea:3000 (Newt proxies to local Gitea web UI)
  • TCP Resource

    • External Port: 23 (or your liking)
    • Target: newt://gitea:2222 (Newt proxies to Gitea’s SSH)

Pangolin will handle TLS certificates (via Let’s Encrypt) and identity‑aware access control.


6. Client SSH Config

Add to ~/.ssh/config:

Host gitea
    HostName git.example.com
    Port 2222
    User git
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Test:

ssh -T gitea

Expected:

Hi <username>! You've successfully authenticated, but Gitea does not provide shell access.

7. Pitfalls & Fixes

Pitfall Symptom Fix
Forgot to register Newt in Pangolin No tunnel, resource unreachable Generate NEWT_ID + NEWT_SECRET in Pangolin
Wrong SSH_PORT vs LISTEN_PORT Connection works but auth fails Keep LISTEN=22 inside, external port defined in Pangolin
UFW blocks WireGuard Tunnel never comes up Allow 51820/udp on VPS
Key not added in Gitea Permission denied (publickey) Add .pub key in Gitea UI
Using port 23 Some ISPs/firewalls block it Prefer high port like 2222

8. Security Best Practices

  • Keep VPS SSH separate from Gitea SSH.
  • Restrict Pangolin access with CrowdSec or IP rules.
  • Regularly update Gitea, Newt, and Pangolin.
  • Use Pangolin’s identity features (SSO, RBAC) for fine‑grained access.

:white_check_mark: With this setup:

  • Pangolin is the public gateway.
  • Newt is the **tunnel **.
  • Gitea stays private, only reachable through the newt tunnel.