Self-hosting with Gitea

Vultr Gitea instance with PostgreSQL

The following is example configuration for a low-cost Vultr instance that can easily run Gitea with PostgreSQL used for data storage.

  1. Cloud Compute
  2. intel Regular Performance
  3. Chicago United States
  4. Debian 11 x64
  5. 25 GB SSD for $5/month with 1 vCPU, 1 GB Memory, 1 TB Bandwidth
  6. Disable Auto Backups
  7. Enable IPv6

Initial setups

  1. Create a new non-root user
    • adduser <new-user>
    • usermod -aG sudo <new-user>
    • exit
  2. Initial updates
    1. sudo apt update
    2. sudo apt upgrade if needed (wasn't required)
    3. sudo apt autoremove to remove ~310 MB of packages
  3. Install required packages
    1. sudo apt install postgresql (version 13)
    2. sudo apt install git (version 2.30.2)
    3. sudo systemctl start postgresql
    4. sudo systemctl enable postgresql
    5. sudo systemctl status postgresql

PostgreSQL Setup

  1. sudo vim /etc/postgresql/13/main/postgresql.conf
    • Under Connections and Authentication, update password_encryption from md5 to scram-sha-256 and uncomment.
  2. sudo vim /etc/postgresql/13/main/pg_hba.conf
    • Update all md5 instances to scram-sha-256.
  3. sudo service postgresql restart (restart service / reload config)
  4. sudo -i -u postgres
  5. psql
  6. CREATE ROLE gitea WITH LOGIN PASSWORD 'TODO-SET-PASSWORD';
    • Alter it: ALTER ROLE gitea WITH PASSWORD 'TODO-SET-NEW-PASSWORD';
  7. CREATE DATABASE giteadb WITH OWNER gitea TEMPLATE template0 ENCODING UTF8 LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';
  8. quit (psql)
  9. exit (postgres user)
  10. sudo vim /etc/postgresql/13/main/pg_hba.conf
    • Add a new line with local giteadb gitea scram-sha-256 for local access.
  11. sudo service postgresql restart
  12. psql -U gitea -d giteadb to verify access.

Install Gitea (1.16.8 at the time of writing)

  1. uname -mrs to confirm amd64.
  2. Get link from https://dl.gitea.io/gitea/
    • https://dl.gitea.io/gitea/1.16.8/gitea-1.16.8-linux-amd64
  3. wget -O gitea https://dl.gitea.io/gitea/1.16.8/gitea-1.16.8-linux-amd64
  4. chmod +x gitea
  5. sudo mv gitea /usr/local/bin/gitea
  6. sudo adduser --system --shell /bin/bash --gecos 'Git Version Control' --group --disabled-password --home /home/git git
  7. Setup 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
  8. sudo wget https://raw.githubusercontent.com/go-gitea/gitea/main/contrib/systemd/gitea.service -P /etc/systemd/system/
  9. sudo nano /etc/systemd/system/gitea.service
    • Uncomment Wants=postgresql.service and After=postgresql.service lines.
  10. sudo systemctl daemon-reload
  11. sudo systemctl enable --now gitea
  12. sudo systemctl status gitea
  13. sudo ufw allow 3000/tcp

Configure Gitea

  1. http://:3000
  2. Select PostgreSQL as Database Type
  3. Set Password.
  4. Change Database Name to giteadb
  5. Update Gitea Base URL to http://:3000/
  6. Create a new administrator account.
  7. Once setup, logout and log back in with new account.
  8. sudo vim /etc/gitea/app.ini if you want to update after the fact.

Lockdown Gitea

This locks down Gitea so that only signed in users can access the site, and registration isn't available.

  1. sudo vim /etc/gitea/app.ini
  2. [service]
    • DISABLE_REGISTRATION = true
    • REQUIRE_SIGNIN_VIEW = true
  3. sudo service gitea restart
  4. sudo chmod 750 /etc/gitea
  5. sudo chmod 640 /etc/gitea/app.ini

Nginx

  1. Setup a new (sub)domain to point to the server.
  2. Should be able to access http://:3000.
  3. sudo apt install nginx
  4. sudo ufw allow 'Nginx HTTP'
  5. sudo ufw status
  6. systemctl status nginx
  7. sudo nano /etc/nginx/nginx.conf
server {
    listen 80;
    server_name git.example.com;

    location / {
        proxy_pass http://localhost: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;
    }
}
  1. sudo nginx -t to verify configuration changes
  2. sudo systemctl restart nginx
  3. Custom domain, port 80, should now work.

Certbot / SSL

  1. sudo apt install certbot python3-certbot-nginx
  2. sudo ufw allow 'Nginx Full'
  3. sudo ufw delete allow 'Nginx HTTP'
  4. sudo ufw status
  5. sudo certbot --nginx -d git.ebacher-skemp.com (or whatever custom domain was setup)
  6. sudo systemctl status certbot.timer (verify Certbot will run again automatically)
  7. sudo certbot renew --dry-run (fake a cert renewal to make sure it picks it up)
  8. https:// should work for Gitea access, and http should redirect
  9. sudo nano /etc/gitea/app.ini
    • Update server > ROOT_URL
    • Also needed to add a repository > DEFAULT_BRANCH = main
  10. sudo service gitea restart
  11. sudo ufw delete allow 3000/tcp (no longer allow external access via 3000)

Other Customizations

  • In my.vultr.com, add the following tags to the server instance (so I know core functionality):
    • gitea
    • postgresql
    • nginx
    • certbot
  • sudo apt install htop (prettier top)
  • sudo vim /etc/gitea/app.ini
    • repository > ENABLE_PUSH_CREATE_USER = true
    • repository > ENABLE_PUSH_CREATE_ORG = true
    • repository > DEFAULT_REPO_UNITS = repo.code,repo.issues,repo.pulls (updated 11/2024)
      • Default is currently repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages,repo.actions (1.22.3)
    • cron.repo_health_check > TIMEOUT = 90s
    • service > REQUIRE_SIGNIN_VIEW = false (updated 4/2023)
    • server > SSH_DOMAIN = git.domain.com (updated 8/2023)
      • DOMAIN is fine as localhost since ROOT_URL is set.
    • server > LANDING_PAGE = explore (updated 12/2023)
  • sudo nano /etc/nginx/nginx.conf
    • Add client_max_body_size 100M; to gitea server section (to allow for larger files)
    • sudo nginx -t
    • sudo systemctl restart nginx
  • sudo nano /var/lib/gitea/custom/robots.txt
    • Configure as you'd like.
    • See https://docs.gitea.com/next/administration/search-engines-indexation#block-search-engines-indexation-using-robotstxt for some options.

Blocking bots

Optionally add the following within the first nginx.conf server block:

if ($http_user_agent ~* "SemrushBot|Semrush|facebookexternalhit|Amazonbot|Bytespider|meta-externalagent|ChatpGPT|CCBot|GPTBot|Applebot") {
	return 403;
}

Regular backups

On the server:

sudo systemctl stop gitea
sudo su - git
gitea dump -c /etc/gitea/app.ini -w /var/lib/gitea -t /tmp
ls -l --block-size=M
rm <old-backup-file>
# Grant everyone read access to the backup file.
chmod a=r <backup-file>
exit
sudo systemctl restart gitea

On your local machine:

# Copy the file locally.
scp <user>@<remote_ip>:/home/git/<backup-file> d:\

SMTP setup with Fastmail

  1. sudo vim /etc/gitea/app.ini
  2. Update [mailer] per the below.
  3. sudo systemctl restart gitea
  4. Send a test email from Gitea's /admin/config.
[mailer]
ENABLED        = true
FROM           = [email protected]
SMTP_ADDR      = smtp.fastmail.com
SMTP_PORT      = 465
USER           = `[email protected]`
PASSWD         = `password`

USER must be your primary Fastmail email. PASSWD is an application password. FROM can be your primary or an alias email.

  1. sudo vim /etc/gitea/app.ini
  2. Add [indexer] per the below.
  3. sudo systemctl restart gitea
  4. After some time, run sudo du -sh /var/lib/gitea/indexers to check index size.
    • sudo ls -lhR /var/lib/gitea/indexers/repos.bleve will list file sizes and dates.
[indexer]
REPO_INDEXER_ENABLED = true
REPO_INDEXER_PATH = indexers/repos.bleve
MAX_FILE_SIZE = 1048576
REPO_INDEXER_INCLUDE = **.bat,**.cfm,**.cs,**.gd,**.go,**.htm,**.html,**.js,**.json,**.linq,**.md,**.ps1,**.ts,**.tsx,**.txt,**.xml,**go.mod
REPO_INDEXER_EXCLUDE =

Useful commands

# View Gitea disk usage.
sudo du -sh /var/lib/gitea
# Show by child directory size.
sudo du -h /var/lib/gitea --max-depth=1
# Show largest directories first.
sudo du -h /var/lib/gitea --max-depth=1 | sort -hr
# Sort by directory name.
sudo du -h /var/lib/gitea --max-depth=1 | sort -k2
# Largest directories.
sudo du --separate-dirs -h /var/lib/gitea | sort -hr | head
sudo du --separate-dirs -h /var/lib/gitea | sort -hr | head -n 2