nginx: path allowlist, GET/HEAD only, CSP and security headers, gzip. README: what the app is, how to use it, CSV format, step-by-step deploy. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
82 lines
3.5 KiB
Nginx Configuration File
82 lines
3.5 KiB
Nginx Configuration File
# Thumbnail Tinder: static site.
|
||
#
|
||
# Куда положить: /etc/nginx/sites-available/thumbnail-tinder
|
||
# (затем ссылка в sites-enabled; на RHEL-подобных системах просто /etc/nginx/conf.d/thumbnail-tinder.conf).
|
||
# Перед запуском замените thumbnails.example.com на свой домен.
|
||
# HTTPS добавляется одной командой после запуска: sudo certbot --nginx -d <домен>
|
||
# (подробности в README.md, раздел «Развёртывание»).
|
||
|
||
server {
|
||
listen 80;
|
||
listen [::]:80;
|
||
server_name thumbnails.example.com;
|
||
|
||
root /var/www/thumbnail-tinder;
|
||
index index.html;
|
||
charset utf-8;
|
||
|
||
access_log /var/log/nginx/thumbnail-tinder.access.log;
|
||
error_log /var/log/nginx/thumbnail-tinder.error.log;
|
||
|
||
# Приложение только отдаёт статику.
|
||
if ($request_method !~ ^(GET|HEAD)$) {
|
||
return 405;
|
||
}
|
||
|
||
# ---------- Сжатие ----------
|
||
gzip on;
|
||
gzip_comp_level 5;
|
||
gzip_min_length 512;
|
||
gzip_vary on;
|
||
gzip_types text/css text/plain application/javascript application/json image/svg+xml;
|
||
# text/html сжимается по умолчанию
|
||
|
||
# ---------- Заголовки безопасности ----------
|
||
# Страницам нужны: шрифты с Google Fonts и превью с i.ytimg.com.
|
||
# Скрипты и стили встроены в HTML, поэтому разрешён 'unsafe-inline'.
|
||
# connect-src 'none': приложение не делает сетевых запросов, файл CSV читается локально в браузере.
|
||
# Важно: add_header в location сбрасывает унаследованные заголовки,
|
||
# поэтому ниже в location используется только expires.
|
||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; img-src 'self' data: https://i.ytimg.com; connect-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'" always;
|
||
add_header X-Content-Type-Options "nosniff" always;
|
||
add_header X-Frame-Options "DENY" always;
|
||
add_header Referrer-Policy "no-referrer" always;
|
||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||
|
||
# ---------- Маршруты: белый список ----------
|
||
# Отдаются только три файла приложения. Всё остальное (в том числе случайно
|
||
# скопированные CSV, .git, README) отвечает 404.
|
||
|
||
location = / {
|
||
try_files /index.html =404;
|
||
expires epoch; # Cache-Control: no-cache, страница всегда свежая
|
||
}
|
||
|
||
location = /index.html {
|
||
expires epoch;
|
||
}
|
||
|
||
location = /liked.html {
|
||
expires epoch;
|
||
}
|
||
|
||
location = /style.css {
|
||
expires 1h; # файл без хеша в имени, поэтому кэш короткий
|
||
}
|
||
|
||
location = /favicon.ico {
|
||
access_log off;
|
||
return 204;
|
||
}
|
||
|
||
# Для certbot (если используется метод webroot, а не --nginx)
|
||
location ^~ /.well-known/acme-challenge/ {
|
||
root /var/www/certbot;
|
||
default_type text/plain;
|
||
}
|
||
|
||
location / {
|
||
return 404;
|
||
}
|
||
}
|