Self-Hosting Git
Debian Development Machine Setup
Chapter 9 ยท Self-Hosting Git with Gitea
Chapter 2 installed the Git client. This chapter installs a Git server: a place on your own network where repositories live, with a web page for browsing them, issues, pull requests and user accounts. We use Gitea, a lightweight self-hosted Git service that ships as a single program. Git and GitHub Foundations teaches the Git commands themselves; here the job is running the service properly on Debian.
Check First
You want no gitea command, a Git of at least 2.0 (Gitea's documented minimum; Debian 13's is far
newer), no existing git user, and nothing else using the ports. If getent prints a
line, a git user already exists and you should look at it before continuing.
Choosing a Database
Gitea stores users, issues and settings in a database, while the repositories themselves are ordinary directories on disk. Chapter 7 gave you two candidates.
| Choice | For | Against |
|---|---|---|
| SQLite | Nothing extra to run or secure; one file to back up; ideal for one person or a small team. | Gitea's own documentation warns it does not scale, so choose something else if the instance may grow. |
| MariaDB | Already installed from Chapter 7; copes with more users; a familiar tool. | One more service that Gitea needs running before it starts, and one more thing to back up. |
For a personal development machine, SQLite is the sensible default, and this chapter uses it. The MariaDB steps are given afterwards in case you prefer them. Gitea's documentation lists MariaDB 10.4 or newer as supported, and Debian 13 has 11.8.
Installing Gitea from the Binary
Gitea publishes a ready-built program for Linux, which is the installation method used here. Everything below follows Gitea's official binary-installation guide. Read the version number on the download page first; the examples use 1.27.3, which was the version in the documentation when this chapter was written, so substitute the current one.
Step 1: Download and verify
Look for Good signature from "Teabot <teabot@gitea.io>". This is the same
verify-before-trust habit as Chapter 1 and Chapter 8: you are about to run a downloaded program as a
service, so confirm it is the one the project signed. A warning that the key is not certified with a trusted
signature is normal for a key you have just fetched; a bad signature is not, and means you should
delete the file and download again.
Step 2: A dedicated user
This creates a git account that cannot log in with a password and exists only to own Gitea's
files and run its process. If Gitea is ever compromised, the attacker has that account's permissions and not
yours.
Step 3: Directories and the program
Data lives under /var/lib/gitea, configuration under /etc/gitea, and the program in
/usr/local/bin, the place Chapter 3 described for software that did not come from apt. Note that
apt knows nothing about this installation, so apt will never update it; upgrades are a
manual job you will do in Chapter 10's routine.
/etc/gitea is writable by the git group at this point so the web installer can save
its settings. Once setup is finished you tighten it (below). Do not leave it at 770.
Step 4: The systemd service
Gitea provides a sample unit file. Create /etc/systemd/system/gitea.service, keeping to the
project's sample and enabling only what you need:
Read it as three facts: it runs as git, not root; it starts Gitea with the configuration file in
/etc/gitea; and Restart=always brings it back if it crashes. The commented lines
matter only for a database that runs as its own service.
enable --now starts it immediately and at every boot. The status and journal commands are the
same ones you would use for any service (systemd in Depth covers them fully), and
ss shows which address and port it is listening on.
First-Run Setup
Open the web address of the machine in your browser on port 3000 (Gitea's own documentation refers to port
3000; use whatever ss shows if yours differs), for example http://localhost:3000.
The first visit shows an installation page. The fields that matter:
| Setting | Suggested value |
|---|---|
| Database type | SQLite3 (the path is offered for you), or MySQL for MariaDB with the details below |
| Server domain | devserver (or its IP address, which is more reliable if names do not resolve on your network) |
| Base URL | http://devserver:3000/, matching how you will actually reach it, because Gitea builds clone links from this |
| Administrator account | Create one here, with a strong password. If you skip it, the first account you register becomes the administrator. |
localhost (Chapter 7's habit) rather than the '%' wildcard the
documentation's example uses for remote access:
127.0.0.1:3306, and those names. Uncomment the two
mariadb.service lines in the unit file.
Lock the configuration down
Once the installer has finished and you can see the Gitea home page, tighten the permissions as the official guide advises:
app.ini contains secrets (and a database password if you used MariaDB), so it should be readable
only by root and the git group.
ss -tlnp | grep gitea: if it shows 127.0.0.1:3000 it is reachable only from this
machine; 0.0.0.0:3000 or *:3000 means the whole network. That is fine on a home
network you trust, and worth a second thought anywhere else. Also disable open registration (Site
Administration → Configuration, or the installer's optional settings) unless you want strangers making
accounts. HTTPS in front of it is outside this course; the HTTPS/TLS Fundamentals and Nginx In Depth courses
cover that.
Working With It
SSH keys
Pushing over SSH avoids typing a password each time. In the web page open your profile → Settings
→ SSH / GPG Keys, and paste the public key (~/.ssh/id_ed25519.pub, the pair you made in
Chapter 2). Gitea's documentation describes a built-in SSH server and also the option of using the system's
OpenSSH; because Chapter 2 already runs OpenSSH, ask the installer page about SSH settings and read what it
offers before changing anything, and keep to the default it proposes. HTTP pushing, described next, needs
none of this and is the simplest way to start.
Create a repository and push an existing project
Create an empty repository in the web page (no README, so the histories do not clash), then:
git remote add records where the server is; push -u uploads and remembers the link
so later a plain git push works. For a project that already has a GitHub remote, use
git remote rename origin github first, or use a second name such as gitea, so both
remain available. Remember the rule from earlier chapters: commit .gitignore, never
venv/, node_modules/ or vendor/.
Using it from other machines
Clone URLs use the Base URL you entered, so the name must resolve from the other computer. If
debserver cannot find devserver, use the IP address or add a line to its
/etc/hosts. Then git clone http://devserver:3000/YOURNAME/project.git works from
there, and VS Code from Chapter 8 can use the repository like any other remote.
Keeping It Healthy
| Task | How |
|---|---|
| Is it running? | systemctl status gitea |
| What went wrong? | journalctl -u gitea, plus the log directory under /var/lib/gitea/log |
| Restart after a config change | sudo systemctl restart gitea |
| Upgrade | Download and verify the new binary, stop the service, copy it over /usr/local/bin/gitea, start it. Back up first. |
| Back up | Chapter 10. Gitea has its own dump command; check gitea dump --help for the options in your version. |
Hands-On Exercises
Install Gitea from the binary: check first, download and verify the signature, create the git user and directories, install the systemd unit, and start it. Show three separate checks that it is running as the git user and listening where you expect.
Complete first-run setup with SQLite, tighten the permissions on /etc/gitea and app.ini, and confirm the service still works afterwards. Explain why the tightening is done after setup and not before.
Push one of your earlier projects (the Composer demo, or a small Python or Node project) to a new Gitea repository. Then clone it into a second directory and prove the copy is identical and that the ignored folders were not uploaded.
๐ View solutionChapter 9 Quick Reference
- Gitea = self-hosted Git service; repositories are directories, everything else is in a database
- SQLite for a personal machine; MariaDB (11.8 on Trixie, 10.4+ supported) if you prefer
- Download the binary, verify with
gpg --verify(key7C9E68152594688862D62AF62D9AE806EC1592E2), copy to/usr/local/bin/gitea - Dedicated
gituser viaadduser --system ... git; data in/var/lib/gitea, config in/etc/gitea - Unit file
/etc/systemd/system/gitea.service;systemctl enable gitea --now - First run at port 3000: set Base URL to how you reach the machine; then
chmod 750 /etc/giteaandchmod 640 /etc/gitea/app.ini - Not installed by apt, so apt never updates it: upgrades are manual
- Push:
git remote add origin URL,git push -u origin main - Check who can reach it with
ss -tlnp | grep gitea; consider disabling open registration