Last active
October 27, 2023 22:01
-
-
Save ufth/02cf876800be1bb70411b19718b70dcf to your computer and use it in GitHub Desktop.
безопасный конфиг nginx для wordpress с php-fpm chroot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# /etc/nginx/sites-available/example.com.conf | |
# if you find this config useful, please consider donating bitcoin:1MjxPWAyebHhjQdjLPGcV5oZd5VbEWrAga | |
# а это уже непосредственно сам файл виртуального хоста | |
# разрешаем 30 запросов за 60 секунд с одного ip | |
# этот параметр работает как ограничение скорости км/ч на знаке, | |
# *нельзя* сделать 30 запросов за несколько секунд и ждать следующей минуты | |
# такая запись эквивалентна разрешённой скорости в 0.5 запроса в секунду | |
limit_req_zone $binary_remote_addr zone=login_user:1m rate=30r/m; | |
# ограничиваем количество запросов к поиску сайта с одного ip | |
map $arg_s $is_search { | |
default ""; | |
"~.*" $binary_remote_addr; | |
} | |
limit_req_zone $is_search zone=search_user:1m rate=10r/m; | |
upstream fcgi_user { | |
server 127.0.0.1:9001; | |
} | |
server { | |
listen 80; | |
# listen 443 ssl; | |
# ssl_session_cache shared:SSL:10m; | |
# ssl_session_timeout 10m; | |
# ssl_certificate /etc/nginx/ssl/example.com.crt; | |
# ssl_certificate_key /etc/nginx/ssl/example.com.key; | |
# add_header Strict-Transport-Security "max-age=31536000"; | |
server_name example.com; | |
charset utf-8; | |
#error_log /var/log/nginx/e.example.log crit; | |
error_log /var/log/nginx/e.example.log error; | |
access_log /var/log/nginx/a.example.log wtimes buffer=16k flush=10s; | |
root /www/user/example.com/www; | |
index index.php index.html index.htm; | |
limit_req zone=search_user burst=1 nodelay; | |
include fastcgi_params; | |
fastcgi_index index.php; | |
fastcgi_intercept_errors off; # передавать ли клиенту ответы FastCGI-сервера с кодом больше либо равным 400, или же перенаправлять их на обработку nginx’у с помощью директивы error_page. | |
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; | |
fastcgi_param SCRIPT_FILENAME /www$fastcgi_script_name; | |
fastcgi_param DOCUMENT_ROOT /www; | |
location / { | |
limit_except GET HEAD POST { | |
deny all; | |
} | |
try_files $uri $uri/ /index.php?$args; | |
} | |
# к этим скриптам ВСЕГДА должен быть доступ | |
location = /index.php { | |
limit_except GET HEAD POST { | |
deny all; | |
} | |
include snippet.d/sec_headers; | |
fastcgi_pass fcgi_user; | |
} | |
location = /wp-login.php { | |
limit_except GET HEAD POST { | |
deny all; | |
} | |
limit_req zone=login_user burst=1 nodelay; | |
include snippet.d/sec_headers; | |
fastcgi_pass fcgi_user; | |
} | |
location = /wp-includes/js/tinymce/wp-tinymce.php { | |
limit_except GET HEAD { | |
deny all; | |
} | |
include snippet.d/sec_headers; | |
fastcgi_pass fcgi_user; | |
} | |
location ~* ^/wp-admin/[^/]*\.php$ { | |
limit_except GET HEAD POST { | |
deny all; | |
} | |
include snippet.d/sec_headers; | |
client_max_body_size 16m; | |
try_files $fastcgi_script_name =404; | |
fastcgi_pass fcgi_user; | |
} | |
# к этим скриптам МОЖНО запретить доступ (нужно просто удалить блок) | |
location = /wp-cron.php { | |
limit_except GET HEAD POST { | |
deny all; | |
} | |
include snippet.d/sec_headers; | |
fastcgi_pass fcgi_user; | |
} | |
location = /wp-activate.php { | |
limit_except GET HEAD { | |
deny all; | |
} | |
include snippet.d/sec_headers; | |
fastcgi_pass fcgi_user; | |
} | |
location ~* ^/wp-content/plugins/.*\.php$ { | |
limit_except GET HEAD POST { | |
deny all; | |
} | |
include snippet.d/sec_headers; | |
try_files $fastcgi_script_name =404; | |
fastcgi_pass fcgi_user; | |
} | |
# иногда может понадобится разрешить интерпретацию этих файлов: | |
# | |
# /xmlrpc.php - если вы не работаете с сайтом через клиент на мобильном устройстве | |
# /wp-trackback.php - трэкбэки и пингбэки | |
# /wp-mail.php - если вы не шлёте сайту статьи на почту, откуда он их забирает | |
# /wp-signup.php - регистрация новых пользователей | |
# /wp-comments-post.php - комментарии (подключайте disqus.com) | |
# /wp-cron.php - если вы настроите настоящий крон через | |
# define('DISABLE_WP_CRON', true); | |
# php -q wp-cron.php | |
# /wp-content/themes/*.\.php | |
# /wp-admin/maint/repair.php - ??? | |
# /wp-admin/(?:includes|network|user)/.*\.php - ??? | |
# /wp-blog-header.php - ??? | |
# /wp-links-opml.php - ??? | |
# /wp-load.php - ??? | |
# /wp-settings.php - ??? | |
# запрещаем доступ к WP REST API v2. некоторые плагины могут перестать работать | |
location ~* ^/wp-json/? { | |
return 403; | |
} | |
# запрещаем доступ ко всем остальным скриптам | |
location ~* \.php$ { | |
return 403; | |
} | |
# запрещаем доступ ко всему что начинается с точки (.htaccess, .git/) | |
location ~* /\. { | |
return 403; | |
} | |
# запрещаем доступ к бэкапам и дампам, которые иногда бывают в папке вебсервера | |
location ~* \.(sql|sql\.gz)$ { | |
return 403; | |
} | |
location = /favicon.ico { | |
log_not_found off; | |
access_log off; | |
} | |
location = /robots.txt { | |
allow all; | |
log_not_found off; | |
access_log off; | |
} | |
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|rar|tgz|gz|rar|bz2|doc|docx|xls|xlsx|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ { | |
limit_except GET HEAD { | |
deny all; | |
} | |
#access_log off; | |
log_not_found off; | |
expires max; | |
} | |
location ~* ^.+\.(css|js)$ { | |
limit_except GET HEAD { | |
deny all; | |
} | |
#access_log off; | |
expires 1d; | |
} | |
# если этот конфиг оказался для вас полезен - поддержите автора монеткой bitcoin:1MjxPWAyebHhjQdjLPGcV5oZd5VbEWrAga | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# /etc/nginx/nginx.conf | |
# | |
# справку по любой директиве конфига можно получить так: | |
# http://nginx.org/r/variables_hash_max_size/ru | |
# | |
# лучше использовать значения по-умолчанию для большинства директив и современную версию nginx | |
# | |
# если решили что-то покрутить и потюнить, почитайте официальные рукводства и эти материалы: | |
# https://www.nginx.com/blog/tuning-nginx/ | |
# https://www.nginx.com/resources/admin-guide/serving-static-content/ | |
# Максимальное количество соединений, которые nginx | |
# может обслуживать одновременно определяются произведением двух параметров: | |
# Всего соединений = worker_processes * worker_connections | |
user www-data; | |
# количество рабочих процессов должно быть не больше количества ядер процессора | |
# за исключением ситуации, когда nginx делает много файловых операций. лучше оставить auto | |
worker_processes 2; | |
pid /var/run/nginx.pid; | |
# максимальное число открытых файлов (RLIMIT_NOFILE) для рабочих процессов | |
# нужно помнить, каждое новое соединение создаёт как минимум два открытых "файла" | |
# worker_rlimit_nofile = worker_processes * worker_connections * 2 | |
# ниже установлено значение для двух воркеров для этого примера конфигурации | |
worker_rlimit_nofile 16384; | |
events { | |
# максимальное число соединений, которое одновременно может открыть рабочий процесс | |
worker_connections 4096; | |
# есть смысл включать только для синтетических тестов типа ab и siedge | |
# multi_accept on; | |
} | |
http { | |
include /etc/nginx/mime.types; | |
default_type application/octet-stream; | |
# if you find this config useful, please consider donating bitcoin:1MjxPWAyebHhjQdjLPGcV5oZd5VbEWrAga | |
# обязательно нужно включать sendfile_max_chunk, если включаем sendfile, | |
# иначе один посетитель с быстрым каналом заблокирует рабочий процесс | |
sendfile on; | |
sendfile_max_chunk 1m; | |
tcp_nopush on; | |
error_log /var/log/nginx/error.log; | |
access_log /var/log/nginx/access.log; | |
resolver 8.8.8.8 8.8.4.4; | |
server_tokens off; | |
# увеличиваем размеры бакетов для переменных, | |
# если у нас множество сайтов и переменных | |
# при ошибке "[emerg]: could not build the variables_hash" | |
# variables_hash_max_size 1024; | |
# variables_hash_bucket_size 128; | |
# увеличиваем размер бакета для имён серверов, | |
# если их много или они длинные | |
# e.g. example.com www.example.com somelongsubdomain.example.com | |
# при ошибке "[emerg]: could not build the server_names_hash" | |
# server_names_hash_bucket_size 128; | |
# см. комментарий к large_client_header_buffers ниже. то же самое, но со стороны бэкэнда | |
# при ошибке "[error]: upstream sent too big header while reading response header from upstream" | |
fastcgi_buffers 8 16k; | |
fastcgi_buffer_size 16k; | |
# если к сайту не подключен внешний сервис защиты от DDoS, а соединений много, | |
# можно уменьшить таймаут между двумя операциями чтения ответа клиентом | |
# send_timeout 20s; | |
# и чтения тела запроса клиента | |
# client_body_timeout 20s; | |
# и немного сэкономить память на уже закрытых соединениях (на keep-alive не работает) | |
# reset_timedout_connection on; | |
# увеличивать client_max_body_size здесь не нужно, это нужно сделать в контексте | |
# того локейшна, который будет обрабатывать загружаемые пользователями файлы | |
# часто это локейшн с админкой сайта или вообще отдельный скрипт загрузки | |
# если URI с огромным QUERY_STRING, в заголовках запроса или в cookie куча инфы | |
# Строка запроса не должна превышать размера одного буфера, | |
# иначе клиенту возвращается ошибка 414 (Request-URI Too Large). | |
# Поле заголовка запроса также не должно превышать размера одного буфера, | |
# иначе клиенту возвращается ошибка 400 (Bad Request). | |
# large_client_header_buffers 8 16k; | |
# для высоконагруженных серверов с огромным количеством файлов, можно включить кеширование | |
# дескрипторов открытых файлов, информации об их размерах, времени модификации и иного | |
# open_file_cache max=300000 inactive=20s; | |
# open_file_cache_valid 30s; | |
# open_file_cache_min_uses 2; | |
# open_file_cache_errors on; | |
# при превышении рейтлимита по запросам в секунду возвращаем код 429 "Too Many Requests" | |
limit_req_status 429; | |
# включаем сжатие, причём не только для text/html | |
gzip on; | |
gzip_disable "msie6"; | |
gzip_types | |
text/plain | |
text/css | |
text/xml | |
text/javascript | |
application/json | |
application/javascript | |
application/x-javascript | |
application/xml | |
application/xml+rss; | |
# определяем более информативный формат лога | |
log_format wtimes '$remote_addr - $remote_user [$time_local] "$request" ' | |
'$status $body_bytes_sent "$http_referer" ' | |
'"$http_user_agent" "$http_x_forwarded_for" ' | |
'"$request_time" ' # время обработки запроса в секундах с точностью до миллисекунд; время, прошедшее с момента чтения первых байт от клиента до момента записи в лог после отправки последних байт клиенту | |
'"$request_length" ' # длина запроса (включая строку запроса, заголовок и тело запроса) | |
'"$request_completion" ' # “OK” если запрос завершился, либо пустая строка | |
'"$host" "$server_name" ' # также записываем в лог заголовок Host клиента и server_name | |
'"$upstream_cache_status" ' | |
'"$http_cf_connecting_ip" ' # оригинальный айпишник юзера, пришедшего через cloudflare | |
'"$server_port"'; | |
include /etc/nginx/conf.d/*.conf; | |
include /etc/nginx/sites-enabled/*; | |
# если этот конфиг оказался для вас полезен - поддержите автора монеткой bitcoin:1MjxPWAyebHhjQdjLPGcV5oZd5VbEWrAga | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# /etc/nginx/snippet.d/sec_headers | |
add_header X-Frame-Options SAMEORIGIN; | |
add_header X-Content-Type-Options "nosniff"; | |
add_header X-XSS-Protection "1; mode=block"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment