feat: fix systemd user and add static-web role
This commit is contained in:
parent
787c171f65
commit
ba94509bca
@ -3,19 +3,23 @@
|
|||||||
# Transparent TCP proxy (no protocol inspection)
|
# Transparent TCP proxy (no protocol inspection)
|
||||||
|
|
||||||
{% if config.http | default(true) %}
|
{% if config.http | default(true) %}
|
||||||
|
upstream {{ domain | replace('.', '_') | replace('-', '_') }}_http {
|
||||||
|
server {{ config.forward_to }}:80;
|
||||||
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
# Using variable forces runtime DNS resolution (avoids startup failures)
|
proxy_pass {{ domain | replace('.', '_') | replace('-', '_') }}_http;
|
||||||
set $upstream_http {{ config.forward_to }};
|
|
||||||
proxy_pass $upstream_http:80;
|
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if config.https | default(true) %}
|
{% if config.https | default(true) %}
|
||||||
|
upstream {{ domain | replace('.', '_') | replace('-', '_') }}_https {
|
||||||
|
server {{ config.forward_to }}:443;
|
||||||
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 443;
|
listen 443;
|
||||||
# Using variable forces runtime DNS resolution (avoids startup failures)
|
proxy_pass {{ domain | replace('.', '_') | replace('-', '_') }}_https;
|
||||||
set $upstream_https {{ config.forward_to }};
|
|
||||||
proxy_pass $upstream_https:443;
|
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@ -57,11 +57,6 @@ http {
|
|||||||
{% if nginx_forwarder and nginx_forwarder | length > 0 %}
|
{% if nginx_forwarder and nginx_forwarder | length > 0 %}
|
||||||
# Stream block for TCP/UDP proxying
|
# Stream block for TCP/UDP proxying
|
||||||
stream {
|
stream {
|
||||||
# DNS resolver for runtime hostname resolution
|
|
||||||
# Using 127.0.0.1 (systemd-resolved) with 30s cache and 5s timeout
|
|
||||||
resolver 127.0.0.1 valid=30s ipv6=off;
|
|
||||||
resolver_timeout 5s;
|
|
||||||
|
|
||||||
# Load stream configurations
|
# Load stream configurations
|
||||||
include {{ nginx_streams_dir }}/*.conf;
|
include {{ nginx_streams_dir }}/*.conf;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,8 @@ After=network-online.target
|
|||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
RemainAfterExit=true
|
RemainAfterExit=true
|
||||||
|
User={{ ansible_user }}
|
||||||
|
Group={{ ansible_user }}
|
||||||
WorkingDirectory={{ podman_projects_dir }}/ntfy
|
WorkingDirectory={{ podman_projects_dir }}/ntfy
|
||||||
ExecStart=/usr/bin/podman-compose up -d
|
ExecStart=/usr/bin/podman-compose up -d
|
||||||
ExecStop=/usr/bin/podman-compose down
|
ExecStop=/usr/bin/podman-compose down
|
||||||
|
|||||||
110
roles/static-web/README.md
Normal file
110
roles/static-web/README.md
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# static-web
|
||||||
|
|
||||||
|
Deploy static websites from Git repositories with Nginx.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Clone static sites from Git repositories
|
||||||
|
- Automatic Nginx vhost configuration
|
||||||
|
- HTTPS enabled by default with Let's Encrypt
|
||||||
|
- Support for build commands (npm, hugo, jekyll, etc.)
|
||||||
|
- Subdirectory serving (for built assets)
|
||||||
|
- Static file caching
|
||||||
|
- Security headers (including HSTS for HTTPS)
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- nginx role (automatically included via meta/main.yml)
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
See [defaults/main.yml](defaults/main.yml)
|
||||||
|
|
||||||
|
**Main configuration:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
static_web_sites:
|
||||||
|
"portfolio.example.fr":
|
||||||
|
git_repo: "https://github.com/example/portfolio.git"
|
||||||
|
git_branch: "main" # Optional, defaults to main
|
||||||
|
git_depth: 1 # Optional, shallow clone
|
||||||
|
build_command: "npm install && npm run build" # Optional
|
||||||
|
root_dir: "dist" # Optional, serve subdirectory
|
||||||
|
ssl_enabled: true # Optional, defaults to true (HTTPS)
|
||||||
|
|
||||||
|
"blog.example.com":
|
||||||
|
git_repo: "https://github.com/example/blog.git"
|
||||||
|
# ssl_enabled defaults to true, set to false for HTTP only
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
**Inventory (host_vars or group_vars):**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
static_web_sites:
|
||||||
|
"portfolio.example.fr":
|
||||||
|
git_repo: "https://github.com/username/portfolio.git"
|
||||||
|
|
||||||
|
"docs.example.com":
|
||||||
|
git_repo: "https://github.com/company/documentation.git"
|
||||||
|
git_branch: "gh-pages"
|
||||||
|
root_dir: "_site"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Playbook:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- hosts: webservers
|
||||||
|
roles:
|
||||||
|
- static-web
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
Sites are deployed to `/var/www/static/<hostname>/`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
/var/www/static/
|
||||||
|
├── portfolio.example.fr/
|
||||||
|
│ └── index.html
|
||||||
|
└── blog.example.com/
|
||||||
|
├── _site/ # Built assets (if root_dir specified)
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Examples
|
||||||
|
|
||||||
|
**Hugo site:**
|
||||||
|
```yaml
|
||||||
|
static_web_sites:
|
||||||
|
"blog.example.com":
|
||||||
|
git_repo: "https://github.com/example/hugo-blog.git"
|
||||||
|
build_command: "hugo --minify"
|
||||||
|
root_dir: "public"
|
||||||
|
```
|
||||||
|
|
||||||
|
**React app:**
|
||||||
|
```yaml
|
||||||
|
static_web_sites:
|
||||||
|
"app.example.com":
|
||||||
|
git_repo: "https://github.com/example/react-app.git"
|
||||||
|
build_command: "npm ci && npm run build"
|
||||||
|
root_dir: "build"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Updating Sites
|
||||||
|
|
||||||
|
Re-run the playbook to pull latest changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i inventory playbook.yml --tags static-web
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Nginx configuration is deployed to `{{ nginx_conf_dir }}/<hostname>.conf`
|
||||||
|
- Sites are owned by nginx user (www-data on Debian, http on Arch)
|
||||||
|
- Git clones use shallow clone (depth=1) by default for efficiency
|
||||||
|
- Build commands run as nginx user
|
||||||
20
roles/static-web/defaults/main.yml
Normal file
20
roles/static-web/defaults/main.yml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
# Static web sites configuration
|
||||||
|
# Define sites as a dictionary with hostname as key
|
||||||
|
# Example:
|
||||||
|
# static_web_sites:
|
||||||
|
# "portfolio.example.fr":
|
||||||
|
# git_repo: "https://github.com/example/portfolio.git"
|
||||||
|
# git_branch: "main" # optional, defaults to main
|
||||||
|
# git_depth: 1 # optional, shallow clone depth
|
||||||
|
# build_command: "" # optional, command to run after git clone (e.g., npm build)
|
||||||
|
# root_dir: "" # optional, subdirectory to serve (e.g., "dist" or "build")
|
||||||
|
# ssl_enabled: true # optional, enable HTTPS with Let's Encrypt (default: true)
|
||||||
|
|
||||||
|
static_web_sites: {}
|
||||||
|
|
||||||
|
# Base directory for static web sites
|
||||||
|
static_web_base_dir: /var/www/static
|
||||||
|
|
||||||
|
# Nginx user (auto-detected from nginx role)
|
||||||
|
# static_web_nginx_user: www-data # Set by nginx role vars
|
||||||
5
roles/static-web/handlers/main.yml
Normal file
5
roles/static-web/handlers/main.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
- name: Reload nginx
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: nginx
|
||||||
|
state: reloaded
|
||||||
3
roles/static-web/meta/main.yml
Normal file
3
roles/static-web/meta/main.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- role: nginx
|
||||||
67
roles/static-web/tasks/main.yml
Normal file
67
roles/static-web/tasks/main.yml
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
---
|
||||||
|
- name: Load OS-specific variables for nginx
|
||||||
|
ansible.builtin.include_vars: "{{ item }}"
|
||||||
|
with_first_found:
|
||||||
|
- "../../nginx/vars/{{ ansible_facts['os_family'] }}.yml"
|
||||||
|
- "../../nginx/vars/debian.yml"
|
||||||
|
|
||||||
|
- name: Install git
|
||||||
|
ansible.builtin.package:
|
||||||
|
name: git
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Ensure static web base directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ static_web_base_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Create site directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ static_web_base_dir }}/{{ item.key }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ nginx_user }}"
|
||||||
|
group: "{{ nginx_user }}"
|
||||||
|
mode: "0755"
|
||||||
|
loop: "{{ static_web_sites | dict2items }}"
|
||||||
|
when: static_web_sites | length > 0
|
||||||
|
|
||||||
|
- name: Clone or update git repositories
|
||||||
|
ansible.builtin.git:
|
||||||
|
repo: "{{ item.value.git_repo }}"
|
||||||
|
dest: "{{ static_web_base_dir }}/{{ item.key }}"
|
||||||
|
version: "{{ item.value.git_branch | default('main') }}"
|
||||||
|
depth: "{{ item.value.git_depth | default(1) }}"
|
||||||
|
force: true
|
||||||
|
loop: "{{ static_web_sites | dict2items }}"
|
||||||
|
when: static_web_sites | length > 0
|
||||||
|
become_user: "{{ nginx_user }}"
|
||||||
|
notify: Reload nginx
|
||||||
|
|
||||||
|
- name: Run build commands if specified
|
||||||
|
ansible.builtin.shell: "{{ item.value.build_command }}"
|
||||||
|
args:
|
||||||
|
chdir: "{{ static_web_base_dir }}/{{ item.key }}"
|
||||||
|
loop: "{{ static_web_sites | dict2items }}"
|
||||||
|
when:
|
||||||
|
- static_web_sites | length > 0
|
||||||
|
- item.value.build_command is defined
|
||||||
|
- item.value.build_command | length > 0
|
||||||
|
become_user: "{{ nginx_user }}"
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Deploy nginx vhost configurations
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: nginx-vhost.conf.j2
|
||||||
|
dest: "{{ nginx_conf_dir }}/{{ item.key }}.conf"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
loop: "{{ static_web_sites | dict2items }}"
|
||||||
|
vars:
|
||||||
|
hostname: "{{ item.key }}"
|
||||||
|
site_config: "{{ item.value }}"
|
||||||
|
when: static_web_sites | length > 0
|
||||||
|
notify: Reload nginx
|
||||||
79
roles/static-web/templates/nginx-vhost.conf.j2
Normal file
79
roles/static-web/templates/nginx-vhost.conf.j2
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# Static web vhost for {{ hostname }}
|
||||||
|
# Managed by Ansible - DO NOT EDIT MANUALLY
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name {{ hostname }};
|
||||||
|
|
||||||
|
{% if site_config.ssl_enabled | default(true) %}
|
||||||
|
# Certbot webroot for ACME challenges
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Redirect to HTTPS
|
||||||
|
location / {
|
||||||
|
return 301 https://$server_name$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
listen [::]:443 ssl;
|
||||||
|
server_name {{ hostname }};
|
||||||
|
|
||||||
|
# Let's Encrypt certificates (managed by Certbot)
|
||||||
|
ssl_certificate /etc/letsencrypt/live/{{ hostname }}/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/{{ hostname }}/privkey.pem;
|
||||||
|
|
||||||
|
# SSL configuration
|
||||||
|
ssl_protocols {{ nginx_ssl_protocols }};
|
||||||
|
ssl_prefer_server_ciphers {{ 'on' if nginx_ssl_prefer_server_ciphers else 'off' }};
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
# Document root
|
||||||
|
{% if site_config.root_dir is defined and site_config.root_dir | length > 0 %}
|
||||||
|
root {{ static_web_base_dir }}/{{ hostname }}/{{ site_config.root_dir }};
|
||||||
|
{% else %}
|
||||||
|
root {{ static_web_base_dir }}/{{ hostname }};
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
# Index files
|
||||||
|
index index.html index.htm;
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
{% if site_config.ssl_enabled | default(true) %}
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
{% if nginx_log_backend == 'journald' %}
|
||||||
|
access_log syslog:server=unix:/dev/log,nohostname,tag=nginx_{{ hostname | replace('.', '_') | replace('-', '_') }};
|
||||||
|
error_log syslog:server=unix:/dev/log,nohostname,tag=nginx_{{ hostname | replace('.', '_') | replace('-', '_') }};
|
||||||
|
{% else %}
|
||||||
|
access_log /var/log/nginx/{{ hostname }}-access.log;
|
||||||
|
error_log /var/log/nginx/{{ hostname }}-error.log;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
# Main location
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deny access to hidden files
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
|
access_log off;
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Static file caching
|
||||||
|
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -165,6 +165,9 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
After=wg-quick@wg0.service
|
After=wg-quick@wg0.service
|
||||||
Requires=wg-quick@wg0.service
|
Requires=wg-quick@wg0.service
|
||||||
|
# Make Unbound part of network-online.target (provides DNS)
|
||||||
|
Before=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
notify: Reload systemd and restart unbound
|
notify: Reload systemd and restart unbound
|
||||||
|
|
||||||
- name: Enables unbound service
|
- name: Enables unbound service
|
||||||
|
|||||||
@ -6,6 +6,8 @@ After=network-online.target
|
|||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
RemainAfterExit=true
|
RemainAfterExit=true
|
||||||
|
User={{ ansible_user }}
|
||||||
|
Group={{ ansible_user }}
|
||||||
WorkingDirectory={{ podman_projects_dir }}/uptime-kuma
|
WorkingDirectory={{ podman_projects_dir }}/uptime-kuma
|
||||||
ExecStart=/usr/bin/podman-compose up -d
|
ExecStart=/usr/bin/podman-compose up -d
|
||||||
ExecStop=/usr/bin/podman-compose down
|
ExecStop=/usr/bin/podman-compose down
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user