Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Gitea Ubuntu
GUIDEInstall Guides

How to Install Gitea on Ubuntu 24.04 — Self-Hosted Git Server

28 min read

How to Install Gitea on Ubuntu 24.04 — Self-Hosted Git Server in 30 Minutes

Running your own Git server with Gitea gives you unlimited private repositories, full data sovereignty, and a developer experience that rivals GitHub — without per-seat fees, storage caps, or vendor lock-in. This tutorial walks through installing Gitea on Ubuntu 24.04 from first SSH login to a production deployment with PostgreSQL, systemd, Nginx TLS, Gitea Actions-ready configuration, Package Registry, and Git LFS.

Want a bigger DevOps stack? If you need an integrated container registry, Kubernetes integration, and built-in security scanning, compare this guide with our GitLab install guide before choosing.

Table of Contents

  • What is Gitea?
  • Why Self-Host Git Instead of Using GitHub?
  • Prerequisites
  • Step 1: Update System and Install Prerequisites
  • Step 2: Install and Configure PostgreSQL
  • Step 3: Create the git System User
  • Step 4: Download the Gitea Binary
  • Step 5: Create Directories and app.ini
  • Step 6: Create the systemd Unit
  • Step 7: Run the First-Install Wizard
  • Step 8: Add an SSH Key and Push Your First Repo
  • Step 9: Repositories, Forks, Wikis, Issues
  • Step 10: Package Registry (npm, Docker, Generic)
  • Step 11: Git LFS Setup
  • Step 12: Nginx Reverse Proxy with TLS
  • Step 13: Backups with gitea dump
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Gitea?

    Gitea is a lightweight, self-hosted Git service written in Go. It ships as a single static binary with no runtime dependencies — no Ruby on Rails, no Elixir, no JVM — and runs comfortably on a 2 GB VPS while serving dozens of developers. Despite the small footprint, Gitea offers a feature set that compares directly with GitHub or GitLab for day-to-day development work.

    Out of the box, Gitea provides Git repositories with branches, tags, and releases; pull requests with reviews and merge rules; issues with labels, milestones, and project boards; per-repo wikis; webhooks to trigger external systems; and a full REST and GraphQL-style API. It supports multiple authentication sources including local accounts, LDAP, SMTP, PAM, OAuth2, OpenID Connect, and SAML. Organizations and teams map cleanly to real-world company structures, with fine-grained permissions per repository.

    More recent Gitea releases have added significant platform features. Gitea Actions, introduced in 1.19 and stabilized through 1.22, brings GitHub Actions-compatible CI/CD with a YAML workflow syntax that runs many existing Action marketplace modules unchanged. The Package Registry accepts uploads for npm, Docker, Maven, PyPI, NuGet, RubyGems, Composer, Conan, Helm, Cargo, Alpine, Debian, RPM, and Generic formats — a single binary replaces multiple specialised artefact stores. Git LFS is built in, letting you track large binaries without external services. Mirror sync keeps repositories in lockstep with upstream GitHub, GitLab, or Bitbucket copies in either direction.

    Typical deployments span a wide range: indie developers self-hosting personal projects on a 2 GB VPS, startups running engineering for 10-30 developers on a 4 GB VPS, agencies hosting client work with strict data-residency requirements, and educational institutions providing per-student Git accounts behind their own SSO. Because Gitea is MIT-licensed, there are no feature gates, seat caps, or enterprise paywalls — everything in the binary is free forever.

    Why Self-Host Git Instead of Using GitHub?

    GitHub is excellent for public open source work and well suited to most teams, but self-hosting Git on your own VPS unlocks advantages that matter for businesses, agencies, and privacy-conscious developers.

    • Unlimited private repositories — GitHub's free tier is generous but has limits on Actions minutes, package storage, and Codespaces hours. On your own Gitea server, every repository is private by default, every build runs on hardware you rent, and you never hit surprise metering.
    • Data sovereignty — Source code is one of the most sensitive assets a software company owns. Keeping it on a server in a jurisdiction you control simplifies GDPR compliance, export-control rules, customer contracts that forbid third-party cloud processors, and government procurement requirements.
    • No vendor lock-in — Gitea stores everything on disk: bare Git repositories under /var/lib/gitea/repositories/, attachments and LFS objects alongside them, and metadata in PostgreSQL. Migrating to Forgejo or any other Git server is a file copy plus a database dump.
    • Predictable flat-rate cost — A 2 GB VPS at around EUR 7.99/month hosts unlimited users, repositories, and CI runners. GitHub Team at $4/user/month plus Actions minutes scales linearly with team size; Gitea does not.
    • Full customization — Add your own OAuth2 provider, integrate with internal SSO, enforce custom commit-message policies, run custom CI runners with GPUs, expose the API to internal tooling — you own the stack end to end.
    • Offline and air-gapped capability — For regulated industries (defence, medical devices, finance), Gitea runs entirely inside a private network with no outbound calls required.
    • Performance — Self-hosted Git operations use LAN bandwidth between your CI runners and the Git server. Clones and pushes that take 30 seconds against GitHub over the public internet complete in under 5 seconds on the same VPS LAN.

    Cost Comparison: GitHub vs. Self-Hosted Gitea

    ScenarioGitHub FreeGitHub TeamSelf-Hosted Gitea (Starter VPS)
    Monthly costFree (with limits)$4/user/monthEUR 7.99/mo (unlimited users)
    Private repositoriesUnlimitedUnlimitedUnlimited
    CI/CD minutes2,000/mo3,000/moUnlimited (on your hardware)
    Package storage500 MB2 GBLimited only by disk
    Data locationUS/global (GitHub)US/global (GitHub)Your chosen DC
    Cost for 10 devs$0 (with caps)$40/mo + overagesEUR 7.99/mo flat
    Cost for 30 devsN/A (overages hit)$120/mo + overagesEUR 7.99/mo flat
    For any team of more than two or three developers that needs private repositories and CI minutes, self-hosted Gitea is cheaper within the first month.

    Prerequisites

    Before starting, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • At least 2 GB of RAM and 20 GB of disk space
    • A domain name (for example git.example.com) with an A record pointing to your VPS IP
    • SSH access to the server
    • Ports 22, 80, 443 open in your firewall (and port 2222 if you run Gitea SSH on an alternate port)
    Recommended Plan: Starter VPS
    >
    For teams up to around 20 developers, the Starter VPS plan is the right fit:
    >
    - 2 vCPU cores
    - 2 GB RAM
    - 40 GB NVMe SSD
    - Unmetered bandwidth
    - EUR 7.99/month
    >
    For larger teams or heavy Gitea Actions workloads, step up to a Professional plan. Gitea's resource needs scale gently — most installs never need more than 4 GB of RAM.

    Connect to your server via SSH:

    bash
    ssh root@your-server-ip

    Step 1: Update System and Install Prerequisites

    Refresh the package index and install Git plus a handful of utilities Gitea relies on.

    bash
    sudo apt update && sudo apt upgrade -y
    sudo apt install -y git curl wget ca-certificates gnupg lsb-release

    Verify Git is at least version 2.34 (Ubuntu 24.04 ships with 2.43+):

    bash
    git --version

    Expected output:

    text
    git version 2.43.0

    If your kernel was updated by the apt upgrade, reboot before continuing:

    bash
    sudo reboot

    Step 2: Install and Configure PostgreSQL

    Gitea supports SQLite, MySQL, MariaDB, and PostgreSQL. For anything beyond a personal test setup, PostgreSQL is the recommended backend — it handles concurrent writes better, gives you point-in-time recovery, and pairs well with modern backup tooling.

    Install PostgreSQL 16 from the default Ubuntu 24.04 repositories:

    bash
    sudo apt install -y postgresql postgresql-contrib
    sudo systemctl enable --now postgresql

    Check the service is running:

    bash
    sudo systemctl status postgresql

    Create a dedicated database and user for Gitea:

    bash
    sudo -u postgres psql <<EOF
    CREATE ROLE gitea WITH LOGIN PASSWORD 'change-me-to-a-long-random-string';
    CREATE DATABASE gitea WITH OWNER gitea TEMPLATE template0 ENCODING 'UTF8' LC_COLLATE 'C' LC_CTYPE 'C';
    GRANT ALL PRIVILEGES ON DATABASE gitea TO gitea;
    EOF
    Security note: Replace change-me-to-a-long-random-string with a real password. Generate one with openssl rand -base64 32. Save it in your password manager — you'll paste it into app.ini and into the install wizard.

    Confirm you can connect as the new user:

    bash
    psql "host=127.0.0.1 user=gitea password=change-me-to-a-long-random-string dbname=gitea" -c '\conninfo'

    Expected output:

    text
    You are connected to database "gitea" as user "gitea" on host "127.0.0.1" at port "5432".

    Step 3: Create the git System User

    Gitea should run under a dedicated non-login user. This isolates repository files from other services and follows Linux security best practice.

    bash
    sudo adduser \
      --system \
      --shell /bin/bash \
      --gecos 'Git Version Control' \
      --group \
      --disabled-password \
      --home /home/git \
      git

    The user owns its own home directory at /home/git, which is where SSH keys and the server's known_hosts live. The shell is set to /bin/bash (not /bin/false) because Gitea rewrites SSH shell invocations when users push over SSH.

    Verify the user exists:

    bash
    id git

    Expected output:

    text
    uid=999(git) gid=999(git) groups=999(git)

    Step 4: Download the Gitea Binary

    Gitea ships as a single static binary. Grab the latest stable release from dl.gitea.com. At time of writing, 1.22 is current; always check docs.gitea.com for the newest tag.

    bash
    GITEA_VERSION=1.22.3
    wget -O /tmp/gitea "https://dl.gitea.com/gitea/${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-amd64"
    sudo mv /tmp/gitea /usr/local/bin/gitea
    sudo chmod +x /usr/local/bin/gitea
    sudo chown root:root /usr/local/bin/gitea

    Verify the install:

    bash
    gitea --version

    Expected output:

    text
    Gitea version 1.22.3 built with GNU Make 4.3, go1.22.7 : bindata, sqlite, sqlite_unlock_notify

    Step 5: Create Directories and app.ini

    Create the directory layout Gitea expects, with correct ownership.

    bash
    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 -p /etc/gitea sudo chown root:git /etc/gitea sudo chmod 770 /etc/gitea

    Create the main configuration file at /etc/gitea/app.ini:

    bash
    sudo tee /etc/gitea/app.ini > /dev/null <<'EOF'
    APP_NAME = My Team Git
    RUN_USER = git
    RUN_MODE = prod

    [server] DOMAIN = git.example.com HTTP_PORT = 3000 ROOT_URL = https://git.example.com/ DISABLE_SSH = false SSH_PORT = 2222 SSH_LISTEN_PORT = 2222 START_SSH_SERVER = true LFS_START_SERVER = true LFS_JWT_SECRET = REPLACE_WITH_LFS_JWT OFFLINE_MODE = false

    [database] DB_TYPE = postgres HOST = 127.0.0.1:5432 NAME = gitea USER = gitea PASSWD = change-me-to-a-long-random-string SSL_MODE = disable

    [repository] ROOT = /var/lib/gitea/data/gitea-repositories

    [lfs] PATH = /var/lib/gitea/data/lfs

    [session] PROVIDER = file

    [picture] AVATAR_UPLOAD_PATH = /var/lib/gitea/data/avatars REPOSITORY_AVATAR_UPLOAD_PATH = /var/lib/gitea/data/repo-avatars

    [attachment] PATH = /var/lib/gitea/data/attachments

    [log] MODE = file LEVEL = info ROOT_PATH = /var/lib/gitea/log

    [security] INSTALL_LOCK = false SECRET_KEY = REPLACE_WITH_SECRET_KEY INTERNAL_TOKEN = REPLACE_WITH_INTERNAL_TOKEN

    [service] DISABLE_REGISTRATION = true REQUIRE_SIGNIN_VIEW = true DEFAULT_KEEP_EMAIL_PRIVATE = true DEFAULT_ALLOW_CREATE_ORGANIZATION = true DEFAULT_ENABLE_TIMETRACKING = true

    [actions] ENABLED = true

    [packages] ENABLED = true

    [mailer] ENABLED = false EOF

    Key settings explained

    • DOMAIN / ROOT_URL — Must match the public URL users will visit. Clone URLs (https://git.example.com/user/repo.git) and webhook signatures are derived from ROOT_URL.
    • SSH_PORT / SSH_LISTEN_PORT = 2222 — Runs Gitea's built-in SSH server on a non-standard port so it doesn't clash with the host's OpenSSH on port 22. Users will clone via git clone ssh://[email protected]:2222/user/repo.git. If you prefer, set START_SSH_SERVER = false and let OpenSSH handle Git traffic on port 22.
    • LFS_START_SERVER = true — Enables the built-in Git LFS server. Configure clients with git lfs install and push large files alongside code.
    • DISABLE_REGISTRATION = true — Locks down signup so only admins can invite users. Flip to false for community installs.
    • [actions] ENABLED = true — Turns on Gitea Actions so you can register CI runners later.
    Generate the three security secrets:

    bash
    sudo -u git gitea generate secret SECRET_KEY
    sudo -u git gitea generate secret INTERNAL_TOKEN
    sudo -u git gitea generate secret LFS_JWT_SECRET

    Each command prints a long random string. Paste them into /etc/gitea/app.ini replacing REPLACE_WITH_SECRET_KEY, REPLACE_WITH_INTERNAL_TOKEN, and REPLACE_WITH_LFS_JWT. Then tighten permissions:

    bash
    sudo chmod 640 /etc/gitea/app.ini
    sudo chown root:git /etc/gitea/app.ini

    Step 6: Create the systemd Unit

    A systemd service makes Gitea start on boot and restart automatically if it crashes.

    bash
    sudo tee /etc/systemd/system/gitea.service > /dev/null <<'EOF'
    [Unit]
    Description=Gitea (Git with a cup of tea)
    After=syslog.target
    After=network.target
    After=postgresql.service
    Requires=postgresql.service

    [Service] RestartSec=2s Type=simple User=git Group=git WorkingDirectory=/var/lib/gitea/ ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini Restart=always Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea

    Hardening

    NoNewPrivileges=true ProtectSystem=strict ReadWritePaths=/var/lib/gitea /etc/gitea PrivateTmp=true PrivateDevices=true ProtectHome=false ProtectKernelTunables=true ProtectControlGroups=true

    [Install] WantedBy=multi-user.target EOF

    Reload systemd, enable the unit on boot, and start it:

    bash
    sudo systemctl daemon-reload
    sudo systemctl enable --now gitea

    Check it came up cleanly:

    bash
    sudo systemctl status gitea

    Expected output:

    text
    ● gitea.service - Gitea (Git with a cup of tea)
         Loaded: loaded (/etc/systemd/system/gitea.service; enabled; preset: enabled)
         Active: active (running) since Thu 2026-04-16 10:00:00 UTC; 5s ago
       Main PID: 4567 (gitea)
          Tasks: 9 (limit: 4590)
         Memory: 142.3M
            CPU: 1.1s

    Confirm it's listening on port 3000:

    bash
    sudo ss -tlnp | grep 3000

    Step 7: Run the First-Install Wizard

    Even though app.ini already contains the database credentials, Gitea presents a first-run wizard at http://your-server-ip:3000/install so you can confirm settings and create the initial admin account.

    Open your browser to http://your-server-ip:3000. You should see the install screen. Because you pre-filled app.ini, most fields are already populated — just confirm the database section connects and scroll to Administrator Account Settings:

    • Administrator Username — for example admin (avoid root)
    • Password — at least 12 characters, stored in your password manager
    • Email — a monitored address; password resets and notifications go here
    Click Install Gitea. You'll be redirected to the dashboard within a few seconds. Behind the scenes, Gitea sets INSTALL_LOCK = true in app.ini, which prevents anyone else from re-running the wizard.

    Confirm the install lock:

    bash
    sudo grep INSTALL_LOCK /etc/gitea/app.ini

    Expected output:

    text
    INSTALL_LOCK = true

    Log in with the admin account. You now have a working Gitea instance — time to secure it and use it.

    Step 8: Add an SSH Key and Push Your First Repo

    Adding an SSH key lets you clone, pull, and push without entering a password.

    On your local machine, copy your public key:

    bash
    cat ~/.ssh/id_ed25519.pub

    In the Gitea web UI, click your avatar → Settings → SSH / GPG Keys → Add Key. Paste the key, give it a name (for example laptop-2026), and save.

    Create a repository from the web UI: + → New Repository → name hello-gitea, tick Initialize Repository.

    Clone it on your laptop. Because we moved Gitea SSH to port 2222, use the full SSH URL:

    bash
    git clone ssh://[email protected]:2222/admin/hello-gitea.git
    cd hello-gitea
    echo "# Hello Gitea" > README.md
    git add README.md
    git commit -m "First self-hosted commit"
    git push origin main

    If you prefer HTTPS, use a Gitea access token instead of your password:

    bash
    git clone https://git.example.com/admin/hello-gitea.git

    Step 9: Repositories, Forks, Wikis, Issues

    Gitea's developer experience mirrors GitHub closely.

    Repositories support branches, tags, releases, and protected branches. Click Settings on a repository to configure merge styles (merge commit, rebase, squash), required reviewers, required status checks from Gitea Actions, and push rules like commit-message regex enforcement.

    Forks — any user with read access can click Fork to create a personal copy. Contributors push to their fork and open a pull request against the upstream repository, mirroring the GitHub workflow exactly. Admins can enable AllowOnlyContributorsToTrackTime and similar governance toggles under organization settings.

    Wikis are stored as a second Git repository alongside the main one. Every page is a markdown file you can clone, edit in your local editor, and push back. Sidebar navigation is auto-generated from the _Sidebar.md file.

    Issues support labels, milestones, assignees, due dates, reactions, and reference links between repositories (#123 resolves to the current repo, owner/repo#123 crosses boundaries). Combine issues with Projects (Kanban-style boards) for sprint planning. Issue templates live in .gitea/ISSUE_TEMPLATE/ inside the repo, and pull request templates live at .gitea/PULL_REQUEST_TEMPLATE.md.

    For teams coming from GitHub, the mental model is identical — only the domain name changes.

    Step 10: Package Registry (npm, Docker, Generic)

    Gitea's Package Registry is one of its most underrated features. Instead of running separate Verdaccio, Harbor, and Artifactory services, one Gitea install handles every major package format.

    You already enabled it in app.ini with [packages] ENABLED = true. Packages live under /var/lib/gitea/data/packages/ and are visible at the Packages tab on each user or organization page.

    Publishing an npm package

    bash
    npm config set registry https://git.example.com/api/packages/your-org/npm/
    npm config set //git.example.com/api/packages/your-org/npm/:_authToken YOUR_GITEA_TOKEN
    npm publish

    Teammates install with:

    bash
    npm install @your-org/your-package --registry https://git.example.com/api/packages/your-org/npm/

    Pushing a Docker image

    bash
    docker login git.example.com -u admin
    docker tag myapp:latest git.example.com/your-org/myapp:latest
    docker push git.example.com/your-org/myapp:latest

    Docker images are addressable by both tag and digest, support multi-arch manifests, and integrate with pull secrets in Kubernetes.

    Uploading a Generic artefact

    The Generic registry accepts any file — ideal for build artefacts like installers, firmware, or release bundles.

    bash
    curl --user admin:TOKEN \
      --upload-file ./my-installer.exe \
      https://git.example.com/api/packages/your-org/generic/my-product/1.0.0/my-installer.exe

    Other formats work the same way: Maven (mvn deploy), PyPI (twine upload), NuGet (dotnet nuget push), RubyGems (gem push), Composer, Conan, Helm, Cargo, and OS packages (Alpine, Debian, RPM). Every format has a /api/packages/<owner>/<format>/... endpoint documented in the Gitea docs.

    Step 11: Git LFS Setup

    Large binary files — design assets, ML model weights, video — bloat Git history badly. Git LFS replaces the file content with a pointer in the commit and stores the real bytes on the server separately.

    You already enabled LFS via LFS_START_SERVER = true in app.ini. On the client:

    bash
    # Install the LFS client once per machine
    git lfs install

    Inside your repo, tell LFS which file patterns to track

    git lfs track "*.psd" git lfs track "*.mp4" git lfs track "models/*.bin"

    Commit the .gitattributes file LFS creates

    git add .gitattributes git commit -m "Track large assets with LFS"

    Push as normal — LFS handles the upload transparently

    git push

    LFS objects land in /var/lib/gitea/data/lfs/. Each one is content-addressable, so identical files across branches and forks are stored once. For teams that push multi-gigabyte assets frequently, run gitea maintenance commands to audit usage:

    bash
    sudo -u git gitea -c /etc/gitea/app.ini manager flush-queues

    Step 12: Nginx Reverse Proxy with TLS

    Exposing Gitea directly on port 3000 works, but you'll want TLS on port 443 and a clean https://git.example.com URL. Nginx handles both.

    Install Nginx and Certbot:

    bash
    sudo apt install -y nginx certbot python3-certbot-nginx

    Create the Gitea vhost:

    bash
    sudo tee /etc/nginx/sites-available/gitea > /dev/null <<'EOF'
    server {
        listen 80;
        server_name git.example.com;
        return 301 https://$host$request_uri;
    }

    server { listen 443 ssl http2; server_name git.example.com;

    ssl_certificate /etc/letsencrypt/live/git.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/git.example.com/privkey.pem;

    # Raise upload size for LFS pushes and large commits client_max_body_size 512m;

    # Security headers add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options SAMEORIGIN always; add_header Referrer-Policy strict-origin-when-cross-origin always;

    location / { proxy_pass http://127.0.0.1:3000; 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;

    # Long timeouts for large git pushes proxy_read_timeout 600s; proxy_send_timeout 600s; } } EOF

    sudo ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/ sudo nginx -t

    Obtain the TLS certificate:

    bash
    sudo certbot --nginx -d git.example.com

    Certbot edits the vhost, installs the certificate, and sets up a renewal timer. Reload Nginx:

    bash
    sudo systemctl reload nginx

    Update app.ini so Gitea knows it's behind TLS:

    ini
    [server]
    DOMAIN   = git.example.com
    ROOT_URL = https://git.example.com/

    Restart Gitea:

    bash
    sudo systemctl restart gitea

    Open https://git.example.com — you should see the Gitea dashboard served over HTTPS with a valid certificate.

    Finally, open your firewall for ports 80, 443, and 2222 (the Gitea SSH port):

    bash
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw allow 2222/tcp
    sudo ufw enable

    Step 13: Backups with gitea dump

    Gitea ships with a backup command that packages everything into a single zip file: database, repositories, LFS objects, attachments, avatars, and app.ini.

    Create a backup directory and run a dump:

    bash
    sudo mkdir -p /var/backups/gitea
    sudo chown git:git /var/backups/gitea

    sudo -u git gitea -c /etc/gitea/app.ini dump \ -f /var/backups/gitea/gitea-dump-$(date +%F).zip

    Schedule it nightly via cron. Edit the git user's crontab:

    bash
    sudo crontab -u git -e

    Add:

    text
    0 2    /usr/local/bin/gitea -c /etc/gitea/app.ini dump -f /var/backups/gitea/gitea-dump-$(date +\%F).zip && find /var/backups/gitea -name 'gitea-dump-.zip' -mtime +7 -delete

    This runs at 02:00 every night and prunes dumps older than seven days. For production, copy each night's zip off-server to S3, Backblaze B2, or another VPS using rclone or restic — a local-only backup doesn't help if the VPS itself is lost.

    To restore, extract the zip, import the SQL with psql, and copy the repos/ directory back into place. Full restore steps are documented at docs.gitea.com.

    Troubleshooting

    ProblemCauseSolution
    502 Bad Gateway from NginxGitea not running or wrong upstream portsudo systemctl status gitea and verify proxy_pass matches HTTP_PORT in app.ini
    Clone over SSH hangsBuilt-in SSH server port blocked by firewallsudo ufw allow 2222/tcp or disable the built-in server and use OpenSSH on 22
    fatal: Authentication failed on HTTPS pushGitHub-style password auth disabledCreate a personal access token under Settings → Applications and use it as the password
    LFS push fails with 413Nginx body size too smallRaise client_max_body_size in the vhost to 512m or higher, reload Nginx
    pq: role "gitea" does not exist in logsPostgres user not created or wrong passwordRe-run the CREATE ROLE statement and update PASSWD in app.ini
    Webhook deliveries failingGitea can't resolve its own ROOT_URLCheck DNS resolves from the server, check outbound firewall rules
    High disk usage under /var/lib/gitea/data/lfsDangling LFS objects from deleted reposRun gitea doctor and then gitea manager flush-queues

    Viewing logs

    bash
    sudo journalctl -u gitea -f
    sudo tail -f /var/lib/gitea/log/gitea.log

    FAQ

    Is Gitea really free and open source?

    Yes. Gitea is MIT-licensed, fully open source, and has no paid tier or feature gating. Every feature — unlimited private repos, CI/CD with Gitea Actions, Package Registry, LFS, wikis, issues, pull requests — is available in the free community edition. Gitea Enterprise exists as a paid offering with additional support and SLAs, but the software itself is identical to the community release.

    How much RAM does Gitea need?

    Gitea is remarkably lightweight compared to GitLab. A small team of 5-20 developers runs comfortably on 2 GB RAM with PostgreSQL on the same server. Gitea itself typically uses 150-300 MB of RAM at rest, rising modestly during heavy Git operations (pack file creation on large clones, Git LFS ingestion). The Starter VPS plan with 2 GB RAM is a good fit for most self-hosted teams.

    Can Gitea replace GitHub for a small team?

    For most small and medium teams, yes. Gitea provides repositories, forks, pull requests, issues, wikis, projects, releases, a built-in package registry (npm, Docker, Maven, PyPI, NuGet, Generic), LFS, webhooks, SSO via OAuth2/OIDC, and CI/CD via Gitea Actions. What it lacks are GitHub Copilot, GitHub Codespaces, and the massive public marketplace — but for private team development, Gitea covers the essentials.

    How does Gitea compare to GitLab and Forgejo?

    Gitea is the lightweight self-hosted Git server — single Go binary, minimal resource usage, fast to install. GitLab is a full DevOps platform with built-in CI runners, container registry, Kubernetes integration, and security scanning, but it needs 8 GB+ RAM and is complex to operate. Forgejo is a community fork of Gitea that tracks Gitea closely but is governed by a non-profit; migrations between the two are trivial because the data formats are identical. Choose Gitea for a simple, fast, low-resource Git server; choose GitLab if you want an integrated DevOps suite; choose Forgejo if you prefer non-profit governance.

    How do I migrate repositories from GitHub to Gitea?

    Gitea has a built-in migration tool that imports from GitHub, GitLab, Bitbucket, and raw Git URLs. From the web UI, click the plus icon and choose Migration, then select GitHub and paste a personal access token with repo scope. Gitea will copy the code, issues, pull requests, labels, milestones, and releases. For bulk migration of many repos, use the Gitea API or the gitea-github-migrator tool. LFS objects migrate automatically when both sides support LFS.

    Is Gitea Actions fully compatible with GitHub Actions?

    Gitea Actions uses the same YAML syntax as GitHub Actions and runs many actions from the GitHub marketplace unchanged. Core actions like actions/checkout, actions/setup-node, and actions/cache work out of the box. The runner is a fork of nektos/act. Differences exist around GitHub-specific services (GitHub Packages, OIDC with cloud providers, deployment environments), but for build-test-deploy pipelines the compatibility is excellent. If you're coming from a different CI background, compare with Drone CI which offers a similar self-hosted model with a different YAML dialect.

    How do I back up Gitea safely?

    Use the built-in gitea dump command, which captures the database, repositories, LFS objects, attachments, avatars, and configuration into a single zip file. Run it as the git user on a nightly cron schedule and ship the zip off-server to S3, Backblaze B2, or another VPS via rclone or restic. For large instances (100 GB+ of repos), use pg_dump for the database plus filesystem snapshots of the repository directory to avoid long single-process dumps.

    Next Steps

    Your Gitea server is running in production. Here's where to go from here:

    • Set up Gitea Actions runners — Follow the Gitea Actions runner setup guide to register a CI runner and start running GitHub Actions-compatible workflows on every push.
    • Compare with alternative CI — If you prefer a lighter, container-native CI, see our Drone CI install guide. Drone integrates with Gitea via OAuth and runs pipelines in ephemeral Docker containers.
    • Evaluate Forgejo — If you're interested in community governance, read our Forgejo install guide. Migrations between Gitea and Forgejo are trivial since they share a common ancestor.
    • Consider GitLab for bigger teams — If your needs grow beyond Git hosting and CI — container registry, Kubernetes auto-deploy, built-in security scanning — the GitLab install guide covers the full DevOps platform.
    • Hook up monitoring — Point Uptime Kuma or a Prometheus blackbox exporter at https://git.example.com/api/healthz to get alerts before users notice downtime.
    • Read the docs — The official docs.gitea.com is excellent. Bookmark the Administration and API sections.

    Need a VPS to host Gitea?
    >
    Our Starter VPS plan gives you 2 vCPU, 2 GB RAM, and 40 GB NVMe SSD for EUR 7.99/month — more than enough for a team of 10-20 developers running Gitea, PostgreSQL, and Nginx together.
    >
    - Full root access on Ubuntu 24.04 LTS
    - Unmetered bandwidth
    - Deploy in under 60 seconds
    - Scale up to more RAM without rebuilding when your team grows
    >
    Launch your Git server VPS now.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket