Я управляю сайтом, где энтузиасты фотографии часто делятся своими работами, и я хочу отключить все сжатие изображений, но при этом включить удаление метаданных. Я внес следующие изменения:
Я установил максимальный размер изображения 40 МБ, максимальное количество мегапикселей — на максимально допустимое значение 150 МП и отключил оптимизацию изображений в редакторе сообщений.
Также я изменил настройки Nginx в контейнере.
Если коротко, я добавил:
client_header_timeout 1m;
client_body_timeout 1m;
proxy_connect_timeout 30s;
proxy_read_timeout 1m;
proxy_send_timeout 1m;
и изменил:
# максимальный размер загружаемого файла (обновляйте при изменении соответствующей настройки на сайте)
client_max_body_size 200m ;
в блоке server{} в файле /etc/nginx/nginx.conf.
Добавил:
client_max_body_size 200m;
client_header_timeout 1m;
client_body_timeout 1m;
proxy_connect_timeout 60s;
proxy_read_timeout 1m;
proxy_send_timeout 1m;
в блок http{} в файле /etc/nginx/nginx.conf.
Вот конфигурации для /etc/nginx/nginx.conf и /etc/nginx/conf.d/discourse.conf:
root@iZj6cgi365ov99veqodfgnZ-app:/var/www/discourse# cat /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
daemon off;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 4000 ;
# multi_accept on;
}
http {
client_max_body_size 200m;
client_header_timeout 1m;
client_body_timeout 1m;
proxy_connect_timeout 60s;
proxy_read_timeout 1m;
proxy_send_timeout 1m;
##
# Базовые настройки
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Настройки SSL
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Отключаем SSLv3, см. POODLE
ssl_prefer_server_ciphers on;
##
# Настройки логирования
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Настройки Gzip
##
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;
##
# Конфигурации виртуальных хостов
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
#mail {
# # См. пример скрипта аутентификации по адресу:
# # 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;
# }
#}
root@iZj6cgi365ov99veqodfgnZ-app:/var/www/discourse# cat /etc/nginx/conf.d/discourse.conf
# Дополнительные MIME-типы, которые вы хотите обрабатывать в nginx, помещаются сюда
types {
text/csv csv;
application/wasm wasm;
}
upstream discourse { server 127.0.0.1:3000; }
# inactive означает, что мы храним данные в течение 1440 минут независимо от последнего доступа (1 неделя)
# levels означает, что это двухуровневая иерархия, так как у нас может быть много файлов
# max_size ограничивает размер кэша
proxy_cache_path /var/nginx/cache inactive=1440m levels=1:2 keys_zone=one:10m max_size=600m;
# Увеличено по сравнению со значением по умолчанию для поддержки больших куки во время потоков oAuth2
# например, в https://meta.discourse.org/t/x/74060 и больших заголовках CSP и Link (preload)
proxy_buffer_size 32k;
proxy_buffers 4 32k;
# Увеличено по сравнению со значением по умолчанию для поддержки большого объема куки в заголовках запроса
# Сам Discourse пытается минимизировать размер куки, но мы не можем контролировать другие куки, устанавливаемые другими инструментами на том же домене.
large_client_header_buffers 4 32k;
# Если вы собираетесь использовать Puma, используйте эти настройки:
#
# upstream discourse {
# server unix:/var/www/discourse/tmp/sockets/puma.sock;
# }
# попытка сохранить протокол, должно быть в контексте http
map $http_x_forwarded_proto $thescheme {
default $scheme;
"~https$" https;
}
log_format log_discourse '[$time_local] "$http_host" $remote_addr "$request" "$http_user_agent" "$sent_http_x_discourse_route" $status $bytes_sent "$http_referer" $upstream_response_time $request_time "$upstream_http_x_discourse_username" "$upstream_http_x_discourse_trackview" "$upstream_http_x_queue_time" "$upstream_http_x_redis_calls" "$upstream_http_x_redis_time" "$upstream_http_x_sql_calls" "$upstream_http_x_sql_time"';
# Разрешить обход кэша с localhost
geo $bypass_cache {
default 0;
127.0.0.1 1;
::1 1;
}
limit_req_zone $binary_remote_addr zone=flood:10m rate=12r/s;
limit_req_zone $binary_remote_addr zone=bot:10m rate=200r/m;
limit_req_status 429;
limit_conn_zone $binary_remote_addr zone=connperip:10m;
limit_conn_status 429;
server {
listen 80;
return 301 https://kongjiang.org$request_uri;
}
server {
access_log /var/log/nginx/access.log log_discourse;
listen 443 ssl http2;
listen [::]:443 ssl http2;
client_header_timeout 1m;
client_body_timeout 1m;
proxy_connect_timeout 30s;
proxy_read_timeout 1m;
proxy_send_timeout 1m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_certificate /shared/ssl/kongjiang.org.cer;
ssl_certificate /shared/ssl/kongjiang.org_ecc.cer;
ssl_certificate_key /shared/ssl/kongjiang.org.key;
ssl_certificate_key /shared/ssl/kongjiang.org_ecc.key;
ssl_session_tickets off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:1m;
gzip on;
add_header Strict-Transport-Security 'max-age=63072000';
if ($http_host != kongjiang.org) {
rewrite (.*) https://kongjiang.org$1 permanent;
}
gzip_vary on;
gzip_min_length 1000;
gzip_comp_level 5;
gzip_types application/json text/css text/javascript application/x-javascript application/javascript image/svg+xml application/wasm;
gzip_proxied any;
# Раскомментируйте и настройте этот раздел для поддержки HTTPS
# ПРИМЕЧАНИЕ: Поместите ваш SSL-сертификат в основную директорию конфигурации nginx (/etc/nginx)
#
# rewrite ^/(.*) https://enter.your.web.hostname.here/$1 permanent;
#
# listen 443 ssl;
# ssl_certificate your-hostname-cert.pem;
# ssl_certificate_key your-hostname-cert.key;
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers HIGH:!aNULL:!MD5;
#
server_name _ ;
server_tokens off;
sendfile on;
keepalive_timeout 65;
# максимальный размер загружаемого файла (обновляйте при изменении соответствующей настройки на сайте)
client_max_body_size 200m ;
# путь к публичной директории Discourse
set $public /var/www/discourse/public;
# без слабых ETag мы не получаем никакой выгоды от ETag для динамически сжимаемого контента
# кроме того, ETag основаны на файле в nginx, а не на хэше данных
# используйте даты, это решает проблему нормально даже между серверами
etag off;
# предотвратить прямую загрузку резервных копий
location ^~ /backups/ {
internal;
}
# обход стека Rails с помощью дешевого 204 для запросов favicon.ico
location /favicon.ico {
return 204;
access_log off;
log_not_found off;
}
location / {
root $public;
add_header ETag "";
# auth_basic on;
# auth_basic_user_file /etc/nginx/htpasswd;
location ~ ^/uploads/short-url/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_pass http://discourse;
break;
}
location ~ ^/(secure-media-uploads/|secure-uploads)/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_pass http://discourse;
break;
}
location ~* (fonts|assets|plugins|uploads)/.*\.(eot|ttf|woff|woff2|ico|otf)$ {
expires 1y;
add_header Cache-Control public,immutable;
add_header Access-Control-Allow-Origin *;
}
location = /srv/status {
access_log off;
log_not_found off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_pass http://discourse;
break;
}
# здесь минимальное кэширование, чтобы мы не спрашивали постоянно
# в долгосрочной перспективе, вероятно, стоит увеличить до 1 года
location ~ ^/javascripts/ {
expires 1d;
add_header Cache-Control public,immutable;
add_header Access-Control-Allow-Origin *;
}
location ~ ^/assets/(?<asset_path>.+)$ {
expires 1y;
# конвейер ресурсов включает это
brotli_static on;
gzip_static on;
add_header Cache-Control public,immutable;
# ВКЛЮЧЕНИЕ в расположение ресурсов (используется для расширяемости)
# TODO, я не думаю, что этот break нужен, он просто выходит из rewrite
break;
}
location ~ ^/plugins/ {
expires 1y;
add_header Cache-Control public,immutable;
add_header Access-Control-Allow-Origin *;
}
# кэширование эмодзи
location ~ /images/emoji/ {
expires 1y;
add_header Cache-Control public,immutable;
add_header Access-Control-Allow-Origin *;
}
location ~ ^/uploads/ {
# ПРИМЕЧАНИЕ: очень раздражает, что мы не можем просто определить заголовки
# на верхнем уровне и наследовать их.
#
# proxy_set_header НЕ наследуется, по дизайну, мы должны повторять его,
# иначе заголовки не будут установлены правильно
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
proxy_set_header X-Accel-Mapping $public/=/downloads/;
expires 1y;
add_header Cache-Control public,immutable;
## опциональные правила защиты от хотлинкинга при загрузке
#valid_referers none blocked mysite.com *.mysite.com;
#if ($invalid_referer) { return 403; }
# пользовательские CSS
location ~ /stylesheet-cache/ {
add_header Access-Control-Allow-Origin *;
try_files $uri =404;
}
# это позволяет нам обходить Rails
location ~* \.(gif|png|jpg|jpeg|bmp|tif|tiff|ico||avif)$ {
add_header Access-Control-Allow-Origin *;
try_files $uri =404;
}
# SVG требует дополнительного заголовка
location ~* \.(svg)$ {
}
# миниатюры и оптимизированные изображения
location ~ /_?optimized/ {
add_header Access-Control-Allow-Origin *;
try_files $uri =404;
}
proxy_pass http://discourse;
break;
}
location ~ ^/admin/backups/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
proxy_set_header X-Accel-Mapping $public/=/downloads/;
proxy_pass http://discourse;
break;
}
# Этот большой блок необходим, чтобы мы могли выборочно включать
# ускорение для резервных копий, аватаров, спрайтов и так далее.
# см. примечание о повторении выше
location ~ ^/(svg-sprite/|letter_avatar/|letter_avatar_proxy/|user_avatar|highlight-js|stylesheets|theme-javascripts|favicon/proxied|service-worker) {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
# если в ответе есть Set-Cookie, ничего не кэшируется
# это двойной промах, так как мы не передаем last modified
proxy_ignore_headers "Set-Cookie";
proxy_hide_header "Set-Cookie";
proxy_hide_header "X-Discourse-Username";
proxy_hide_header "X-Runtime";
# обратите внимание, x-accel-redirect нельзя использовать с proxy_cache
proxy_cache one;
proxy_cache_key "$scheme,$host,$request_uri";
proxy_cache_valid 200 301 302 7d;
proxy_cache_bypass $bypass_cache;
proxy_pass http://discourse;
break;
}
# нам нужно отключить буферизацию для message bus
location /message-bus/ {
proxy_set_header X-Request-Start "t=${msec}";
proxy_set_header Host $http_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 $thescheme;
proxy_http_version 1.1;
proxy_buffering off;
proxy_pass http://discourse;
break;
}
# это означает, что сначала пробуются все файлы в public
try_files $uri @discourse;
}
location /downloads/ {
internal;
alias $public/;
}
location @discourse {
add_header Strict-Transport-Security 'max-age=31536000'; # запомнить сертификат на год и автоматически подключаться к HTTPS для этого домена limit_conn connperip 20;
limit_req zone=flood burst=12 nodelay;
limit_req zone=bot burst=100 nodelay;
proxy_set_header Host $http_host;
proxy_set_header X-Request-Start "t=${msec}";
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 $thescheme;
proxy_pass http://discourse;
}
}
Несмотря на эти изменения, я всё ещё получаю ошибку «файл слишком большой» при загрузке изображений размером более 15 МБ, и при отключённой оптимизации изображений в редакторе сообщений загрузка изображений не удаётся.
Мог бы кто-нибудь подсказать, какие ещё настройки нужно изменить или есть ли проблема в моей конфигурации Nginx?
Я новичок в Nginx и полностью полагался на Google и ChatGPT при внесении этих изменений.