diff --git a/webapps/gitea/defaults/main.yml b/webapps/gitea/defaults/main.yml index d8ee93bd..5d20121b 100644 --- a/webapps/gitea/defaults/main.yml +++ b/webapps/gitea/defaults/main.yml @@ -5,6 +5,7 @@ git_version: '1.18.5' gitea_url: "https://dl.gitea.io/gitea/{{ git_version }}/gitea-{{ git_version }}-linux-amd64" gitea_checksum: "sha256:4766ad9310bd39d50676f8199563292ae0bab3a1922b461ece0feb4611e867f2" domains: ['example.domain.org'] +certbot_admin_email: 'mgauthier@evolix.ca' db_host: '127.0.0.1:3306' db_name: "{{ service }}" db_user: "{{ service }}" diff --git a/webapps/gitea/tasks/main.yml b/webapps/gitea/tasks/main.yml index b19c326b..36a79663 100644 --- a/webapps/gitea/tasks/main.yml +++ b/webapps/gitea/tasks/main.yml @@ -4,6 +4,7 @@ - name: Install main system dependencies apt: name: "{{ system_dep }}" + update_cache: yes - name: Download gitea binary get_url: @@ -47,11 +48,6 @@ state: directory mode: '0755' -- name: Skip if gitea.ini is already present - stat: - path: "/etc/gitea/{{ service }}.ini" - register: gitea_ini - - name: Template gitea ini file template: src: "gitea.ini.j2" @@ -59,7 +55,6 @@ owner: 'root' group: "{{ service }}" mode: '0660' - when: gitea_ini.stat.exists == false - name: Template gitea systemd unit template: @@ -69,7 +64,7 @@ - name: Start gitea systemd unit service: name: "gitea@{{ service }}" - state: started + state: restarted - name: Create the redis dir if needed file: @@ -105,39 +100,53 @@ name: "redis@{{ service }}" state: started -#~ - name: Check if SSL certificate is present and register result - #~ stat: - #~ path: "/etc/letsencrypt/live/{{ domains |first }}/fullchain.pem" - #~ register: ssl +- name: Template nginx snippet for Let's Encrypt/Certbot + template: + src: "letsencrypt.conf.j2" + dest: "/etc/nginx/snippets/letsencrypt.conf" -#~ - name: Generate certificate only if required (first time) - #~ block: - #~ - name: Template vhost without SSL for successfull LE challengce - #~ template: - #~ src: "vhost.conf.j2" - #~ dest: "/etc/nginx/sites-available/{{ service }}.conf" - #~ - name: Enable temporary nginx vhost for gitea - #~ file: - #~ src: "/etc/nginx/sites-available/{{ service }}.conf" - #~ dest: "/etc/nginx/sites-enabled/{{ service }}.conf" - #~ state: link - #~ - name: Reload nginx conf - #~ service: - #~ name: nginx - #~ state: reloaded - #~ - name: Make sure /var/lib/letsencrypt exists and has correct permissions - #~ file: - #~ path: /var/lib/letsencrypt - #~ state: directory - #~ mode: '0755' - #~ - name: Generate certificate with certbot - #~ shell: certbot certonly --webroot --webroot-path /var/lib/letsencrypt -d {{ domains |first }} - #~ when: ssl.stat.exists == true +- name: Check if SSL certificate is present and register result + stat: + path: "/etc/letsencrypt/live/{{ domains |first }}/fullchain.pem" + register: ssl -#~ - name: (Re)check if SSL certificate is present and register result - #~ stat: - #~ path: "/etc/letsencrypt/live/{{ domains |first }}/fullchain.pem" - #~ register: ssl +- name: Generate certificate only if required (first time) + block: + - name: Template vhost without SSL for successfull LE challengce + template: + src: "vhost.conf.j2" + dest: "/etc/nginx/sites-available/{{ service }}.conf" + - name: Enable temporary nginx vhost for gitea + file: + src: "/etc/nginx/sites-available/{{ service }}.conf" + dest: "/etc/nginx/sites-enabled/{{ service }}.conf" + state: link + - name: Reload nginx conf + service: + name: nginx + state: reloaded + - name: Make sure /var/lib/letsencrypt exists and has correct permissions + file: + path: /var/lib/letsencrypt + state: directory + mode: '0755' + - name: Generate certificate with certbot + shell: certbot certonly --webroot --webroot-path /var/lib/letsencrypt --non-interactive --agree-tos --email {{ certbot_admin_email }} -d {{ domains |first }} + - name: Create the ssl dir if needed + file: + path: /etc/nginx/ssl + state: directory + mode: '0750' + - name: Template ssl bloc for nginx vhost + template: + src: "ssl.conf.j2" + dest: "/etc/nginx/ssl/{{ domains |first }}.conf" + when: ssl.stat.exists != true + +- name: (Re)check if SSL certificate is present and register result + stat: + path: "/etc/letsencrypt/live/{{ domains |first }}/fullchain.pem" + register: ssl - name: (Re)template conf file for nginx vhost with SSL template: diff --git a/webapps/gitea/templates/gitea.ini.j2 b/webapps/gitea/templates/gitea.ini.j2 index eb5ea23e..4b1b32a1 100644 --- a/webapps/gitea/templates/gitea.ini.j2 +++ b/webapps/gitea/templates/gitea.ini.j2 @@ -9,7 +9,7 @@ HTTP_ADDR = /home/{{ service }}/gitea.sock UNIX_SOCKET_PERMISSION = 660 OFFLINE_MODE = true SSH_DOMAIN = {{ domains | first }} -ROOT_URL = http://{{ domains | first }}/ +ROOT_URL = https://{{ domains | first }}/ [repository] ROOT = /home/{{ service }}/repositories diff --git a/webapps/gitea/templates/letsencrypt.conf.j2 b/webapps/gitea/templates/letsencrypt.conf.j2 new file mode 100644 index 00000000..6b33847e --- /dev/null +++ b/webapps/gitea/templates/letsencrypt.conf.j2 @@ -0,0 +1,5 @@ +location ~ /.well-known/acme-challenge { + alias /var/lib/letsencrypt/; + try_files $uri =404; + allow all; +} diff --git a/webapps/gitea/templates/ssl.conf.j2 b/webapps/gitea/templates/ssl.conf.j2 new file mode 100644 index 00000000..86194389 --- /dev/null +++ b/webapps/gitea/templates/ssl.conf.j2 @@ -0,0 +1,22 @@ +## +# Certificates +# you need a certificate to run in production. see https://letsencrypt.org/ +## +ssl_certificate /etc/letsencrypt/live/{{ domains | first }}/fullchain.pem; +ssl_certificate_key /etc/letsencrypt/live/{{ domains | first }}/privkey.pem; + +## +# Security hardening (as of Nov 15, 2020) +# based on Mozilla Guideline v5.6 +## + +ssl_protocols TLSv1.2 TLSv1.3; +ssl_prefer_server_ciphers on; +ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; # add ECDHE-RSA-AES256-SHA if you want compatibility with Android 4 +ssl_session_timeout 1d; # defaults to 5m +ssl_session_cache shared:SSL:10m; # estimated to 40k sessions +ssl_session_tickets off; +ssl_stapling on; +ssl_stapling_verify on; +# HSTS (https://hstspreload.org), requires to be copied in 'location' sections that have add_header directives +#add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; diff --git a/webapps/gitea/templates/vhost.conf.j2 b/webapps/gitea/templates/vhost.conf.j2 index 98c22aee..95e85988 100644 --- a/webapps/gitea/templates/vhost.conf.j2 +++ b/webapps/gitea/templates/vhost.conf.j2 @@ -3,19 +3,30 @@ upstream gitea_{{ service }} { } server { - listen 0.0.0.0:80; - listen [::]:80; - #listen 0.0.0.0:443 ssl http2; - #listen [::]:443 ssl http2; + listen 80; + listen [::]:80; + server_name {{ domains | first }}; + + # For certbot + include /etc/nginx/snippets/letsencrypt.conf; + + {% if ssl.stat.exists %} + location / { return 301 https://$host$request_uri; } + {% endif %} +} + +{% if ssl.stat.exists %} +server { + listen 0.0.0.0:443 ssl http2; + listen [::]:443 ssl http2; server_name {{ domains | first }}; + + access_log /var/log/nginx/{{ service }}.access.log; + error_log /var/log/nginx/{{ service }}.error.log; - #include /etc/nginx/letsencrypt.conf; - #include /etc/nginx/ssl/{{ domains | first }}.conf; - - #if ( $scheme = http ) { - # return 301 https://$server_name$request_uri; - #} + include /etc/nginx/snippets/letsencrypt.conf; + include /etc/nginx/ssl/{{ domains | first }}.conf; location / { proxy_pass http://gitea_{{ service }}; @@ -24,3 +35,4 @@ server { proxy_read_timeout 10; } } +{% endif %}