Ansible role that configures multiple Gitea instances on the same host (workable, but some care required)
Find a file
Image taha@asks2 8d9f9d9369 Updated README on how to work with multiple remotes.
This reflects my current best practice.

+ fetch module should be used with become: False whenever possible
+ tasks got more tags, and renamed a tag for consistency
2024-03-24 12:51:36 +01:00
defaults Default to private when creating new repo 2023-08-26 02:18:57 +02:00
files Role now includes backup functionality 2022-05-27 20:40:24 +02:00
handlers Migrated Gitea instances from dahab VPS to damietta VPS 2023-05-09 23:51:21 +02:00
meta Default to private when creating new repo 2023-08-26 02:18:57 +02:00
tasks Updated README on how to work with multiple remotes. 2024-03-24 12:51:36 +01:00
templates Default to private when creating new repo 2023-08-26 02:18:57 +02:00
vars Refactor of variable names in defaults. 2022-09-14 00:55:54 +02:00
.gitignore First commit 2021-06-27 07:05:36 +02:00
LICENSE Initial commit 2021-06-27 06:38:57 +02:00
README.md Updated README on how to work with multiple remotes. 2024-03-24 12:51:36 +01:00

Gitea

I originally wrote this Ansible role to provision two Gitea instances on the same VPS. The code inside this role has since been improved, and should now allow the provision of an arbitrary number of Gitea instances (1 or more).

To backup and update Gitea, you should run the playbook with --tags updates-only --extra-vars "{gitea_backup: true}". This role takes care to create the backup before updating. Note that backups only occur if gitea_backup==true.

Installing Gitea the first time

If you are running this role on a host for the first time (no existing Gitea), you need to set gitea_first_install==true in order for the role to relax file permissions to 770 on /etc/gitea/ so that the web installer (which you then run manually) can do its job.

By setting gitea_first_install==true this role also takes care to set INSTALL_LOCK==false in app.ini, thus allowing the web installer to reset the database and security configuration.

Also, if gitea_first_install==true is set, backup is skipped.

So in summary, for first-time setup, I recommend you run the playbook using extra-vars, like this:

$ ansible-playbook playbook.yml --ask-become-pass --tags "gitea" --extra-vars "{gitea_first_install: true}"

Setup multiple Gitea instances on the same host

I wanted to run two (2) separate Gitea instances on a single VPS. Because Gitea is so light-weight, I don't see why not. But I found no guides describing this situation. The ones I did found that were related appear to focus on distributing the same Gitea instance across multiple machines (load distribution, etc.).

This role makes the following assumptions:

  • each instance gets its own SQL database,
  • each instance gets its own /etc/gitea/<instance>/ directory,
  • each instance gets its own own systemd service file,
  • each instance gets its own working directory, log directory, root repo directory, LFS path, etc.,
  • all instances use the same Gitea binary,
  • all instances use the same SQL user account,
  • all instances use the same Linux user account.

These choices are mostly built-in to this role - I have made no effort to make them configurable. But I hope that you agree that these choices are non-controversial.

But be warned, there is a major pitfall. Due to the shared Linux user account all Gitea instances end up using the same authorized_keys file (/home/gitea/.ssh/authorized_keys). The problem is that each Gitea instance will handle this file as if it had sole discretion over it, and if you run the Gitea maintenance job Update the .ssh/authorized_keys file with Gitea SSH keys. from the Gitea admin panel this file is wiped by that instance and only the keys known to that instance are repopulated, effectively breaking SSH access for all other instances. Luckily it seems this Gitea maintenance job is only run if the admin triggers it manually. Obviously, please never run it manually either.

Furthermore, it appears that Gitea checks the user's provided key against each key in authorized_keys and as soon as it finds a match it stops and does not test the rest of the authorized keys even if the matched key belongs to the other instance. This means that if you reuse the same SSH key across instances, only the instance listed first in authorized_keys will have working SSH access, and the others will not work!

