Gitea is a self-hosted, open-source Git service similar to GitHub, but lightweight, free, and perfect for personal or local setups.
While the official Gitea installation guide is simple, the process you'll see here might seem a bit extra - and that's because I wanted something very specific.
Let's put it this way: I wanted to run my own local github.com, completely offline.
My top priority was to host everything locally on my own network, where the host and client machines could communicate both wirelessly (through a Wi-Fi router) and directly through a LAN cable (peer-to-peer).
I like to keep backups of my personal data in multiple places - one of which is a Fedora machine.
Before setting this up, I used to sync data from my main machine (also running Fedora) to the backup machine using FTP and FileZilla. It worked, but it was tedious - I had to manually track every single change until I synced them.
That's when I thought: why not use Git for this?
I just didn't want anything in the cloud. So setting up my own self-hosted Git server locally made perfect sense.
It's a major security best practice to run services like Gitea under a dedicated user account, not as an administrator/root.
Open a terminal and run:
# Add new group
sudo groupadd --system git
# Add new user
sudo adduser \
--system \
--shell /bin/bash \
--comment 'Git' \
--gid git \
--home-dir /home/git \
--create-home \
git-
Create required directory structure
sudo mkdir -p /var/lib/gitea/{custom,data,log} sudo chown -R git:git /var/lib/gitea/ sudo chmod -R 750 /var/lib/gitea/ sudo mkdir /etc/gitea sudo chown root:git /etc/gitea sudo chmod 770 /etc/gitea -
Download the latest Gitea binary
Check for the latest version for your OS type here (usually it's
amd64) and then replace the<version>below with the actual version number.sudo mkdir -p /usr/local/bin/gitea sudo wget -O /usr/local/bin/gitea/gitea https://dl.gitea.com/gitea/<version>/gitea-<version>-linux-amd64 sudo chmod +x /usr/local/bin/gitea/gitea
This will start Gitea server automatically on boot.
-
Create a service file
sudo nano /etc/systemd/system/gitea.service
-
Copy the sample gitea.service file
Make sure to use the same release version as your Gitea binary, then paste in the above
gitea.servicefile that we just opened in a nano editor. -
Fix the binary path in
ExecStartdirective# Change this ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini # To this (note the `gitea` binary added after the `gitea` directory) ExecStart=/usr/local/bin/gitea/gitea web --config /etc/gitea/app.ini
-
Save and close the file (
Ctrl+X,Y,Enter) -
Enable and start the Gitea Service
sudo systemctl enable gitea --now -
Verify the service is active
sudo systemctl status gitea
Go to http://localhost:3000 on your browser and you'll be presented with an Initial Configuration page from Gitea.
We'll use the bare minimum configuration at this point and leave the advanced configuration for the later steps:
- Database Type: SQLite3
- Site Title: GitShah (use whatever name you want or keep the default one)
- Check Enable Update Checker
- Click Install Gitea
Wait until the installation finishes and redirects you to the Register page.
Do not register for now and close the browser's tab.
As mentioned in the official Gitea installation guide:
/etc/giteais temporarily set with write permissions for usergitso that the web installer can write the configuration file. After the installation is finished, it is recommended to set permissions to read-only using:
sudo chmod 750 /etc/gitea
sudo chmod 640 /etc/gitea/app.ini-
For LAN
We'll have to set a static IP on both the client and server machines, which, in my case, is Fedora.
Follow the Configure Network Settings > On Fedora 43 section from here to configure the static IP on both machines.
On Fedora client machine use:
Address: 192.168.200.1 Netmask: 255.255.255.0On Fedora server machine use:
Address: 192.168.200.7 Netmask: 255.255.255.0 -
For WiFi
In the case of WiFi, you only need to set a static IP on the server machine.
First you need to find your WiFi router's IP using the command:
ip route | grep default.Let's assume it's
192.168.100.1like below:$ ip route | grep default default via 192.168.100.1 dev wlp2s0 proto dhcp src 192.168.100.125 metric 600which means, you can use the static IP within the same range e.g.,
192.168.100.x, wherexcould be any number from2to254.Just to be consistent with my server's LAN IP, I'll be using
192.168.100.7.Follow the same Configure Network Settings > On Fedora 43 section from here, but go to Wi-Fi instead of Network and enter the following values under IPv4 for your Wi-Fi connection:
Address: 192.168.100.7 Netmask: 255.255.255.0 Gateway: 192.168.100.1 DNS: 192.168.100.1
For the domain, I'll be using gitshah.com, use whatever you like.
-
On WiFi router
Login to your WiFi router's admin panel and find the Static DNS (or similar) settings and add:
gitshah.com → 192.168.100.7 www.gitshah.com → 192.168.100.7For example, my Huawei Router has below settings:
-
On Fedora server machine
Open
/etc/hostsfile:sudo nano /etc/hosts
Add line:
127.0.0.1 gitshah.com www.gitshah.com
Save and close the file (
Ctrl+X,Y,Enter). -
On Fedora client machine
Since we want
gitshah.comto be accessible on both LAN and WiFi - and we prefer LAN (because it's faster and has lower latency) when both are connected - we'll add both IPs in the/etc/hostsfile like this:192.168.200.7 gitshah.com www.gitshah.com # via LAN 192.168.100.7 gitshah.com www.gitshah.com # via WiFi
Now here's where it gets annoying: some applications and browsers (like Google Chrome) only use the first occurrence of a domain in
/etc/hostsand completely ignore any subsequent entries for the same domain. Others - likecurl,ping, or even Firefox - are smarter and just work fine.This means that in our case,
gitshah.comwill only resolve via LAN, since it's listed first.One way to handle this is to keep the LAN line commented out by default and manually toggle it - uncomment when LAN is connected, comment when it's not. Works fine, but it's repetitive and annoying as hell.
Another approach is to use something like mDNS (
dnsmasqor similar), but that's way too much machinery for something this simple. It adds multiple moving parts, and you'll have to modify each connection profile too. That's just not worth it for a small local setup like this.Personally, I think sticking with the plain old
/etc/hostsfile is far simpler and works right out of the box. If you're using Firefox, just keep both entries uncommented - it'll resolve whichever connection is active, no complaints.But if you're stuck with Google Chrome (like me), you'll quickly realize how much of a pain it is to manually toggle those entries every time your LAN cable connects or disconnects.
So yeah, we'll automate this with a simple NetworkManager dispatcher script - it's straightforward, reliable, and doesn't depend on any specific app or browser behavior.
-
Add domain mapping in
/etc/hostsOpen the file:
sudo nano /etc/hosts
Add:
#192.168.200.7 gitshah.com www.gitshah.com # via LAN 192.168.100.7 gitshah.com www.gitshah.com # via WiFi
It's important to keep the order of the IPs as above to try LAN first if it's connected.
-
Create a dispatcher script
Create a new shell script:
sudo mkdir -p /etc/NetworkManager/dispatcher.d sudo nano /etc/NetworkManager/dispatcher.d/99-gitshah-lan-monitor.sh
Put this inside:
#!/bin/bash IFACE="$1" STATE="$2" HOSTS_FILE="/etc/hosts" LAN_MARKER="via LAN" if [ "$IFACE" = "enp0s31f6" ]; then case "$STATE" in up) # Enable LAN line (remove #) sed -i "/$LAN_MARKER/s/^#//" "$HOSTS_FILE" logger -t gitshah-lan-monitor "LAN is UP → enabled LAN entry in $HOSTS_FILE" ;; down) # Disable LAN line (add # at start) sed -i "/$LAN_MARKER/s/^/#/" "$HOSTS_FILE" logger -t gitshah-lan-monitor "LAN is DOWN → disabled LAN entry in $HOSTS_FILE" ;; esac fi
Replace
enp0s31f6with your LAN interface (ip linkwill tell you).Make it executable:
sudo chmod +x /etc/NetworkManager/dispatcher.d/99-gitshah-lan-monitor.sh
-
Restart NetworkManager
sudo systemctl restart NetworkManager
Now, every time your LAN interface (i.e.,
enp0s31f6, in my case) goes up or down, NetworkManager will automatically toggle (uncomment/comment) the line ending withvia LANin/etc/hosts.You can also see the messages in your logs whenever the script triggers:
journalctl -t gitshah-lan-monitor
-
-
Create a Root CA
Create a private key for your CA:
openssl genrsa -out gitshahCA.key.pem 4096
Create a self-signed CA certificate (valid 10 years):
openssl req -x509 -new -nodes -key gitshahCA.key.pem -sha256 -days 3650 \ -out gitshahCA.cert.pem \ -subj "/C=PK/ST=Sindh/L=Karachi/O=GitShahCA/OU=Dev/CN=GitShah Root CA" -
Create a Server Key + CSR
Make a server private key:
openssl genrsa -out gitshah.key.pem 2048
Make a config file for your SANs:
# Open a new file nano san.cnf # Paste the following, then save and close the file [req] default_bits = 2048 default_md = sha256 prompt = no distinguished_name = req_distinguished_name req_extensions = req_ext [req_distinguished_name] CN = gitshah.com [req_ext] subjectAltName = @alt_names [alt_names] DNS.1 = gitshah.com DNS.2 = www.gitshah.com
Generate a certificate signing request (CSR):
openssl req -new -key gitshah.key.pem -out gitshah.csr.pem -config san.cnf
-
Sign the CSR with your Root CA
openssl x509 -req -in gitshah.csr.pem -CA gitshahCA.cert.pem -CAkey gitshahCA.key.pem \ -CAcreateserial -out gitshah.cert.pem -days 3650 -sha256 -extfile san.cnf -extensions req_ext
-
Copy the Certificate and Key Files
sudo mkdir /var/lib/gitea/custom/https sudo cp gitshah.cert.pem gitshah.key.pem /var/lib/gitea/custom/https
-
Change Ownership
sudo chown -R git:git /var/lib/gitea/custom/https
-
Update
app.iniOpen the file:
sudo nano /etc/gitea/app.ini
Go to the
[server]block and add/modify the following:PROTOCOL = https CERT_FILE = /var/lib/gitea/custom/https/gitshah.cert.pem KEY_FILE = /var/lib/gitea/custom/https/gitshah.key.pem DOMAIN = gitshah.com HTTP_PORT = 443 ROOT_URL = https://gitshah.com/ START_SSH_SERVER = true SSH_DOMAIN = gitshah.com SSH_PORT = 2222
Save and close the file (
Ctrl+X,Y,Enter). -
Open the firewall for HTTPS Traffic
Fedora has a firewall enabled by default. You must ensure port 443 (HTTPS) is open to traffic from your local network.
# Check the currently active services sudo firewall-cmd --list-all # Permanently add the HTTPS service to the firewall sudo firewall-cmd --add-service=https --permanent # Open firewall for our custom SSH port (2222) sudo firewall-cmd --add-port=2222/tcp --permanent # Reload the firewall to apply the changes sudo firewall-cmd --reload # Verify the service is added sudo firewall-cmd --list-all
You should now see
httpsand2222/tcpadded to the services and ports, respectively. -
Grant Capability to bind to privileged port (443)
We need to grant the binary special permissions to bind to a privileged port like
443.Open
gitea.servicefile:sudo nano /etc/systemd/system/gitea.service
Uncomment the following:
CapabilityBoundingSet=CAP_NET_BIND_SERVICE AmbientCapabilities=CAP_NET_BIND_SERVICE
Add the following at the end of the
[Service]section:# Security hardening and sandboxing (tweak if needed) NoNewPrivileges=true ProtectSystem=strict ProtectHome=true PrivateTmp=true PrivateDevices=true ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true LockPersonality=true RestrictRealtime=true # # Allow writes only to necessary dirs ReadWritePaths=/var/lib/gitea
Save and close the file (
Ctrl+X,Y,Enter). -
Reload
systemdDaemonsudo systemctl daemon-reload
-
Restart the Service
sudo systemctl restart gitea sudo systemctl status gitea # Verify it's running correctly -
Verify the SSH and HTTPS ports are listening
sudo ss -tlnp | grep -E '2222|443'
You should see an output similar to below:
LISTEN 0 4096 *:2222 *:* users:(("gitea",pid=20799,fd=12)) LISTEN 0 4096 *:443 *:* users:(("gitea",pid=20799,fd=13))
Use the following steps on both Fedora client and Fedora server machines:
-
Install Root CA into Fedora trust store
sudo cp gitshahCA.cert.pem /etc/pki/ca-trust/source/anchors/ sudo update-ca-trust
-
Verify
curl -v https://gitshah.com
If your service is running with that cert,
curlshould connect without complaining about an untrusted certificate. -
Restart your browser to apply.
Now, you should be able to access your Gitea server web interface using both https://gitshah.com and https://www.gitshah.com.
When you register your first account - it becomes admin.
-
Go to https://gitshah.com and click on the Register button on the top-right corner and register an account.
-
After you're signed in, click on your username on the top-right corner, click Settings > Profile > find User visibility option and set it to Private.
We'll only use the admin account for Gitea server management or if there's a need to manage other users and their repositories - but we won't create repositories/organizations from this account.
For a regular use, we'll register a user account, just like you would on GitHub/GitLab, and then create and manage repositories/organizations, etc.
Optional:
-
After you're signed in, if you configured optional mailer settings yourself in the fourth step (Initial Gitea Configuration) above, you can activate your account by clicking on your username on the top-right corner, click Settings > Account > under Manage Email Addresses section, click Send Activation.
-
You'll receive an activation link on your email (check spam if not), but it may not activate your account when you are already signed in (it's a bug on Gitea's end), so you'll have to sign out first and then use the activation link to activate your account.
See the official documentation for the recommended way of updating to a new version, which includes creating a backup before updating, otherwise, follow the steps below:
# Stop the Gitea server
sudo systemctl stop gitea
# Download and replace with the latest Gitea binary (check for the latest version at https://dl.gitea.com/gitea/)
sudo wget -O /usr/local/bin/gitea/gitea https://dl.gitea.com/gitea/<version>/gitea-<version>-linux-amd64
# Restart the server
sudo systemctl restart giteaFor troubleshooting purposes, you can see live Gitea logs using:
journalctl -u gitea -fAs per the documentation, the default max size of each file is 50 MB and 5 files per upload.
Note
This only applies to the file upload via the Gitea's web interface and not push via command-line - it has no limit.
To increase these limits, modify app.ini:
# Open app.ini
sudo nano /etc/gitea/app.ini
# Add the following, then save and close the file
[repository.upload]
FILE_MAX_SIZE = 10240 # 10 GB per file
MAX_FILES = 20000 # 20,000 files per upload
# Restart the service
sudo systemctl restart giteaThe following are some of the repository settings I like to have for an ease of use. See the full list here.
# Open app.ini
sudo nano /etc/gitea/app.ini
# Go to the [repository] block and add the following, then save and close the file
DEFAULT_BRANCH = master # Default branch name of all repositories.
DEFAULT_PUSH_CREATE_PRIVATE = false # Default private when creating a new repository with push-to-create.
ENABLE_PUSH_CREATE_USER = true # Allow users to push local repositories to Gitea and have them automatically created for a user.
ENABLE_PUSH_CREATE_ORG = true # Allow users to push local repositories to Gitea and have them automatically created for an org.
# Restart the service
sudo systemctl restart gitea