Self-Hosting Gitea: Docker Setup with Web and SSH Public Access via Cloudflare Tunnel
This guide will walk you through the process of setting up Gitea using Docker on an Ubuntu server and making it accessible via Cloudflare Tunnel.
Prerequisites
- A system running Ubuntu
- A user account with sudo privileges
- Terminal access
Installation Steps
1. Install Docker on server
Please refer to the Server Setup - Install Docker on Ubuntu guide for detailed instructions on how to install Docker on your Ubuntu server.
2. Install/Configure Cloudflare Tunnel on server
Make sure you have a domain added to your Cloudflare account and install the Cloudflare Tunnel on your server, please refer to the Cloudflare Tunnel guide for detailed instructions on how to install Cloudflare Tunnel on your Ubuntu server.
You can first create a tunnel named gitea
and run it on your server.
3. Docker install Gitea
Here is a offical page of Gitea Docker Installation. But you can also follow the steps below to install Gitea.
3.1 Create a user git
on your server to do SSH Container Passthrough
A. Create a user git
and set the user ID to an unused ID, for example 1001
.
1
sudo adduser git -u 1001
Note:
a. Just create a user
git
and you do NOT have to do the following steps with login asgit
user.b. You can use
id git
to check the user ID and group ID of the usergit
.
B. Create an SSH key pair on the host machine. This key pair will be used to authenticate the git user when connecting from the host to the container. Run the following command as a user with sudo privileges:
1
sudo -u git ssh-keygen -t rsa -b 4096 -C "Gitea Host Key"
C. Add the public key of the key you created above (“Gitea Host Key”) to /home/git/.ssh/authorized_keys
.
1
2
sudo -u git cat /home/git/.ssh/id_rsa.pub | sudo -u git tee -a /home/git/.ssh/authorized_keys
sudo -u git chmod 600 /home/git/.ssh/authorized_keys
D. Create a fake host gitea command that will forward commands from the host to the container.
1
2
3
4
5
cat <<"EOF" | sudo tee /usr/local/bin/gitea
#!/bin/sh
ssh -p 2222 -o StrictHostKeyChecking=no [email protected] "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"
EOF
sudo chmod +x /usr/local/bin/gitea
3.2 Install Gitea with Docker
A. Create a directory for gitea installation, for example /opt/gitea
.
B. Create a docker-compose.yml
file in the directory /opt/gitea
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
services:
server:
image: docker.io/gitea/gitea:latest
environment:
- USER_UID=1001 # Set the user ID to the same as the user you created in step 3.1
- USER_GID=1001 # Set the group ID to the same as the user you created in step 3.1
- GITEA__database__DB_TYPE=mysql
- GITEA__database__HOST=db:3306
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea_password
restart: always
volumes:
- /home/git/.ssh/:/data/git/.ssh
- ./data:/var/lib/gitea
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000" # Web port mapping HOST:CONTAINER
- "127.0.0.1:2222:22" # SSH port mapping HOST:CONTAINER
depends_on:
- db
db:
image: mysql:8
restart: always
environment:
- MYSQL_ROOT_PASSWORD=gitea
- MYSQL_USER=gitea
- MYSQL_PASSWORD=gitea_password
- MYSQL_DATABASE=gitea
volumes:
- ./mysql:/var/lib/mysql
C. Run the docker-compose.yml
file to install Gitea.
1
docker compose up -d
Now when you curl localhost:3000
, you should see the Gitea web page.
4. Configure Cloudflare Tunnels for Gitea
Suppose your domain is yourgitea.com
. On the Cloudflare dashboard, navigate to Zero Trust > Networks > Tunnels to find the tunnel gitea
you created, then add following public names for web and ssh.
A. HTTP Tunnel for Gitea Web
- Subdomain:
gitea_web
(or any subdomain you want) - Type:
HTTP
- URL:
localhost:3000
(this should match the web port mapping in your docker-compose.yml)
Now you can access your Gitea web interface at https://gitea_web.yourgitea.com
. Please initialize the database and create an admin user following the web page instructions. After initialization, now you should be able to create a new repository.
If you create a repository named first-repo
, you should be able to access it by the HTTP link Gitea provided, something like https://gitea_web.yourgitea.com/${your_username}/first-repo.git
.
But now the ssh link like git@gitea_web.yourgitea.com:${your_username}/first-repo.git
is not accessible externally.
B. SSH Tunnel for Gitea SSH
- Subdomain:
gitea_ssh
(or any subdomain you want) - Type:
SSH
- URL:
localhost:2222
(this should match the ssh port mapping in your docker-compose.yml)
Now we have a domain gitea_ssh.yourgitea.com
which binds to the server port 2222
.
5. Add public SSH key to the Gitea
A. Generate a public SSH key on your local machine. For example, ~/.ssh/id_rsa.pub
.
B. Enter the Gitea web interface, click your avatar to Settings
-> SSH/GPG Keys
, and add the public key you created above.
C. After you add the public key, you can see a key has been added into the Sever’s /home/git/.ssh/authorized_keys
file, something like:
1
2
# gitea public key
command="/usr/local/bin/git ...
6. Configure SSH conifg on your local machine
A. Create a ~/.ssh/config
file on your local machine if it does not exist.
B. Add the following content to the ~/.ssh/config
file.
1
2
3
4
5
Host gitea_web.yourgitea.com # match the subdomain configured for HTTP (Gitea domain)
HostName gitea_ssh.yourgitea.com
User git
IdentityFile ~/.ssh/id_rsa
ProxyCommand ${cloudflared_path} access ssh --hostname %h # cloudflared_path is the path to the cloudflared executable (e.g. /usr/local/bin/cloudflared)
Now you should be able to use git clone git@gitea_web.yourgitea.com:${your_username}/first-repo.git
to clone the repository.
Conclusion
You now have a fully functional, self-hosted Gitea instance with:
- Secure web access through Cloudflare Tunnel
- SSH support for Git operations
- MySQL database for data persistence
- Automatic container restarts
This setup provides a robust, private Git server that’s securely accessible from anywhere while being protected by Cloudflare’s security features.