You might otherwise think that reusing the same key for multiple instances should work since each entry in the Gitea-generated authorized_keys has a unique key number and specifies the path to that instance's app.ini. But by trial-and-error it is evident that Gitea (last tested with v1.17.3) only compares the key itself without any regard to the domain address. Quite unfortunate from this role's perspective (perhaps worth opening a feature request?).

After provisioning your Gitea instances for the first time you might need to manually edit the authorized_keys file to make sure the key for each instance is included:

$ cat /home/gitea/.ssh/authorized_keys
# gitea public key
command="/usr/local/bin/gitea --config=/etc/gitea/asks/app.ini serv key-5",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict ssh-ed25519 AA....5f
# gitea public key
command="/usr/local/bin/gitea --config=/etc/gitea/solarchemist/app.ini serv key-5",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict ssh-ed25519 AA....8I

On the client side, using a different key for different remotes comes with the usual inconvenience. In my experience the least cumbersome way around it is to specify the key in each repository's .git/config file, for example:

$ git config core.sshCommand "/usr/bin/ssh -i ~/.ssh/id_ed25519"

Or you could configure the same using includeIf in your global ~/.gitconfig. I would not recommend trying to address this issue by editing your ~/.ssh/config.

Web-UI themes

  1. Find your gitea custom directory path in Site Administration > Configuration > Custom File Root Path.
  2. Create directories: templates and public/css within the directory, if it does not already exist. But please empty any previous files as they may create a conflict or unexpected behaviour.
  3. Clone then Copy/Move files from this repo into the custom directory location.
  4. Add the folowing lines to your gitea config:
[ui]
# list of themes each user can choose from: THEMES
THEMES = gitea,<new-theme>
# the default theme for all users
DEFAULT_THEME = <new-theme>
  1. Restart your Gitea service (note: to force the new theme also for logged-in users, list no other themes in THEMES).

Webhooks

I have created a webhook for all repos in my uu org that connects to a Matrix room on my taha account. The Room ID is visible from the Element desktop app or the Element web app, but not always from other clients (e.g., not visible in FluffyChat). The access token is for your account (not the room), and can be found under All Settings -> Help/About -> Advanced in the Element web app.

Despite the room being E2E encrypted, and Gitea having our access token, messages from Gitea are marked as "not encrypted". I have no idea why. But hey, it's working!

Authorized keys

Other Ansible roles

How I migrated Gitea from armant to dahab

Notes on how I migrated my single existing Gitea instance from a bare-metal Ubuntu server (armant) to the new VPS (dahab).

I manually migrated the SQL database, the .ssh/authorized_keys, the Gitea working directory (/var/lib/gitea), and the Gitea repositories root tree from armant to dahab.

So far, this was all routine.

The unexpected complication showed itself when I tried to push to one of my repos at the migrated Gitea instance:

(master) $ git push
Counting objects: 7, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (7/7), 866 bytes | 866.00 KiB/s, done.
Total 7 (delta 5), reused 0 (delta 0)
remote: Gitea: EOF
To git.solarchemist.se:backup/dns-records.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'gitea@git.solarchemist.se:backup/dns-records.git'

A comment on a Github issue made me look closer into the contents of the files in my Gitea repo hooks directories, and I realised that they all contained the path Gitea's app.ini config file, which had now obviously moved.

root@dahab:/media/gitea
# cat solarchemist/repositories/backup/dns-records.git/hooks/pre-receive.d/gitea
#!/usr/bin/env bash
"/usr/local/bin/gitea" hook --config='/etc/gitea/app.ini' pre-receive

A quick search across the entire Gitea root tree revealed a hundred or so instances of this snippet in various hook files. Luckily, we can correct all of them in one fell swoop using sed:

gitea@dahab:/media/gitea/solarchemist$
find . -type f -exec sed -i 's+/etc/gitea/app.ini+/etc/gitea/solarchemist/app.ini+g' {} \;

For good measure, restart the Gitea service: systemctl restart gitea_solarchemist.service.

And now Git push works for the migrated instance.