Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save ammarshah/ddd481db43e69afa11714f3850951cfd to your computer and use it in GitHub Desktop.

Select an option

Save ammarshah/ddd481db43e69afa11714f3850951cfd to your computer and use it in GitHub Desktop.
Set Up Your Own Git Server on Windows 10 Using Gitea

Set Up Your Own Git Server on Windows 10 Using Gitea

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 set it up on both Windows and Linux. But let me be real here: if you have the option, use Linux. Windows is a pain in the ass. Often, it feels like fighting the OS instead of working with it.

Honestly, after doing this setup, I hate Windows even more than before - and I already hated it plenty.

That said, I had to do this on both because I use two backup machines - one running Windows 10 and the other Fedora Linux.

Before setting this up, I used to sync data from my main machine (also running Fedora) to those backups 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.

1. Create a Dedicated User

It's a major security best practice to run services like Gitea under a dedicated user account, not as an administrator/root.

You must be logged in to the administrator user account to perform the following:

  • Press Win + R, type lusrmgr.msc, and press Enter.

  • Right-click on Users and select New User.

  • Create a user named git.

    • Set a strong password.
    • Uncheck User must change password.
    • Check Password never expires.
  • Click Create then Close.

Now, sign out from the current administrator account and login to the git user account for the rest of the setup.

2. Install Git for Windows

  • Download and run the installer from the official Git for Windows website.

  • Select the following options during installation:

    • Choosing the default editor used by Git: Use the Nano editor by default.
    • Adjusting your PATH environment: Git from the command line and also from 3rd-party software.
    • Choosing HTTPS transport backend: Use the OpenSSL library.
    • Configuring the line ending conversions: Checkout Windows-style, commit Unix-style line endings.
    • Configuring the terminal emulator to use with Git Bash: Use MinTTY (the default terminal of MSYS2).
    • Choose the default behaviour of git pull: Only ever fast-forward.
    • Choose a credential helper: Git Credential Manager.
    • Finish the installation.

3. Download Gitea

  • Create a folder for Gitea, e.g., C:\gitea.

  • Find the latest version for your OS type here. Usually it's amd64, so the one you need would be: gitea-<version>-gogit-windows-4.0-amd64.exe.

  • Download it and place it in the C:\gitea folder.

  • Rename the file to gitea.exe.

4. Run Gitea as a Service

