Назад | Перейти на главную страницу

Nginx + Passenger: кешировать 404 URL

Контекст

У меня есть приложение Rails с сервером nginx и Passenger.

Приложение динамически генерирует страницы на основе URL-адреса запроса: если URL-адрес существует в базе данных, приложение отображает соответствующую страницу. Или, если URL-адрес не существует в базе данных, приложение отображает страницу 404.

Проблема

Многие сканеры пытаются найти уязвимости и запрашивают множество URL-адресов (.git, admin / config.php, wp-login.php и т. Д.).

Каждый из этих запросов достигает приложения Rails, которое генерирует обращения в базе данных.

Решение

Я ищу способ сделать это:

  1. первый раз "несуществующий" URL-адрес, если запрашивается, проходит через приложение Rails, которое отвечает 404
  2. nginx кеширует и запоминает этот URL
  3. в следующий раз, когда будет запрошен тот же URL, nginx напрямую ответит со статусом 404 без прохождения через приложение Rails

Также, когда приложение Rails перезапускается (через Passenger), этот кеш должен быть очищен.

Пытается

Как вы понимаете, я новичок в nginx. Спасибо за вашу помощь.

Конфигурация Nginx

server {
  listen ...;

  server_name ...;

  root /path/to/rails/app;

  error_page 404 /404;
  error_page 500 502 503 504 /500;

  # First I tried this, no success so I removed it
  fastcgi_cache_valid 404 10m;

  # Then I tried this, no success so I removed it also
  proxy_cache_valid 404 10m;

  location / {
    gzip_static on;
    etag off;
    charset utf-8;
    add_header Cache-Control "max-age=0, private, must-revalidate";
    add_header Referrer-Policy strict-origin-when-cross-origin;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options deny;
    add_header X-XSS-Protection "1; mode=block";

    location = / {
      try_files /cached/index.html @rails;
    }

    location / {
      try_files /cached$uri.html /cached$uri $uri @rails;
    }
  }

  location @rails {
    passenger_enabled on;
    passenger_ruby /path/to/ruby;
    passenger_app_env production;
  }
}

Я больше всего знаком с кешированием в среде обратного прокси, поэтому я выберу именно такой подход. К счастью, Nginx может довольно легко проксировать для себя:

# define your cache
proxy_cache_path /path/to/cache levels=1:2 keys_zone=cacheName:[metaDataSize] max_size=[maxCacheSize] inactive=60m use_temp_path=off;

http {
  server {
    # Any TLS, caching, or gzipping on this virtual server
    listen ...;
    server_name [Actual Domain];

    location / {
      proxy_pass http://127.0.0.1:80;
      proxy_set_header Host [domain.passenger];

      # Activate and configure caching here
      proxy_cache cacheName;
      proxy_cache_valid 404 10m;
      ...any other proxy settings you want.

      # Forward original request info
      proxy_set_header X-Original-Host $http_host;
      proxy_set_header X-Original-Scheme $scheme;
      proxy_set_header X-Forwarded-For $remote_addr;

      # Gzip if you want
      gzip on;
      gzip_proxied any;

      ...etc
    }
  }

  server {
    # Any Rails/Passenger configuration on this virtual server
    listen 80;
    server_name [domain.passenger]; 

    # Don't log requests twice
    access_log off; 

    # Only allow local requests
    allow 127.0.0.1;
    deny all;

    location / {
      passenger_enabled on;
      passenger_ruby /path/to/ruby;
      passenger_app_env production;
    }
  }
}

Для очистки кеша просто нужно запустить rm -rf /path/to/cache/*, чтобы вы могли встроить это в свои процедуры перезапуска Rails любым удобным для вас способом.