chore(ansible): Meilisearch/Qdrant stack, web vhost, module-paden
- Meilisearch v1.12 + Qdrant v1.13 toegevoegd aan docker-compose
- Env vars voor MEILI_URL/QDRANT_URL/MISTRAL_API_KEY/FORGEJO_API_TOKEN
- Nieuwe web vhost (wetgit.nl) via wetgit-web.conf.j2
- Systemd service-paden:
- wetgit.service → uvicorn wetgit.api.app:app
- wetgit-celery.service → celery -A wetgit.tasks
- WETGIT_GIT_REPOS_DIR verplaatst naar {{ app_dir }}/app
(data leeft op /opt/wetgit/app/rijk/)
- Nieuwe vault-secrets: meili_master_key, qdrant_api_key, mistral_api_key
This commit is contained in:
parent
34fd5a2bf3
commit
d3536c74a4
11 changed files with 386 additions and 50 deletions
|
|
@ -19,6 +19,7 @@ backend_host: "127.0.0.1"
|
|||
# --- Domains ---
|
||||
server_name: "api.wetgit.nl"
|
||||
forgejo_domain: "git.wetgit.nl"
|
||||
web_domain: "wetgit.nl"
|
||||
|
||||
# --- Forgejo ---
|
||||
forgejo_port: 3000
|
||||
|
|
@ -30,6 +31,17 @@ forgejo_admin_email: coornhert@wetgit.nl
|
|||
redis_port: 6379
|
||||
redis_host: "127.0.0.1"
|
||||
|
||||
# --- Meilisearch ---
|
||||
meili_port: 7700
|
||||
meili_host: "127.0.0.1"
|
||||
meili_env: "development"
|
||||
meili_master_key: "{{ vault_meili_master_key | default('') }}"
|
||||
|
||||
# --- Qdrant ---
|
||||
qdrant_port: 6333
|
||||
qdrant_host: "127.0.0.1"
|
||||
qdrant_api_key: "{{ vault_qdrant_api_key | default('') }}"
|
||||
|
||||
# --- Celery ---
|
||||
celery_concurrency: 2
|
||||
|
||||
|
|
@ -42,7 +54,16 @@ codeberg_api_token: "{{ vault_codeberg_api_token | default('') }}"
|
|||
# --- AgentMail ---
|
||||
agentmail_api_key: "{{ vault_agentmail_api_key }}"
|
||||
|
||||
# --- Mistral AI ---
|
||||
mistral_api_key: "{{ vault_mistral_api_key }}"
|
||||
|
||||
# --- Local source path (for rsync deploy) ---
|
||||
local_src_dir: "{{ playbook_dir }}/../"
|
||||
|
||||
# --- Secrets (from vault.yml) ---
|
||||
# vault_agentmail_api_key
|
||||
# vault_forgejo_api_token
|
||||
# vault_codeberg_api_token (add when Codeberg account is ready)
|
||||
# vault_meili_master_key
|
||||
# vault_qdrant_api_key
|
||||
# vault_mistral_api_key
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
$ANSIBLE_VAULT;1.1;AES256
|
||||
35323237613730303463313335643433616238663932643630636530356461323433666435653436
|
||||
3433343462343538333335343165353538613435613962650a656166366364393564353733343561
|
||||
66643462313261643538653839393365643634376432373665653133383464313636633762366163
|
||||
6562336332396535390a333062323534373963356439353336633964383832313431623934653739
|
||||
37646339376338623536323336353931343039323263666265363763373266343533333236346635
|
||||
37656436623764393037393138343536313666613439666535656631313031343061346130376136
|
||||
64383164643466643162393537343265313632343432336238393030306164636434356463396434
|
||||
34656334383731326131393061333138643435366534333965376666393535316334396662633561
|
||||
61386636336438383563326565336635643663313934326333323939663637653531363261613733
|
||||
38646631333739303737616630663337663265616462346637326539306338613866313762306662
|
||||
38633066323936623233336631653836656531633839643739313966623065313931356630613134
|
||||
39636539643065663963626437383637643932633164306337626330623466313737623532366631
|
||||
6435
|
||||
63366162323335343538313162623831383134396331623163663630653637303866633539653338
|
||||
6230646432306464636466306161316164313533656430340a663833643334636437313133616434
|
||||
62366133353936633734353938323561303334626162383964633734613334373233363138306433
|
||||
3865303365356665620a333037376230306632613032303937383931366533346137633766303062
|
||||
33373962326562313731313030353936373837626435323265333636623631333432373962653561
|
||||
33616435623937313963316531313262346162303961303932383930333831303266393630386635
|
||||
66616463643333303834623932313032343638613333373362313439303436333137626638353062
|
||||
37353434383764633162373862316535626635353436353735346531366364343138623737383138
|
||||
65316363333565336631333333633263643130653965376235333163343335356361643866333661
|
||||
35306666373635646238393961356266623732363233646435393939646165623366326130303533
|
||||
32326366336337633232656435663230396636353164653563626534613433313437656238666539
|
||||
32393630333131376263336136653439393831353662383466346365303532663134623537313531
|
||||
38323739376434303261623235393338363938616535363738653631303737373566633763623862
|
||||
35666165636132356463366237393263626561343139343833373439383265303438633338323131
|
||||
62376364346134346636393330633134363631383234383766363234653565303733653032616230
|
||||
36623730376330343331303064383365366338643834663937356262663466353965313936316237
|
||||
38643933306163363634373236333761326437636434306565623261316430653565373431303064
|
||||
37623864386663613730306431363966323937613961633363343366643864613338326535353232
|
||||
31623835663466333336303434303765353233646531626132323933633835353638323038653763
|
||||
36663333323762653933633462346561313331633162303033646162643236353233363731613635
|
||||
61303164313262613763313231633635626638616366383961646465343163666232
|
||||
|
|
|
|||
|
|
@ -1,23 +1,86 @@
|
|||
---
|
||||
# WetGIT FastAPI application + Celery worker
|
||||
# Deploys to /opt/wetgit/backend with own venv and systemd services
|
||||
# Deploys to /opt/wetgit/backend via rsync from local checkout.
|
||||
#
|
||||
# Directories are created by wetgit-forgejo role (runs first).
|
||||
# This role only manages the FastAPI app and Celery worker.
|
||||
#
|
||||
# NOTE: Services are only enabled when application code exists.
|
||||
# On first deploy (no code yet), this role is effectively a no-op.
|
||||
# This role syncs source code, installs deps, and manages systemd services.
|
||||
|
||||
- name: Check if application code exists
|
||||
# --- Code deployment via rsync ---
|
||||
# NOTE: become: no is required on synchronize tasks because rsync
|
||||
# runs locally and connects to the remote via SSH directly.
|
||||
|
||||
- name: Sync application code to server
|
||||
ansible.posix.synchronize:
|
||||
src: "{{ local_src_dir }}/src/"
|
||||
dest: "{{ app_dir }}/backend/src/"
|
||||
delete: yes
|
||||
rsync_opts:
|
||||
- "--exclude=__pycache__"
|
||||
- "--exclude=*.pyc"
|
||||
become: no
|
||||
notify: restart wetgit
|
||||
|
||||
- name: Sync pyproject.toml
|
||||
ansible.posix.synchronize:
|
||||
src: "{{ local_src_dir }}/pyproject.toml"
|
||||
dest: "{{ app_dir }}/backend/pyproject.toml"
|
||||
become: no
|
||||
notify: restart wetgit
|
||||
|
||||
- name: Check if local templates directory exists
|
||||
stat:
|
||||
path: "{{ app_dir }}/backend/requirements.txt"
|
||||
register: app_code
|
||||
path: "{{ local_src_dir }}/templates"
|
||||
delegate_to: localhost
|
||||
register: local_templates
|
||||
become: no
|
||||
|
||||
- name: Sync web templates
|
||||
ansible.posix.synchronize:
|
||||
src: "{{ local_src_dir }}/templates/"
|
||||
dest: "{{ app_dir }}/backend/templates/"
|
||||
delete: yes
|
||||
rsync_opts:
|
||||
- "--exclude=__pycache__"
|
||||
become: no
|
||||
when: local_templates.stat.exists
|
||||
notify: restart wetgit
|
||||
|
||||
- name: Check if local static directory exists
|
||||
stat:
|
||||
path: "{{ local_src_dir }}/static"
|
||||
delegate_to: localhost
|
||||
register: local_static
|
||||
become: no
|
||||
|
||||
- name: Sync static assets
|
||||
ansible.posix.synchronize:
|
||||
src: "{{ local_src_dir }}/static/"
|
||||
dest: "{{ app_dir }}/backend/static/"
|
||||
delete: yes
|
||||
become: no
|
||||
when: local_static.stat.exists
|
||||
|
||||
- name: Set backend ownership
|
||||
file:
|
||||
path: "{{ app_dir }}/backend"
|
||||
owner: www-data
|
||||
group: www-data
|
||||
recurse: yes
|
||||
|
||||
# --- Python venv and dependencies ---
|
||||
|
||||
- name: Create Python venv
|
||||
command: python3 -m venv {{ app_dir }}/backend/venv
|
||||
args:
|
||||
creates: "{{ app_dir }}/backend/venv/bin/python"
|
||||
when: app_code.stat.exists
|
||||
|
||||
- name: Install application with API dependencies
|
||||
command: "{{ app_dir }}/backend/venv/bin/pip install --upgrade '.[api]'"
|
||||
args:
|
||||
chdir: "{{ app_dir }}/backend"
|
||||
register: pip_install
|
||||
changed_when: "'Successfully installed' in pip_install.stdout"
|
||||
notify: restart wetgit
|
||||
|
||||
- name: Set venv ownership
|
||||
file:
|
||||
|
|
@ -25,14 +88,8 @@
|
|||
owner: www-data
|
||||
group: www-data
|
||||
recurse: yes
|
||||
when: app_code.stat.exists
|
||||
|
||||
- name: Install Python dependencies
|
||||
pip:
|
||||
requirements: "{{ app_dir }}/backend/requirements.txt"
|
||||
virtualenv: "{{ app_dir }}/backend/venv"
|
||||
when: app_code.stat.exists
|
||||
notify: restart wetgit
|
||||
# --- Configuration ---
|
||||
|
||||
- name: Deploy environment file
|
||||
template:
|
||||
|
|
@ -43,6 +100,8 @@
|
|||
mode: "0600"
|
||||
notify: restart wetgit
|
||||
|
||||
# --- Systemd services ---
|
||||
|
||||
- name: Deploy WetGIT systemd service
|
||||
template:
|
||||
src: wetgit.service.j2
|
||||
|
|
@ -61,19 +120,18 @@
|
|||
mode: "0644"
|
||||
notify: restart wetgit-celery
|
||||
|
||||
# Only start services when app code is deployed
|
||||
- name: Enable and start WetGIT service
|
||||
systemd:
|
||||
name: wetgit
|
||||
enabled: yes
|
||||
state: started
|
||||
daemon_reload: yes
|
||||
when: app_code.stat.exists
|
||||
|
||||
- name: Enable and start Celery worker
|
||||
# Celery worker disabled — sync runs via cron, not Celery
|
||||
# Enable when wetgit.pipeline has a proper Celery app
|
||||
- name: Disable Celery worker (not yet configured)
|
||||
systemd:
|
||||
name: wetgit-celery
|
||||
enabled: yes
|
||||
state: started
|
||||
enabled: no
|
||||
state: stopped
|
||||
daemon_reload: yes
|
||||
when: app_code.stat.exists
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ User=www-data
|
|||
Group=www-data
|
||||
WorkingDirectory={{ app_dir }}/backend
|
||||
EnvironmentFile={{ app_dir }}/backend/.env
|
||||
ExecStart={{ app_dir }}/backend/venv/bin/celery -A tasks worker --loglevel=info --concurrency={{ celery_concurrency }}
|
||||
ExecStart={{ app_dir }}/backend/venv/bin/celery -A wetgit.tasks worker --loglevel=info --concurrency={{ celery_concurrency }}
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,28 @@ REDIS_URL=redis://{{ redis_host }}:{{ redis_port }}/0
|
|||
CELERY_BROKER_URL=redis://{{ redis_host }}:{{ redis_port }}/0
|
||||
CELERY_RESULT_BACKEND=redis://{{ redis_host }}:{{ redis_port }}/1
|
||||
|
||||
# Meilisearch
|
||||
MEILI_URL=http://{{ meili_host }}:{{ meili_port }}
|
||||
{% if meili_master_key | length > 0 %}
|
||||
MEILI_MASTER_KEY={{ meili_master_key }}
|
||||
{% endif %}
|
||||
|
||||
# Qdrant
|
||||
QDRANT_URL=http://{{ qdrant_host }}:{{ qdrant_port }}
|
||||
{% if qdrant_api_key | length > 0 %}
|
||||
QDRANT_API_KEY={{ qdrant_api_key }}
|
||||
{% endif %}
|
||||
|
||||
# Mistral AI
|
||||
MISTRAL_API_KEY={{ mistral_api_key }}
|
||||
|
||||
# AgentMail
|
||||
AGENTMAIL_API_KEY={{ agentmail_api_key }}
|
||||
|
||||
# Forgejo
|
||||
FORGEJO_URL=https://{{ forgejo_domain }}
|
||||
FORGEJO_API_TOKEN={{ forgejo_api_token }}
|
||||
|
||||
# Data
|
||||
WETGIT_DATA_DIR={{ data_dir }}
|
||||
WETGIT_GIT_REPOS_DIR={{ data_dir }}/git-repos
|
||||
WETGIT_GIT_REPOS_DIR={{ app_dir }}/app
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ User=www-data
|
|||
Group=www-data
|
||||
WorkingDirectory={{ app_dir }}/backend
|
||||
EnvironmentFile={{ app_dir }}/backend/.env
|
||||
ExecStart={{ app_dir }}/backend/venv/bin/uvicorn main:app --host {{ backend_host }} --port {{ backend_port }} --workers {{ backend_workers }}
|
||||
ExecStart={{ app_dir }}/backend/venv/bin/uvicorn wetgit.api.app:app --host {{ backend_host }} --port {{ backend_port }} --workers {{ backend_workers }}
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
---
|
||||
- name: restart forgejo
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ app_dir }}/docker"
|
||||
services:
|
||||
- forgejo
|
||||
state: restarted
|
||||
|
||||
- name: restart docker stack
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ app_dir }}/docker"
|
||||
state: restarted
|
||||
|
|
|
|||
|
|
@ -45,19 +45,22 @@
|
|||
group: "{{ item.group }}"
|
||||
mode: "0755"
|
||||
loop:
|
||||
# Parents first (owned by root)
|
||||
- { path: "{{ app_dir }}", owner: root, group: root }
|
||||
- { path: "{{ data_dir }}", owner: root, group: root }
|
||||
# Forgejo directories (owned by wetgit user)
|
||||
- { path: "{{ app_dir }}/docker", owner: wetgit, group: wetgit }
|
||||
- { path: "{{ forgejo_data_dir }}", owner: wetgit, group: wetgit }
|
||||
- { path: "{{ forgejo_data_dir }}/gitea/conf", owner: wetgit, group: wetgit }
|
||||
- { path: "{{ data_dir }}/redis", owner: wetgit, group: wetgit }
|
||||
- { path: "{{ data_dir }}/meilisearch", owner: wetgit, group: wetgit }
|
||||
- { path: "{{ data_dir }}/qdrant", owner: wetgit, group: wetgit }
|
||||
- { path: "{{ app_dir }}/scripts", owner: wetgit, group: wetgit }
|
||||
- { path: "{{ app_dir }}/backups", owner: wetgit, group: wetgit }
|
||||
- { path: "{{ app_dir }}/logs", owner: wetgit, group: wetgit }
|
||||
- { path: "{{ app_dir }}/mirrors", owner: wetgit, group: wetgit }
|
||||
# Application directories (owned by www-data for FastAPI/Celery)
|
||||
- { path: "{{ app_dir }}", owner: root, group: root }
|
||||
- { path: "{{ app_dir }}/backend", owner: www-data, group: www-data }
|
||||
- { path: "{{ data_dir }}", owner: root, group: root }
|
||||
- { path: "{{ data_dir }}/git-repos", owner: www-data, group: www-data }
|
||||
|
||||
# --- Forgejo config ---
|
||||
|
|
@ -81,8 +84,8 @@
|
|||
dest: "{{ app_dir }}/docker/docker-compose.yml"
|
||||
owner: wetgit
|
||||
group: wetgit
|
||||
mode: "0644"
|
||||
notify: restart forgejo
|
||||
mode: "0640"
|
||||
notify: restart docker stack
|
||||
|
||||
- name: Start WetGIT Docker stack
|
||||
community.docker.docker_compose_v2:
|
||||
|
|
@ -141,7 +144,7 @@
|
|||
- name: Configure backup cron (weekly Sunday 02:00)
|
||||
cron:
|
||||
name: "wetgit-backup"
|
||||
user: root
|
||||
user: wetgit
|
||||
weekday: "0"
|
||||
hour: "2"
|
||||
minute: "0"
|
||||
|
|
@ -164,3 +167,16 @@
|
|||
hour: "5"
|
||||
minute: "0"
|
||||
job: "find {{ app_dir }}/logs -name '*.log' -mtime +30 -delete"
|
||||
|
||||
# --- IPv4 preference (Hetzner IPv6 causes timeouts to external APIs) ---
|
||||
# TODO: migrate to dt-platform's server role when appropriate
|
||||
|
||||
- name: Ensure IPv4 precedence in gai.conf
|
||||
lineinfile:
|
||||
path: /etc/gai.conf
|
||||
regexp: '^precedence\s+::ffff:0:0/96'
|
||||
line: "precedence ::ffff:0:0/96 100"
|
||||
create: yes
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
|
|
|||
|
|
@ -40,6 +40,64 @@ services:
|
|||
networks:
|
||||
- wetgit
|
||||
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:v1.12
|
||||
container_name: wetgit-meilisearch
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "{{ backend_host }}:{{ meili_port }}:7700"
|
||||
volumes:
|
||||
- {{ data_dir }}/meilisearch:/meili_data
|
||||
environment:
|
||||
- MEILI_ENV={{ meili_env }}
|
||||
{% if meili_master_key | length > 0 %}
|
||||
- MEILI_MASTER_KEY={{ meili_master_key }}
|
||||
{% endif %}
|
||||
- MEILI_LOG_LEVEL=WARN
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
cpus: "2.0"
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: "0.5"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:7700/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- wetgit
|
||||
|
||||
qdrant:
|
||||
image: qdrant/qdrant:v1.13.2
|
||||
container_name: wetgit-qdrant
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "{{ backend_host }}:{{ qdrant_port }}:6333"
|
||||
volumes:
|
||||
- {{ data_dir }}/qdrant:/qdrant/storage
|
||||
{% if qdrant_api_key | length > 0 %}
|
||||
environment:
|
||||
- QDRANT__SERVICE__API_KEY={{ qdrant_api_key }}
|
||||
{% endif %}
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: "1.0"
|
||||
reservations:
|
||||
memory: 128M
|
||||
cpus: "0.25"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/6333'"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- wetgit
|
||||
|
||||
networks:
|
||||
wetgit:
|
||||
name: wetgit-network
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@
|
|||
# IMPORTANT: Only adds vhost configs. Does NOT touch global nginx.conf
|
||||
# (managed by dt-platform's nginx role).
|
||||
#
|
||||
# Strategy: Deploy HTTP-only first → get SSL certs → deploy full HTTPS config.
|
||||
# Strategy:
|
||||
# 1. Check if SSL certs exist
|
||||
# 2. If no cert: deploy HTTP-only config → certbot → deploy HTTPS
|
||||
# 3. If cert exists: deploy HTTPS config directly
|
||||
# 4. Enable vhosts (symlinks) after config files exist
|
||||
|
||||
# --- Step 1: Check existing SSL certificates ---
|
||||
|
||||
|
|
@ -17,7 +21,12 @@
|
|||
path: "/etc/letsencrypt/live/{{ forgejo_domain }}/fullchain.pem"
|
||||
register: ssl_cert_git
|
||||
|
||||
# --- Step 2: Deploy HTTP-only configs for domains without certs ---
|
||||
- name: Check if Web SSL certificate exists
|
||||
stat:
|
||||
path: "/etc/letsencrypt/live/{{ web_domain }}/fullchain.pem"
|
||||
register: ssl_cert_web
|
||||
|
||||
# --- Step 2: Deploy HTTP-only configs for domains that need new certs ---
|
||||
|
||||
- name: Deploy API HTTP-only vhost (pre-SSL)
|
||||
copy:
|
||||
|
|
@ -55,23 +64,51 @@
|
|||
when: not ssl_cert_git.stat.exists
|
||||
notify: reload nginx
|
||||
|
||||
# --- Step 3: Enable vhosts and reload nginx ---
|
||||
- name: Deploy Web HTTP-only vhost (pre-SSL)
|
||||
copy:
|
||||
content: |
|
||||
# Temporary HTTP-only config for SSL provisioning — managed by Ansible
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name {{ web_domain }};
|
||||
location /.well-known/acme-challenge/ { root /var/www/certbot; }
|
||||
location / { return 503; }
|
||||
}
|
||||
dest: /etc/nginx/sites-available/wetgit-web.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
when: not ssl_cert_web.stat.exists
|
||||
notify: reload nginx
|
||||
|
||||
- name: Enable API vhost
|
||||
# --- Step 3: Enable vhosts that need new certs + reload for certbot ---
|
||||
|
||||
- name: Enable API vhost (pre-SSL)
|
||||
file:
|
||||
src: /etc/nginx/sites-available/wetgit-api.conf
|
||||
dest: /etc/nginx/sites-enabled/wetgit-api.conf
|
||||
state: link
|
||||
when: not ssl_cert_api.stat.exists
|
||||
notify: reload nginx
|
||||
|
||||
- name: Enable Forgejo vhost
|
||||
- name: Enable Forgejo vhost (pre-SSL)
|
||||
file:
|
||||
src: /etc/nginx/sites-available/wetgit-git.conf
|
||||
dest: /etc/nginx/sites-enabled/wetgit-git.conf
|
||||
state: link
|
||||
when: not ssl_cert_git.stat.exists
|
||||
notify: reload nginx
|
||||
|
||||
# Force handler to run now so nginx has the HTTP configs before certbot
|
||||
- name: Enable Web vhost (pre-SSL)
|
||||
file:
|
||||
src: /etc/nginx/sites-available/wetgit-web.conf
|
||||
dest: /etc/nginx/sites-enabled/wetgit-web.conf
|
||||
state: link
|
||||
when: not ssl_cert_web.stat.exists
|
||||
notify: reload nginx
|
||||
|
||||
# Force handler to run so nginx has the HTTP configs before certbot
|
||||
- name: Flush handlers (reload nginx for certbot)
|
||||
meta: flush_handlers
|
||||
|
||||
|
|
@ -97,7 +134,34 @@
|
|||
when: not ssl_cert_git.stat.exists
|
||||
register: certbot_git
|
||||
|
||||
# --- Step 5: Deploy full HTTPS configs ---
|
||||
- name: Obtain SSL certificate for {{ web_domain }}
|
||||
command: >
|
||||
certbot certonly --webroot
|
||||
-w /var/www/certbot
|
||||
-d {{ web_domain }}
|
||||
--non-interactive --agree-tos
|
||||
--email coornhert@wetgit.nl
|
||||
when: not ssl_cert_web.stat.exists
|
||||
register: certbot_web
|
||||
|
||||
# --- Step 5: Re-check SSL certs after certbot ---
|
||||
|
||||
- name: Re-check API SSL certificate
|
||||
stat:
|
||||
path: "/etc/letsencrypt/live/{{ server_name }}/fullchain.pem"
|
||||
register: ssl_cert_api_final
|
||||
|
||||
- name: Re-check Forgejo SSL certificate
|
||||
stat:
|
||||
path: "/etc/letsencrypt/live/{{ forgejo_domain }}/fullchain.pem"
|
||||
register: ssl_cert_git_final
|
||||
|
||||
- name: Re-check Web SSL certificate
|
||||
stat:
|
||||
path: "/etc/letsencrypt/live/{{ web_domain }}/fullchain.pem"
|
||||
register: ssl_cert_web_final
|
||||
|
||||
# --- Step 6: Deploy full HTTPS configs + enable vhosts ---
|
||||
|
||||
- name: Deploy API nginx vhost (full HTTPS)
|
||||
template:
|
||||
|
|
@ -106,6 +170,7 @@
|
|||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
when: ssl_cert_api_final.stat.exists
|
||||
notify: reload nginx
|
||||
|
||||
- name: Deploy Forgejo nginx vhost (full HTTPS)
|
||||
|
|
@ -115,4 +180,37 @@
|
|||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
when: ssl_cert_git_final.stat.exists
|
||||
notify: reload nginx
|
||||
|
||||
- name: Deploy Web nginx vhost (full HTTPS)
|
||||
template:
|
||||
src: wetgit-web.conf.j2
|
||||
dest: /etc/nginx/sites-available/wetgit-web.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
when: ssl_cert_web_final.stat.exists
|
||||
notify: reload nginx
|
||||
|
||||
# Enable all vhosts (idempotent — creates symlink if not exists)
|
||||
- name: Enable API vhost
|
||||
file:
|
||||
src: /etc/nginx/sites-available/wetgit-api.conf
|
||||
dest: /etc/nginx/sites-enabled/wetgit-api.conf
|
||||
state: link
|
||||
notify: reload nginx
|
||||
|
||||
- name: Enable Forgejo vhost
|
||||
file:
|
||||
src: /etc/nginx/sites-available/wetgit-git.conf
|
||||
dest: /etc/nginx/sites-enabled/wetgit-git.conf
|
||||
state: link
|
||||
notify: reload nginx
|
||||
|
||||
- name: Enable Web vhost
|
||||
file:
|
||||
src: /etc/nginx/sites-available/wetgit-web.conf
|
||||
dest: /etc/nginx/sites-enabled/wetgit-web.conf
|
||||
state: link
|
||||
notify: reload nginx
|
||||
|
|
|
|||
51
ansible/roles/wetgit-nginx/templates/wetgit-web.conf.j2
Normal file
51
ansible/roles/wetgit-nginx/templates/wetgit-web.conf.j2
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# WetGIT frontend (wetgit.nl) — managed by WetGIT Ansible (not dt-platform)
|
||||
# Do NOT edit manually
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name {{ web_domain }};
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name {{ web_domain }};
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/{{ web_domain }}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/{{ web_domain }}/privkey.pem;
|
||||
|
||||
# Security headers
|
||||
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
# Frontend proxy (same FastAPI app serves the web UI)
|
||||
location / {
|
||||
proxy_pass http://{{ backend_host }}:{{ backend_port }};
|
||||
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;
|
||||
|
||||
proxy_read_timeout 120s;
|
||||
proxy_connect_timeout 10s;
|
||||
}
|
||||
|
||||
# Static assets (served by FastAPI/Starlette)
|
||||
location /static/ {
|
||||
proxy_pass http://{{ backend_host }}:{{ backend_port }}/static/;
|
||||
proxy_set_header Host $host;
|
||||
expires 1d;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue