Merge pull request 'Certbot (Let's Encrypt) support.' (#8) from development into main

Reviewed-on: http://gitea.tomsitcafe.com:3000/iron/ds-gitea/pulls/8
This commit is contained in:
DeadSwitch
2026-02-11 13:20:18 +01:00
7 changed files with 189 additions and 40 deletions

View File

@@ -2,6 +2,8 @@
#+AUTHOR: DeadSwitch | The Silent Architect
#+OPTIONS: toc:nil num:nil \n:t
[[https://opensource.org/licenses/MIT][https://img.shields.io/badge/license-MIT-blue.svg]] [[https://img.shields.io/badge/version-3.0.0-green.svg]]
* ds-gitea
This role installs and configures a [[https://docs.gitea.com/][Gitea]] server.
@@ -9,10 +11,12 @@ This role installs and configures a [[https://docs.gitea.com/][Gitea]] server.
It uses SQLite as its default database service - with optional PostgreSQL support.
The role can set up a reverse proxy with SSL using Nginx.
Self-signed certificates and Let's Encrypt with =certbot= are supported.
- Use the =ds-ufw= role to configure the firewall.
- Use the =ds-posgresql= role to configure the database.
- Use the =ds-nginx= role to install the proxy server.
- Use the =ds-act_runner= role to configure and register Actions runners.
* Role Behavior
@@ -40,7 +44,7 @@ gitea_reverse_proxy: ''
* Requirements
- Ansible >= 2.12
- Debian-based OS (Bookworm, Trixie)
- Debian 12+ or compatible
- git
- sudo
- ca-certificates
@@ -72,6 +76,8 @@ gitea_reverse_proxy: ''
| gitea_ssl_key | string | SSL key |
| gitea_enable_http_redirect | boolean | Redirect HTTP to HTTPS |
| gitea_self_signed | boolean | Generate a self-signed cert and key |
| gitea_lets_encrypt | boolean | Use certbot to configure the SSL |
| gitea_certbot_email | string | Email to register the certificates |
* Handlers
@@ -109,20 +115,25 @@ Then re-run the playbook to finish the installation.
gitea_ssh_domain: gitea.tomsitcafe.com
gitea_domain: gitea.tomsitcafe.com
gitea_http_port: 3000
gitea_root_url: http://gitea.tomsitcafe.com:3000
gitea_root_url: https://gitea.tomsitcafe.com
# Optional Postgresql database backend
gitea_database_server: postgresql
# Optional Nginx reverse proxy configuration
gitea_reverse_proxy: nginx
gitea_enable_https: true
gitea_self_signed: true
gitea_ssl_cert: /var/lib/gitea/certs/cert.pem
gitea_ssl_key: /var/lib/gitea/certs/key.pem
gitea_enable_http_redirect: true
gitea_enable_https: true # Use HTTPS
gitea_self_signed: false # Don't generate self-signed certs
gitea_lets_encrypt: true # Use certbot
gitea_enable_http_redirect: true # Redirect HTTP to HTTPS
# In prod put these secrets in SOPS:
# Certbot configuration
gitea_certbot_email: email@domain.tld
gitea_ssl_cert: /etc/letsencrypt/live/{{ gitea_domain }}/fullchain.pem
gitea_ssl_key: /etc/letsencrypt/live/{{ gitea_domain }}/privkey.pem
gitea_ssl_trusted_certificate: /etc/letsencrypt/live/{{ gitea_domain }}/chain.pem
# In prod put the secrets in SOPS:
gitea_lfs_jwt_secret: G9bZrRHMhRQ8w4R0KkH2VLnx2rzq81ROQ951IQjlMs4
gitea_internal_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3NzA2Mzk1Njh9.ybbaeNLFiLbyvxfj4vkqhXSAXKRGpwvP8jIm9YLPgXw
gitea_jwt_secret: uJni4x4e0AzpkLYc-t4keRJKOB6EaLzwVsdLeamkFyU

View File

@@ -0,0 +1,34 @@
---
- name: Install Gitea
hosts: gitea
become: true
roles:
- role: ds-postgresql
- role: ds-nginx
- role: ds-gitea
vars:
gitea_user: git
gitea_group: git
gitea_database_server: postgresql
gitea_binary_url: https://dl.gitea.com/gitea/1.25.4/gitea-1.25.4-linux-amd64
gitea_checksum_url: https://dl.gitea.com/gitea/1.25.4/gitea-1.25.4-linux-amd64.sha256
gitea_app_name: Tom's IT Cafe Test Gitea Server
gitea_domain: gitea.tomsitcafe.com
gitea_ssh_domain: "{{ gitea_domain }}"
gitea_http_port: 3000
gitea_ssh_port: 22
gitea_root_url: https://{{ gitea_domain }}
gitea_reverse_proxy: nginx
gitea_enable_https: true
gitea_lets_encrypt: true
gitea_enable_http_redirect: true
gitea_certbot_email: tom@tomsitcafe.com
gitea_ssl_cert: /etc/letsencrypt/live/{{ gitea_domain }}/fullchain.pem
gitea_ssl_key: /etc/letsencrypt/live/{{ gitea_domain }}/privkey.pem
gitea_ssl_trusted_certificate: /etc/letsencrypt/live/{{ gitea_domain }}/chain.pem
# Secrets to SOPS
gitea_lfs_jwt_secret: G9bZrRHMhRQ8w4R0KkH2VLnx2rzq81ROQ951IQjlMs4
gitea_internal_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3NzA2Mzk1Njh9.ybbaeNLFiLbyvxfj4vkqhXSAXKRGpwvP8jIm9YLPgXw
gitea_jwt_secret: uJni4x4e0AzpkLYc-t4keRJKOB6EaLzwVsdLeamkFyU
gitea_db_password: Eegh7Aothooph7pa6eu7eitha_zaim0G

View File

@@ -0,0 +1,22 @@
- name: Install Gitea
hosts: gitea
become: true
roles:
- role: ds-gitea
vars:
gitea_user: git
gitea_group: git
gitea_binary_url: https://dl.gitea.com/gitea/1.25.4/gitea-1.25.4-linux-amd64
gitea_checksum_url: https://dl.gitea.com/gitea/1.25.4/gitea-1.25.4-linux-amd64.sha256
gitea_app_name: Tom's IT Cafe Test Gitea Server
gitea_domain: gitea.tomsitcafe.com
gitea_ssh_domain: "{{ gitea_domain }}"
gitea_http_port: 3000
gitea_ssh_port: 22
gitea_root_url: http://{{ gitea_domain }}:{{ gitea_http_port }}
# Secrets to SOPS
gitea_lfs_jwt_secret: G9bZrRHMhRQ8w4R0KkH2VLnx2rzq81ROQ951IQjlMs4
gitea_internal_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3NzA2Mzk1Njh9.ybbaeNLFiLbyvxfj4vkqhXSAXKRGpwvP8jIm9YLPgXw
gitea_jwt_secret: uJni4x4e0AzpkLYc-t4keRJKOB6EaLzwVsdLeamkFyU
gitea_db_password: Eegh7Aothooph7pa6eu7eitha_zaim0G

View File

@@ -0,0 +1,31 @@
- name: Install Gitea
hosts: gitea
become: true
roles:
- role: ds-postgresql
- role: ds-nginx
- role: ds-gitea
vars:
gitea_user: git
gitea_group: git
gitea_database_server: postgresql
gitea_binary_url: https://dl.gitea.com/gitea/1.25.4/gitea-1.25.4-linux-amd64
gitea_checksum_url: https://dl.gitea.com/gitea/1.25.4/gitea-1.25.4-linux-amd64.sha256
gitea_app_name: Tom's IT Cafe Test Gitea Server
gitea_domain: gitea.tomsitcafe.com
gitea_ssh_domain: "{{ gitea_domain }}"
gitea_http_port: 3000
gitea_ssh_port: 22
gitea_root_url: https://{{ gitea_domain }}
gitea_reverse_proxy: nginx
gitea_enable_https: true
gitea_self_signed: true
gitea_ssl_cert: /var/lib/gitea/certs/cert.pem
gitea_ssl_key: /var/lib/gitea/certs/key.pem
gitea_enable_http_redirect: true
# Secrets to SOPS
gitea_lfs_jwt_secret: G9bZrRHMhRQ8w4R0KkH2VLnx2rzq81ROQ951IQjlMs4
gitea_internal_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3NzA2Mzk1Njh9.ybbaeNLFiLbyvxfj4vkqhXSAXKRGpwvP8jIm9YLPgXw
gitea_jwt_secret: uJni4x4e0AzpkLYc-t4keRJKOB6EaLzwVsdLeamkFyU
gitea_db_password: Eegh7Aothooph7pa6eu7eitha_zaim0G

29
tasks/lets-encrypt.yml Normal file
View File

@@ -0,0 +1,29 @@
---
- name: Install certbot
ansible.builtin.apt:
name:
- certbot
state: present
- name: Ensure webroot directory exists
ansible.builtin.file:
path: /var/www/html/.well-known/acme-challenge
state: directory
owner: www-data
group: www-data
mode: '0755'
- name: Obtain or renew TLS certificate (non-destructive)
ansible.builtin.command:
cmd: >
certbot certonly
--webroot
-w /var/www/html
-d {{ gitea_domain }}
--agree-tos
--email {{ gitea_certbot_email }}
--non-interactive
--keep-until-expiring
register: certbot_result
changed_when: "'Congratulations' in certbot_result.stdout"
notify: Reload_nginx

View File

@@ -99,6 +99,11 @@
file: self-signed-cert.yml
when: gitea_self_signed | default(false)
- name: Configure the Let's Encrypt certificates
ansible.builtin.include_tasks:
file: lets-encrypt.yml
when: gitea_lets_encrypt | default(false)
- name: Pause to generate and save the secrets in SOPS
ansible.builtin.pause:
prompt: |

View File

@@ -2,54 +2,71 @@
{% if gitea_enable_https | default(false) %}
server {
listen 443 ssl http2;
server_name {{ gitea_domain }};
listen 443 ssl;
http2 on;
server_name {{ gitea_domain }};
ssl_certificate {{ gitea_ssl_cert }};
ssl_certificate_key {{ gitea_ssl_key }};
ssl_certificate {{ gitea_ssl_cert }};
ssl_certificate_key {{ gitea_ssl_key }};
{% if gitea_lets_encrypt | default(false) %}
ssl_trusted_certificate {{ gitea_ssl_trusted_certificate }};
{% endif %}
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_protocols TLSv1.2 TLSv1.3;
client_max_body_size 50M;
client_max_body_size 50M;
location / {
client_max_body_size 512M;
proxy_pass http://localhost:{{ gitea_http_port }};
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
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;
}
location / {
client_max_body_size 512M;
proxy_pass http://localhost:{{ gitea_http_port }};
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
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;
}
}
{% if gitea_enable_http_redirect | default(true) %}
server {
listen 80;
server_name {{ gitea_domain }};
listen 80;
server_name {{ gitea_domain }};
{% if gitea_lets_encrypt | default(false) %}
# Allow Let's Encrypt to verify certificates
location ^~ /.well-known/acme-challenge/ {
root /var/www/html;
allow all;
}
# Redirect everything else to HTTPS
location / {
return 301 https://$host$request_uri;
}
{% else %}
return 301 https://$host$request_uri;
{% endif %}
}
{% endif %}
{% else %}
# HTTP-only configuration
server {
listen 80;
server_name {{ gitea_domain }};
listen 80;
server_name {{ gitea_domain }};
client_max_body_size 50M;
client_max_body_size 50M;
location / {
client_max_body_size 512M;
proxy_pass http://localhost:{{ gitea_http_port }};
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
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;
}
location / {
client_max_body_size 512M;
proxy_pass http://localhost:{{ gitea_http_port }};
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
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;
}
}
{% endif %}