From 09e19680e6fe497862c1c2eb107664018e101916 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Tue, 23 Dec 2025 23:19:46 +0100 Subject: [PATCH] any.software.gitea: started role --- .../any.software.gitea/files/gitea.Caddyfile | 5 + .../files/gitea.data.backup.sh | 12 ++ .../files/gitea.lfs.backup.sh | 12 ++ roles/any.software.gitea/files/gitea.pod | 4 + .../files/gitea.postgres.backup.sh | 7 ++ .../files/gitea.repositories.backup.sh | 12 ++ roles/any.software.gitea/files/gitea.service | 13 ++ roles/any.software.gitea/handlers/main.yml | 5 + roles/any.software.gitea/meta/main.yml | 3 + roles/any.software.gitea/tasks/main.yml | 82 +++++++++++++ roles/any.software.gitea/templates/app.ini.j2 | 112 ++++++++++++++++++ .../templates/gitea-app.container.j2 | 20 ++++ .../templates/gitea-postgres.container.j2 | 18 +++ 13 files changed, 305 insertions(+) create mode 100644 roles/any.software.gitea/files/gitea.Caddyfile create mode 100644 roles/any.software.gitea/files/gitea.data.backup.sh create mode 100644 roles/any.software.gitea/files/gitea.lfs.backup.sh create mode 100644 roles/any.software.gitea/files/gitea.pod create mode 100644 roles/any.software.gitea/files/gitea.postgres.backup.sh create mode 100644 roles/any.software.gitea/files/gitea.repositories.backup.sh create mode 100644 roles/any.software.gitea/files/gitea.service create mode 100644 roles/any.software.gitea/handlers/main.yml create mode 100644 roles/any.software.gitea/meta/main.yml create mode 100644 roles/any.software.gitea/tasks/main.yml create mode 100644 roles/any.software.gitea/templates/app.ini.j2 create mode 100644 roles/any.software.gitea/templates/gitea-app.container.j2 create mode 100644 roles/any.software.gitea/templates/gitea-postgres.container.j2 diff --git a/roles/any.software.gitea/files/gitea.Caddyfile b/roles/any.software.gitea/files/gitea.Caddyfile new file mode 100644 index 0000000..b27c714 --- /dev/null +++ b/roles/any.software.gitea/files/gitea.Caddyfile @@ -0,0 +1,5 @@ +git.rustybever.be { + reverse_proxy localhost:8010 { + header_down +X-Robots-Tag "none" + } +} diff --git a/roles/any.software.gitea/files/gitea.data.backup.sh b/roles/any.software.gitea/files/gitea.data.backup.sh new file mode 100644 index 0000000..279f68a --- /dev/null +++ b/roles/any.software.gitea/files/gitea.data.backup.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +data_dir='/mnt/data1/gitea/data' +snapshot_dir="${data_dir}.snapshot" + +# Read-only snapshot for atomic backup +btrfs subvolume snapshot -r "$data_dir" "$snapshot_dir" || exit $? + +/usr/local/bin/restic backup "$snapshot_dir" + +# Always remove snapshot subvolume, even if restic fails +btrfs subvolume delete "$snapshot_dir" diff --git a/roles/any.software.gitea/files/gitea.lfs.backup.sh b/roles/any.software.gitea/files/gitea.lfs.backup.sh new file mode 100644 index 0000000..bfc3869 --- /dev/null +++ b/roles/any.software.gitea/files/gitea.lfs.backup.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +data_dir='/mnt/data1/gitea/lfs' +snapshot_dir="${data_dir}.snapshot" + +# Read-only snapshot for atomic backup +btrfs subvolume snapshot -r "$data_dir" "$snapshot_dir" || exit $? + +/usr/local/bin/restic backup "$snapshot_dir" + +# Always remove snapshot subvolume, even if restic fails +btrfs subvolume delete "$snapshot_dir" diff --git a/roles/any.software.gitea/files/gitea.pod b/roles/any.software.gitea/files/gitea.pod new file mode 100644 index 0000000..daf30a0 --- /dev/null +++ b/roles/any.software.gitea/files/gitea.pod @@ -0,0 +1,4 @@ +# vim: ft=systemd +[Pod] +PublishPort=8016:22 +PublishPort=8010:3000 diff --git a/roles/any.software.gitea/files/gitea.postgres.backup.sh b/roles/any.software.gitea/files/gitea.postgres.backup.sh new file mode 100644 index 0000000..6217795 --- /dev/null +++ b/roles/any.software.gitea/files/gitea.postgres.backup.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +cd /etc/gitea + +/usr/bin/docker compose exec -T db pg_dump -U gitea gitea | + /usr/bin/gzip --rsyncable | + /usr/local/bin/restic backup --stdin --stdin-filename gitea-postgres.sql.gz diff --git a/roles/any.software.gitea/files/gitea.repositories.backup.sh b/roles/any.software.gitea/files/gitea.repositories.backup.sh new file mode 100644 index 0000000..f3df264 --- /dev/null +++ b/roles/any.software.gitea/files/gitea.repositories.backup.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +data_dir='/mnt/data1/gitea/repositories' +snapshot_dir="${data_dir}.snapshot" + +# Read-only snapshot for atomic backup +btrfs subvolume snapshot -r "$data_dir" "$snapshot_dir" || exit $? + +/usr/local/bin/restic backup "$snapshot_dir" + +# Always remove snapshot subvolume, even if restic fails +btrfs subvolume delete "$snapshot_dir" diff --git a/roles/any.software.gitea/files/gitea.service b/roles/any.software.gitea/files/gitea.service new file mode 100644 index 0000000..6e88626 --- /dev/null +++ b/roles/any.software.gitea/files/gitea.service @@ -0,0 +1,13 @@ +[Unit] +Description=Private, Fast, Reliable DevOps Platform +After=docker.service +Requires=docker.service + +[Service] +Type=exec +WorkingDirectory=/etc/gitea +ExecStart=/usr/bin/docker compose up +ExecStop=/usr/bin/docker compose down + +[Install] +WantedBy=multi-user.target diff --git a/roles/any.software.gitea/handlers/main.yml b/roles/any.software.gitea/handlers/main.yml new file mode 100644 index 0000000..f8bd4e5 --- /dev/null +++ b/roles/any.software.gitea/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: 'restart gitea' + ansible.builtin.service: + name: 'gitea' + state: 'restarted' diff --git a/roles/any.software.gitea/meta/main.yml b/roles/any.software.gitea/meta/main.yml new file mode 100644 index 0000000..d620a12 --- /dev/null +++ b/roles/any.software.gitea/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: any.tools.caddy diff --git a/roles/any.software.gitea/tasks/main.yml b/roles/any.software.gitea/tasks/main.yml new file mode 100644 index 0000000..c9a642a --- /dev/null +++ b/roles/any.software.gitea/tasks/main.yml @@ -0,0 +1,82 @@ +--- +- name: Ensure configuration directory is present + ansible.builtin.file: + path: '/etc/gitea' + state: directory + mode: '0755' + +- name: Ensure Quadlet files is present + ansible.builtin.template: + src: "{{ item }}.j2" + dest: "/home/debian/.config/containers/systemd/{{ item }}" + mode: '0755' + owner: 'debian' + group: 'debian' + loop: + - 'gitea-app.container' + - 'gitea-postgres.container' + +- name: Ensure Quadlet files is present + ansible.builtin.copy: + src: "{{ item }}" + dest: "/home/debian/.config/containers/systemd/{{ item }}" + mode: '0755' + owner: 'debian' + group: 'debian' + loop: + - 'gitea.pod' + +- name: Ensure Caddyfile is present + ansible.builtin.copy: + src: 'gitea.Caddyfile' + dest: '/etc/caddy/gitea.Caddyfile' + owner: root + group: root + mode: '0644' + notify: reload caddy + +- name: Allow Gitea SSH connections + community.general.ufw: + port: 8016 + rule: 'allow' + +# - name: Ensure compose file is present +# ansible.builtin.copy: +# src: 'compose.yml' +# dest: '/etc/gitea/compose.yml' +# mode: '0644' +# owner: 'root' +# group: 'root' +# notify: 'restart gitea' + +# - name: Ensure config file is present +# ansible.builtin.template: +# src: 'app.ini.j2' +# dest: '/etc/gitea/app.ini' +# mode: '0644' +# owner: 'root' +# group: 'root' +# notify: 'restart gitea' + +# - name: Ensure backup scripts are present +# ansible.builtin.copy: +# src: "gitea.{{ item }}.backup.sh" +# dest: "/etc/backups/gitea.{{ item }}.backup.sh" +# owner: 'root' +# group: 'root' +# mode: '0644' +# loop: +# - 'postgres' +# - 'data' +# - 'lfs' +# - 'repositories' + +# - name: systemd-reload +# ansible.builtin.systemd_service: +# daemon_reload: true +# when: 'res.changed' + +# - name: Ensure gitea service is enabled +# ansible.builtin.service: +# name: 'gitea' +# enabled: true diff --git a/roles/any.software.gitea/templates/app.ini.j2 b/roles/any.software.gitea/templates/app.ini.j2 new file mode 100644 index 0000000..4653ec3 --- /dev/null +++ b/roles/any.software.gitea/templates/app.ini.j2 @@ -0,0 +1,112 @@ +APP_NAME = The Rusty Bever +RUN_MODE = prod +RUN_USER = git +WORK_PATH = /data/gitea + +[repository] +ROOT = /data/git/repositories +; Makes public the default option when creating a repo +DEFAULT_PRIVATE = public +; Disables releases, projects & wiki by default for new repos (but can be enabled when needed) +DEFAULT_REPO_UNITS = repo.code,repo.issues,repo.pulls +; Might as well be compatible with +DEFAULT_BRANCH = main + +[repository.pull-request] +WORK_IN_PROGRESS_PREFIXES = WIP:,[WIP]:,Draft:,[Draft]: + +[repository.local] +LOCAL_COPY_PATH = /data/gitea/tmp/local-repo + +[repository.upload] +TEMP_PATH = /data/gitea/uploads + +[ui] +; Always show the full name of a user when possible +DEFAULT_SHOW_FULL_NAME = true +THEMES = auto,gitea,arc-green,gitea-modern + +[server] +APP_DATA_PATH = /data/gitea +DOMAIN = git.rustybever.be +SSH_DOMAIN = git.rustybever.be +HTTP_PORT = 3000 +ROOT_URL = https://git.rustybever.be/ +DISABLE_SSH = false +SSH_PORT = 22 +SSH_LISTEN_PORT = 22 +LFS_START_SERVER = true +OFFLINE_MODE = false +LFS_JWT_SECRET = {{ gitea_lfs_jwt_secret }} + +[lfs] +PATH = /data/git/lfs + +[database] +PATH = /data/gitea/gitea.db +DB_TYPE = postgres +HOST = db:5432 +NAME = gitea +USER = gitea +PASSWD = gitea +LOG_SQL = false +SCHEMA = +SSL_MODE = disable +CHARSET = utf8 + +[indexer] +ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve + +[session] +PROVIDER_CONFIG = /data/gitea/sessions +PROVIDER = file + +[picture] +AVATAR_UPLOAD_PATH = /data/gitea/avatars +REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars +DISABLE_GRAVATAR = false +ENABLE_FEDERATED_AVATAR = true + +[attachment] +PATH = /data/gitea/attachments + +[log] +MODE = console +LEVEL = info +REDIRECT_MACARON_LOG = true +MACARON = console +ROUTER = console +ROOT_PATH = /data/gitea/log + +[security] +INSTALL_LOCK = true +MIN_PASSWORD_LENGTH = 12 +PASSWORD_COMPLEXITY = lower,upper,digit +SECRET_KEY = {{ gitea_secret_key }} +INTERNAL_TOKEN = {{ gitea_internal_token }} + +[service] +DISABLE_REGISTRATION = true +REQUIRE_SIGNIN_VIEW = false +REGISTER_EMAIL_CONFIRM = false +ENABLE_NOTIFY_MAIL = false +ALLOW_ONLY_EXTERNAL_REGISTRATION = false +ENABLE_CAPTCHA = false +DEFAULT_KEEP_EMAIL_PRIVATE = false +DEFAULT_ALLOW_CREATE_ORGANIZATION = true +DEFAULT_ENABLE_TIMETRACKING = true +NO_REPLY_ADDRESS = noreply.localhost + +[mailer] +ENABLED = false + +[openid] +ENABLE_OPENID_SIGNIN = true +ENABLE_OPENID_SIGNUP = false + +[oauth2] +JWT_SECRET = {{ gitea_jwt_secret }} + +[other] +SHOW_FOOTER_VERSION = false +SHOW_FOOTER_TEMPLATE_LOAD_TIME = false diff --git a/roles/any.software.gitea/templates/gitea-app.container.j2 b/roles/any.software.gitea/templates/gitea-app.container.j2 new file mode 100644 index 0000000..0797473 --- /dev/null +++ b/roles/any.software.gitea/templates/gitea-app.container.j2 @@ -0,0 +1,20 @@ +# vim: ft=systemd +[Unit] +Requires=gitea-postgres.service +After=gitea-postgres.service + +[Container] +Image=docker.io/gitea/gitea:1.20.1 +Pod=gitea.pod + +Volume={{ gitea_data_dir }}:/data +Volume={{ gitea_repositories_dir }}:/data/git/repositories +Volume={{ gitea_lfs_dir }}:/data/git/lfs +; Volume=/etc/timezone:/etc/timezone:ro +Volume=/etc/localtime:/etc/localtime:ro + +[Service] +Restart=always + +[Install] +WantedBy=default.target diff --git a/roles/any.software.gitea/templates/gitea-postgres.container.j2 b/roles/any.software.gitea/templates/gitea-postgres.container.j2 new file mode 100644 index 0000000..fd9657b --- /dev/null +++ b/roles/any.software.gitea/templates/gitea-postgres.container.j2 @@ -0,0 +1,18 @@ +# vim: ft=systemd +[Container] +Image=docker.io/postgres:14.8-alpine +Pod=gitea.pod + +Environment=POSTGRES_USER=gitea POSTGRES_PASSWORD=gitea POSTGRES_DB=gitea + +HealthCmd=["pg_isready","-U","gitea"] +HealthInterval=30s +HealthRetries=3 +HealthStartPeriod=30s +HealthTimeout=5s +Notify=Healthy + +Volume={{ postgres_data_dir }}:/var/lib/postgresql/data + +[Service] +Restart=always