Self-hosting Gitea with Cloudflare Tunnel for ssh
A simple walkthru of how I self host my gitea instance with nginx and cloudflare zero access to enable ssh.
Part 0: setting up gitea
Gitea binary
I do not want to host it using docker, so I went thru the binary installation route. Gitea already have a pretty decent how-to guide on their site, this part is mainly a copy-paste from their doc.
At the time of writing this blog post, the release version used was 1.25.3, and the server used was running debian 13:
wget -O gitea https://dl.gitea.com/gitea/1.25.3/gitea-1.25.3-linux-amd64
chmod +x gitea
mv gitea /usr/local/bin/gitea
creating a dedicated user for gitea to be run as:
adduser \ --system \ --shell /bin/bash \ --gecos 'Git Version Control' \ --group \ --disabled-password \ --home /home/git \ gitcreating the directories:
mkdir -p /var/lib/gitea/{custom,data,log} chown -R git:git /var/lib/gitea/ chmod -R 750 /var/lib/gitea/ mkdir /etc/gitea chown root:git /etc/gitea chmod 770 /etc/giteato run
giteausing systemd, we can download the samplegitea.servicefrom the gitea repo:wget -O /etc/systemd/system/gitea.service https://github.com/go-gitea/gitea/raw/refs/heads/release/v1.25/contrib/systemd/gitea.service systemctl daemon-reload systemctl enable gitea --now
DB setup
per gitea’s official documentation:
Be aware that SQLite does not scale; if you expect your instance to grow at a later time, you should choose another database type.
to future proof our instance, I chose to use postgresql 18:
apt install -y postgresql-common
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
apt install postgresql-18
login to the db using su -c "psql" - postgres, and create gitea role and giteadb database:
CREATE ROLE gitea WITH LOGIN PASSWORD '<your-password>';
CREATE DATABASE giteadb WITH OWNER gitea TEMPLATE template0 ENCODING UTF8 LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';
you will also need to modify the pg_hba.conf located at /etc/postgresql/18/main/pg_hba.conf:
local giteadb gitea scram-sha-256
you can test your db connection with psql -U gitea -d giteadb
from the doc: Rules on
pg_hba.confare evaluated sequentially, that is the first matching rule will be used for authentication. Your PostgreSQL installation may come with generic authentication rules that match all users and databases. You may need to place the rules presented here above such generic rules if it is the case.
Reverse Proxying with Nginx
here’s my nginx config:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
ssl_certificate <path-to-cert>;
ssl_certificate_key <path-to-privkey>;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_session_tickets off;
ssl_stapling off;
ssl_stapling_verify off;
server_name <your-server-name>;
location / {
client_max_body_size 512M;
proxy_pass http://localhost:3000;
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
now you can go to yoursite and start the gitea setup, we will be changing the ssh domain for gitea later. The config file is located at /etc/gitea/app.ini. The list of configurable options can be found here.
Part 1: setting up cloudflared
the web interface and https based git are proxied by cloudflare, but we will need argo tunnels for ssh based accesses.
we will mainly be following this guide from cloudflare.
Creating an application
we will need to create an application on Cloudflare ZeroTrust, go to Access Controls -> Applications, and add an application there with the application hostname you intended to use and access policies. we can keep everything else default.
Getting the latest cloudflared binary
download deb
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb dpkg -i cloudflared-linux-amd64.debsetting up systemd for it
cloudflared service installlog in to your cf account and create a new tunnel, it will assign a uuid that we need later:
cloudflared login cloudflared tunnel create giteaconfigure the tunnel
vim ~/.cloudflared/config.yml:tunnel: <uuid> credentials-file: /root/.cloudflared/<uuid>.json ingress: - hostname: git-ssh.example.com service: ssh://localhost:22 # Catch-all rule, which just responds with 404 if traffic doesn't match any of # the earlier rules - service: http_status:404valid your tunnel config using
cloudflared tunnel ingress validateand bring it up withsystemctl start cloudflared(orcloudflared tunnel run)
Creating DNS records
add a cname record pointing to <uuid>.cfargotunnel.com with the hostname you intended to use.
Updating the gitea’s app.ini
under [server], update SSH_DOMAIN to the hostname you intend to use, then restart gitea using systemctl restart gitea.
Part 2: Client setup
upload your ssh public key to the gitea instance in
example.com/user/settings/keys.follow the instructions above to get the latest
cloudflaredbinaryappend
~/.ssh/configwith the following:Host git-ssh.example.com ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %hattempt to git clone a new repo would prompt you to authenticate
git clone [email protected]:test/test