This will start Gitea server automatically on boot.

  • Create a service

    Open Git Bash (Run as administrator) and run:

    sc create gitea binPath= "C:\gitea\gitea.exe web --config C:\gitea\custom\conf\app.ini" start= auto

    (We'll use Git Bash as our default terminal to run commands in this entire guide, but only Run as administrator when mentioned explicitly).

  • Press Windows key and search for Services, right-click it and select Run as administrator.

  • Search for the service named gitea, right-click it and click on Properties.

  • Go to the Log On tab → select This account → click Browse...

    • Type your Windows username (i.e., git) → click Check Names → click OK.
    • Enter the password you set for the git user twice.
  • Go to the Recovery tab

    • For First failure, select Restart the Service (do the same for Second failure and Subsequent failures as well).
    • Set Reset fail count after value to 0 days.
    • Set Restart service after value to 1 minutes.
    • Close the window by clicking OK.
  • Right-click on the gitea service again and click Start.

Important

In case, the service does not auto-start on boot, run the following command as mentioned here:

sc config gitea start= delayed-auto

5. Initial Gitea Configuration

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.

6. Configure Static IP

  • For LAN

    We'll have to set a static IP on both the client and server machines, which, in my case, is Fedora and Windows, respectively.

    Follow the Configure Network Settings section from here for each machine.

  • 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: ipconfig | grep Default.

    Let's assume it's 192.168.100.1 like below:

    $ ipconfig | grep Default
      Default Gateway . . . . . . . . . : 192.168.100.1

    which means, you can use the static IP within the same range e.g., 192.168.100.x, where x could be any number from 2 to 254.

    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 Windows 10 section from here, but right-click on the Wi-Fi adapter instead of Ethernet and enter the following values under Internet Protocol Version 4 (TCP/IPv4) > Properties:

    IP address:           192.168.100.7
    Subnet mask:          255.255.255.0
    Default gateway:      192.168.100.1
    Preferred DNS server: 192.168.100.1
    

7. Map DNS for Your Domain

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.7
    

    For example, my Huawei Router has below settings:

    image
  • On Windows server machine

    Open Git Bash (Run as administrator) and run:

    nano /c/Windows/System32/drivers/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.com to 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/hosts file 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/hosts and completely ignore any subsequent entries for the same domain. Others - like curl, ping, or even Firefox - are smarter and just work fine.

    This means that in our case, gitshah.com will 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 (dnsmasq or 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/hosts file 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.

    1. Add domain mapping in /etc/hosts

      Open 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.

    2. 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 enp0s31f6 with your LAN interface (ip link will tell you).

      Make it executable:

      sudo chmod +x /etc/NetworkManager/dispatcher.d/99-gitshah-lan-monitor.sh
    3. 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 with via LAN in /etc/hosts.

    You can also see the messages in your logs whenever the script triggers:

    journalctl -t gitshah-lan-monitor

8. Generate Self-Signed SSL Certificate

Open Git Bash and run the following commands:

  • 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

9. Configure Gitea for HTTPS and SSH

While still in the Git Bash from the previous step, run the following commands:

  • Copy the Certificate and Key Files

    mkdir /c/gitea/custom/https
    cp gitshah.cert.pem gitshah.key.pem /c/gitea/custom/https
  • Update app.ini

    Open the file:

    nano /c/gitea/custom/conf/app.ini

    Go to the [server] block and add/modify the following:

    PROTOCOL = https
    CERT_FILE = C:/gitea/custom/https/gitshah.cert.pem
    KEY_FILE = C:/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).

  • Restart the Service

    Open a new Git Bash (Run as administrator) and run:

    sc stop gitea
    sc start gitea

    (Or you can open the Services application as an administrator, find and right-click on your gitea service and then click Restart).

10. Trust the Self-Signed Certificate

  • On Windows server machine

    • Press Windows key → type mmc → right-click on it and select Run as administrator → enter admin password (if prompts) then click Yes.
    • Go to FileAdd/Remove Snap-in.
    • Select Certificates from Available snap-ins (left-pane) → click Add → select Computer accountLocal computer → click Finish then OK.
    • Expand Certificates (Local Computer) → expand Trusted Root Certification Authorities → right-click Certificates.
    • Select → All TasksImport.
    • Import your CA certificate (gitshahCA.cert.pem) → click Next.
    • Keep Place all certificates in the following store selected and make sure Certificate store has Trusted Root Certification Authorities selected.
    • Complete the wizard.
  • On Fedora client machine

    • 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, curl should 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.

11. Create Admin User

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 fifth 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.

BONUS

1. Upgrade to a new version

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:

Open Git Bash (Run as administrator) and run:

  • Stop the service

    sc stop gitea
  • Upgrade Gitea binary

    • Find the latest version for your OS type here, as you did in the third step (Download Gitea) above.
    • Download it and rename the file to gitea.exe.
    • Replace the existing gitea.exe in the C:\gitea folder with the new one.
  • Start the service

    sc start gitea

2. Troubleshooting

For troubleshooting purposes, you can see live Gitea logs using the following:

  • Update Gitea configuration

    # Open Gitea config file
    nano /c/gitea/custom/conf/app.ini
    
    # Go to the [log] block and change `MODE` from `console` to `file`
    MODE = file

    Save and close the file (Ctrl+X, Y, Enter).

  • Restart the service

    Open Git Bash (Run as administrator) and run:

    sc stop gitea
    sc start gitea
  • See live logs

    tail -f /c/gitea/log/gitea.log

3. Increase file upload limit via Gitea web interface

As 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:

  • Update Gitea configuration

    # Open Gitea config file
    nano /c/gitea/custom/conf/app.ini
    
    # Add the following
    [repository.upload]
    FILE_MAX_SIZE = 10240 # 10 GB per file
    MAX_FILES = 20000     # 20,000 files per upload

    Save and close the file (Ctrl+X, Y, Enter).

  • Restart the service

    Open Git Bash (Run as administrator) and run:

    sc stop gitea
    sc start gitea

4. Few nice-to-have repository settings

The following are some of the repository settings I like to have for an ease of use. See the full list here.

  • Update Gitea configuration

    # Open Gitea config file
    nano /c/gitea/custom/conf/app.ini
    
    # Go to the [repository] block and add the following
    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.

    Save and close the file (Ctrl+X, Y, Enter).

  • Restart the service

    Open Git Bash (Run as administrator) and run:

    sc stop gitea
    sc start gitea
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment