aboutsummaryrefslogtreecommitdiff
path: root/roles/nginx
diff options
context:
space:
mode:
authorMiguel Dalberto Pedro <miguel.pedro@precisioninno.com>2026-10-29 12:48:06 -0300
committerMiguel Dalberto Pedro <miguel.pedro@precisioninno.com>2026-10-29 12:48:06 -0300
commit4b7379914a1865f07b2c54252234cc90158fc253 (patch)
treea476c7e08bb994034d7d04b5b1cdfce216f49c43 /roles/nginx
downloadmy-infra-4b7379914a1865f07b2c54252234cc90158fc253.tar.gz
my-infra-4b7379914a1865f07b2c54252234cc90158fc253.zip
feat(iac): establish Ansible baseline for Nginx, SearXNG, Valkey, and Certbot
- Reverse-engineer live Debian 13 (trixie) VPS state at miguelpedro.xyz.br - Add modular Ansible roles: common, certbot, valkey, searxng, and nginx - Encrypt SearXNG secret_key using ansible-vault in group_vars/all/vault.yml - Cleanly remove unused example.com Nginx stub symlink (sites-enabled/miguelpedro.xyz.br) - Scaffold cgit + fcgiwrap role (cgit_enabled: false) for upcoming deployment - Add DISCOVERY_REPORT.md, COMMAND_LOG.md, README.md, and AGENT_INSTRUCTIONS.md with Self-Updating Protocol
Diffstat (limited to 'roles/nginx')
-rw-r--r--roles/nginx/handlers/main.yml11
-rw-r--r--roles/nginx/tasks/main.yml87
-rw-r--r--roles/nginx/templates/default-app-searxng.conf.j223
-rw-r--r--roles/nginx/templates/nginx.conf.j284
-rw-r--r--roles/nginx/templates/site-default.conf.j2173
-rw-r--r--roles/nginx/templates/site-searxng.conf.j247
6 files changed, 425 insertions, 0 deletions
diff --git a/roles/nginx/handlers/main.yml b/roles/nginx/handlers/main.yml
new file mode 100644
index 0000000..3940edb
--- /dev/null
+++ b/roles/nginx/handlers/main.yml
@@ -0,0 +1,11 @@
+---
+- name: Validate and reload nginx
+ ansible.builtin.command: /usr/sbin/nginx -t
+ changed_when: false
+ notify: Reload nginx service
+
+- name: Reload nginx service
+ ansible.builtin.systemd:
+ name: nginx.service
+ state: reloaded
+ listen: Reload nginx
diff --git a/roles/nginx/tasks/main.yml b/roles/nginx/tasks/main.yml
new file mode 100644
index 0000000..c4f55b6
--- /dev/null
+++ b/roles/nginx/tasks/main.yml
@@ -0,0 +1,87 @@
+---
+- name: Ensure nginx is installed
+ ansible.builtin.apt:
+ name:
+ - nginx
+ state: present
+
+- name: Ensure Nginx directories exist
+ ansible.builtin.file:
+ path: "{{ item }}"
+ state: directory
+ owner: root
+ group: root
+ mode: "0755"
+ loop:
+ - /etc/nginx/sites-available
+ - /etc/nginx/sites-enabled
+ - /etc/nginx/default.apps-available
+ - /etc/nginx/default.d
+ - "{{ default_web_root }}"
+
+- name: Deploy /etc/nginx/nginx.conf
+ ansible.builtin.template:
+ src: nginx.conf.j2
+ dest: /etc/nginx/nginx.conf
+ owner: root
+ group: root
+ mode: "0644"
+ validate: "/usr/sbin/nginx -t -c %s"
+ notify: Reload nginx
+
+- name: Deploy /etc/nginx/default.apps-available/searxng.conf
+ ansible.builtin.template:
+ src: default-app-searxng.conf.j2
+ dest: /etc/nginx/default.apps-available/searxng.conf
+ owner: root
+ group: root
+ mode: "0644"
+ notify: Reload nginx
+
+- name: Enable /etc/nginx/default.d/searxng.conf symlink
+ ansible.builtin.file:
+ src: /etc/nginx/default.apps-available/searxng.conf
+ dest: /etc/nginx/default.d/searxng.conf
+ state: link
+ notify: Reload nginx
+
+- name: Deploy /etc/nginx/sites-available/default
+ ansible.builtin.template:
+ src: site-default.conf.j2
+ dest: /etc/nginx/sites-available/default
+ owner: root
+ group: root
+ mode: "0644"
+ notify: Reload nginx
+
+- name: Deploy /etc/nginx/sites-available/searxng.conf
+ ansible.builtin.template:
+ src: site-searxng.conf.j2
+ dest: /etc/nginx/sites-available/searxng.conf
+ owner: root
+ group: root
+ mode: "0644"
+ notify: Reload nginx
+
+- name: Enable active Nginx sites
+ ansible.builtin.file:
+ src: "/etc/nginx/sites-available/{{ item }}"
+ dest: "/etc/nginx/sites-enabled/{{ item }}"
+ state: link
+ loop:
+ - default
+ - searxng.conf
+ notify: Reload nginx
+
+- name: Remove unused/stub Nginx site symlinks (clean tracking)
+ ansible.builtin.file:
+ path: "/etc/nginx/sites-enabled/{{ item }}"
+ state: absent
+ loop: "{{ nginx_remove_unused_sites | default([]) }}"
+ notify: Reload nginx
+
+- name: Ensure nginx service is enabled and running
+ ansible.builtin.systemd:
+ name: nginx.service
+ enabled: true
+ state: started
diff --git a/roles/nginx/templates/default-app-searxng.conf.j2 b/roles/nginx/templates/default-app-searxng.conf.j2
new file mode 100644
index 0000000..66b1f86
--- /dev/null
+++ b/roles/nginx/templates/default-app-searxng.conf.j2
@@ -0,0 +1,23 @@
+location /searxng {
+
+ uwsgi_pass unix://{{ searxng_socket_path }};
+
+ include uwsgi_params;
+
+ uwsgi_param HTTP_HOST $host;
+ uwsgi_param HTTP_CONNECTION $http_connection;
+
+ # see flaskfix.py
+ uwsgi_param HTTP_X_FORWARDED_PROTO $scheme;
+ uwsgi_param HTTP_X_SCRIPT_NAME /searxng;
+
+ # see botdetection/trusted_proxies.py
+ uwsgi_param HTTP_X_REAL_IP $remote_addr;
+ uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
+}
+
+# To serve the static files via the HTTP server
+#
+# location /searxng/static/ {
+# alias /usr/local/searxng/searxng-src/searx/static/;
+# }
diff --git a/roles/nginx/templates/nginx.conf.j2 b/roles/nginx/templates/nginx.conf.j2
new file mode 100644
index 0000000..68a8fd4
--- /dev/null
+++ b/roles/nginx/templates/nginx.conf.j2
@@ -0,0 +1,84 @@
+user www-data;
+worker_processes auto;
+worker_cpu_affinity auto;
+pid /run/nginx.pid;
+error_log /var/log/nginx/error.log;
+include /etc/nginx/modules-enabled/*.conf;
+
+events {
+ worker_connections 768;
+ # multi_accept on;
+}
+
+http {
+
+ ##
+ # Basic Settings
+ ##
+
+ sendfile on;
+ tcp_nopush on;
+ types_hash_max_size 2048;
+ server_tokens off; # Recommended practice is to turn this off
+
+ # server_names_hash_bucket_size 64;
+ # server_name_in_redirect off;
+
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ ##
+ # SSL Settings
+ ##
+
+ ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3 (POODLE), TLS 1.0, 1.1
+ ssl_prefer_server_ciphers off; # Don't force server cipher order.
+
+ ##
+ # Logging Settings
+ ##
+
+ access_log /var/log/nginx/access.log;
+
+ ##
+ # Gzip Settings
+ ##
+
+ gzip on;
+
+ # gzip_vary on;
+ # gzip_proxied any;
+ # gzip_comp_level 6;
+ # gzip_buffers 16 8k;
+ # gzip_http_version 1.1;
+ # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+ ##
+ # Virtual Host Configs
+ ##
+
+ include /etc/nginx/conf.d/*.conf;
+ include /etc/nginx/sites-enabled/*;
+}
+
+
+#mail {
+# # See sample authentication script at:
+# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
+#
+# # auth_http localhost/auth.php;
+# # pop3_capabilities "TOP" "USER";
+# # imap_capabilities "IMAP4rev1" "UIDPLUS";
+#
+# server {
+# listen localhost:110;
+# protocol pop3;
+# proxy on;
+# }
+#
+# server {
+# listen localhost:143;
+# protocol imap;
+# proxy on;
+# }
+#}
diff --git a/roles/nginx/templates/site-default.conf.j2 b/roles/nginx/templates/site-default.conf.j2
new file mode 100644
index 0000000..2542a3a
--- /dev/null
+++ b/roles/nginx/templates/site-default.conf.j2
@@ -0,0 +1,173 @@
+##
+# You should look at the following URL's in order to grasp a solid understanding
+# of Nginx configuration files in order to fully unleash the power of Nginx.
+# https://www.nginx.com/resources/wiki/start/
+# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
+# https://wiki.debian.org/Nginx/DirectoryStructure
+#
+# In most cases, administrators will remove this file from sites-enabled/ and
+# leave it as reference inside of sites-available where it will continue to be
+# updated by the nginx packaging team.
+#
+# This file will automatically load configuration files provided by other
+# applications, such as Drupal or Wordpress. These applications will be made
+# available underneath a path with that package name, such as /drupal8.
+#
+# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
+##
+
+# Default server configuration
+#
+server {
+ # Load configuration files for the default server block.
+ include /etc/nginx/default.d/*.conf;
+
+ listen 80 default_server;
+ listen [::]:80 default_server;
+
+ # SSL configuration
+ #
+ # listen 443 ssl default_server;
+ # listen [::]:443 ssl default_server;
+ #
+ # Note: You should disable gzip for SSL traffic.
+ # See: https://bugs.debian.org/773332
+ #
+ # Read up on ssl_ciphers to ensure a secure configuration.
+ # See: https://bugs.debian.org/765782
+ #
+ # Self signed certs generated by the ssl-cert package
+ # Don't use them in a production server!
+ #
+ # include snippets/snakeoil.conf;
+
+ root {{ default_web_root }};
+
+ # Add index.php to the list if you are using PHP
+ index index.html index.htm index.nginx-debian.html;
+
+ server_name _;
+
+ location / {
+ # First attempt to serve request as file, then
+ # as directory, then fall back to displaying a 404.
+ try_files $uri $uri/ =404;
+ }
+
+ # pass PHP scripts to FastCGI server
+ #
+ #location ~ \.php$ {
+ # include snippets/fastcgi-php.conf;
+ #
+ # # With php-fpm (or other unix sockets):
+ # fastcgi_pass unix:/run/php/php7.4-fpm.sock;
+ # # With php-cgi (or other tcp sockets):
+ # fastcgi_pass 127.0.0.1:9000;
+ #}
+
+ # deny access to .htaccess files, if Apache's document root
+ # concurs with nginx's one
+ #
+ #location ~ /\.ht {
+ # deny all;
+ #}
+}
+
+
+# Virtual Host configuration for example.com
+#
+# You can move that to a different file under sites-available/ and symlink that
+# to sites-enabled/ to enable it.
+#
+#server {
+# listen 80;
+# listen [::]:80;
+#
+# server_name example.com;
+#
+# root /var/www/example.com;
+# index index.html;
+#
+# location / {
+# try_files $uri $uri/ =404;
+# }
+#}
+
+server {
+
+ # SSL configuration
+ #
+ # listen 443 ssl default_server;
+ # listen [::]:443 ssl default_server;
+ #
+ # Note: You should disable gzip for SSL traffic.
+ # See: https://bugs.debian.org/773332
+ #
+ # Read up on ssl_ciphers to ensure a secure configuration.
+ # See: https://bugs.debian.org/765782
+ #
+ # Self signed certs generated by the ssl-cert package
+ # Don't use them in a production server!
+ #
+ # include snippets/snakeoil.conf;
+
+ root {{ default_web_root }};
+
+ # Add index.php to the list if you are using PHP
+ index index.html index.htm index.nginx-debian.html;
+ server_name {{ primary_domain_aliases | join(' ') }} {{ primary_domain }}; # managed by Certbot
+
+
+ location / {
+ # First attempt to serve request as file, then
+ # as directory, then fall back to displaying a 404.
+ try_files $uri $uri/ =404;
+ }
+
+ # pass PHP scripts to FastCGI server
+ #
+ #location ~ \.php$ {
+ # include snippets/fastcgi-php.conf;
+ #
+ # # With php-fpm (or other unix sockets):
+ # fastcgi_pass unix:/run/php/php7.4-fpm.sock;
+ # # With php-cgi (or other tcp sockets):
+ # fastcgi_pass 127.0.0.1:9000;
+ #}
+
+ # deny access to .htaccess files, if Apache's document root
+ # concurs with nginx's one
+ #
+ #location ~ /\.ht {
+ # deny all;
+ #}
+
+
+ listen 443 ssl; # managed by Certbot
+ listen [::]:443 ssl ipv6only=on; # managed by Certbot
+ ssl_certificate /etc/letsencrypt/live/{{ primary_domain }}/fullchain.pem; # managed by Certbot
+ ssl_certificate_key /etc/letsencrypt/live/{{ primary_domain }}/privkey.pem; # managed by Certbot
+ include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
+
+
+
+}
+server {
+{% for alias in primary_domain_aliases %}
+ if ($host = {{ alias }}) {
+ return 301 https://$host$request_uri;
+ } # managed by Certbot
+
+
+{% endfor %}
+ if ($host = {{ primary_domain }}) {
+ return 301 https://$host$request_uri;
+ } # managed by Certbot
+
+
+ listen 80 ;
+ listen [::]:80 ;
+ server_name {{ primary_domain_aliases | join(' ') }} {{ primary_domain }};
+ return 404; # managed by Certbot
+}
diff --git a/roles/nginx/templates/site-searxng.conf.j2 b/roles/nginx/templates/site-searxng.conf.j2
new file mode 100644
index 0000000..67a5a2d
--- /dev/null
+++ b/roles/nginx/templates/site-searxng.conf.j2
@@ -0,0 +1,47 @@
+server {
+ server_name {{ searxng_domain }};
+
+ # Disable logging for user privacy
+ access_log /dev/null;
+ error_log /dev/null;
+
+ # Security headers
+ add_header X-Frame-Options "SAMEORIGIN" always;
+ add_header X-Content-Type-Options "nosniff" always;
+ add_header Referrer-Policy "no-referrer" always;
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
+
+ location / {
+ uwsgi_pass unix://{{ searxng_socket_path }};
+
+ include uwsgi_params;
+
+ uwsgi_param HTTP_HOST $host;
+ uwsgi_param HTTP_CONNECTION $http_connection;
+
+ # see flaskfix.py
+ uwsgi_param HTTP_X_SCHEME $scheme;
+
+ # see limiter.py
+ uwsgi_param HTTP_X_REAL_IP $remote_addr;
+ uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
+ }
+
+ listen 443 ssl; # managed by Certbot
+ listen [::]:443 ssl; # managed by Certbot
+ ssl_certificate /etc/letsencrypt/live/{{ searxng_domain }}/fullchain.pem; # managed by Certbot
+ ssl_certificate_key /etc/letsencrypt/live/{{ searxng_domain }}/privkey.pem; # managed by Certbot
+ include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
+}
+
+server {
+ if ($host = {{ searxng_domain }}) {
+ return 301 https://$host$request_uri;
+ } # managed by Certbot
+
+ listen 80;
+ listen [::]:80;
+ server_name {{ searxng_domain }};
+ return 404; # managed by Certbot
+}