65741644a3
- dashboard.html: Fix zones, leases, wg_status, cert key names, add services var
- server.py: Pass services to dashboard template via _get_service_status()
- lib/acme.py: Fix dead third date format (%Y%m%d%H%M%z) using astimezone(UTC)
- lib/wireguard.py: Add -- separator to cp command to match sudoers rule
- lib/nginx.py: Replace shallow dict.copy() with {**...} for DEFAULT_SSL
- AGENTS.md: Update test count 149 -> 154
- docs/api.md: Rename cert field expiry -> expires_at
100 lines
3.2 KiB
Plaintext
100 lines
3.2 KiB
Plaintext
# Auto-generated by Vacuum Wall — do not edit manually
|
|
# Domain: {{ domain }}
|
|
|
|
{% if force_ssl %}
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name {{ domain }};
|
|
|
|
# Redirect all HTTP traffic to HTTPS
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
|
|
{% endif %}
|
|
server {
|
|
listen 443 ssl;
|
|
listen [::]:443 ssl;
|
|
server_name {{ domain }};
|
|
|
|
{% if cert %}
|
|
{% if cert.type == "acme" %}
|
|
# Certificate managed by acme.sh
|
|
{% if cert.email %} # ACME contact: {{ cert.email }}
|
|
{% endif %} ssl_certificate /home/vacuum-wall/.acme.sh/{{ domain }}/fullchain.cer;
|
|
ssl_certificate_key /home/vacuum-wall/.acme.sh/{{ domain }}/{{ domain }}.key;
|
|
|
|
{% elif cert.type == "file" %}
|
|
ssl_certificate {{ cert.path }};
|
|
ssl_certificate_key {{ cert.key_path }};
|
|
|
|
{% elif cert.type == "selfsigned" %}
|
|
ssl_certificate /home/wall/vacuum-wall/data/certs/{{ domain }}.crt;
|
|
ssl_certificate_key /home/wall/vacuum-wall/data/certs/{{ domain }}.key;
|
|
|
|
{% endif %}
|
|
{% elif is_management %}
|
|
ssl_certificate /home/wall/vacuum-wall/data/certs/{{ domain }}.crt;
|
|
ssl_certificate_key /home/wall/vacuum-wall/data/certs/{{ domain }}.key;
|
|
|
|
{% endif %}
|
|
# Shared SSL settings
|
|
include snippets/vacuum-wall-ssl.conf;
|
|
|
|
{% if auth %}
|
|
# HTTP basic authentication
|
|
auth_basic "{{ "Vacuum Wall" if is_management else "Restricted" }}";
|
|
auth_basic_user_file {{ auth.htpasswd }};
|
|
|
|
{% endif %}
|
|
{% if not is_management %}
|
|
# Security hardening headers
|
|
add_header X-Content-Type-Options nosniff always;
|
|
add_header X-Frame-Options DENY always;
|
|
add_header X-XSS-Protection "1; mode=block" always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
|
|
# Proxy headers
|
|
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;
|
|
{% for hname, hval in headers.items() %}
|
|
proxy_set_header {{ hname }} {{ hval }};
|
|
{% endfor %}
|
|
{% endif %}
|
|
# Proxy pass to backend
|
|
proxy_pass {{ backend.proto }}://{{ backend.host }}:{{ backend.port }};
|
|
proxy_http_version 1.1;
|
|
|
|
{% if not is_management %}
|
|
# Timeouts
|
|
proxy_connect_timeout 30s;
|
|
proxy_send_timeout 60s;
|
|
proxy_read_timeout 60s;
|
|
proxy_buffering off;
|
|
|
|
# Access / error logs
|
|
access_log /var/log/nginx/{{ domain }}_access.log;
|
|
error_log /var/log/nginx/{{ domain }}_error.log warn;
|
|
{% else %}
|
|
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_connect_timeout 30s;
|
|
proxy_send_timeout 60s;
|
|
proxy_read_timeout 60s;
|
|
proxy_buffering off;
|
|
|
|
access_log /var/log/nginx/wall_mgmt_access.log;
|
|
error_log /var/log/nginx/wall_mgmt_error.log warn;
|
|
{% endif %}
|
|
location / {
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection $connection_upgrade;
|
|
}
|
|
}
|