我已将服务器配置移至新服务器,同时使用 apache mod_proxy 配置它以访问 gunicorn/django web 服务器(位于端口 8000 上的 docker 容器内)。以前的服务器使用 apache mod_wsgi 直接访问 django。
因此我更改了一些虚拟主机配置,但我不明白为什么现在一些请求要通过 apache 到 django,而请求服务器名不是我的 DNS 和虚拟主机配置之一……
目前,django 会以Invalid HTTP_HOST header
错误的方式阻止它们,但我想直接在 apache 配置中过滤它们,并了解此类扫描请求如何传递 DNS 和 apache 配置。
以下是我收到的一个典型的 django 错误:
Report at /
Invalid HTTP_HOST header: 'sprucetips.cyou'. You may need to add 'sprucetips.cyou' to ALLOWED_HOSTS.
Request Method: GET
Request URL: https://sprucetips.cyou/
Django Version: 2.2.28
Python Executable: /usr/local/bin/python
Python Version: 3.5.10
...
Request information:
USER: [unable to retrieve the current user]
GET: No GET data
POST: No POST data
FILES: No FILES data
COOKIES: No cookie data
META:
HTTP_ACCEPT_ENCODING = 'gzip'
HTTP_CONNECTION = 'Keep-Alive'
HTTP_HOST = 'sprucetips.cyou'
HTTP_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'
HTTP_X_FORWARDED_FOR = '34.220.181.252'
HTTP_X_FORWARDED_HOST = 'sprucetips.cyou'
HTTP_X_FORWARDED_PROTO = 'https'
HTTP_X_FORWARDED_SERVER = 'mydomain.ca'
PATH_INFO = '/'
QUERY_STRING = ''
RAW_URI = '/'
REMOTE_ADDR = '172.23.0.1'
REMOTE_PORT = '47332'
REQUEST_METHOD = 'GET'
SCRIPT_NAME = ''
SERVER_NAME = '0.0.0.0'
SERVER_PORT = '8000'
SERVER_PROTOCOL = 'HTTP/1.1'
SERVER_SOFTWARE = 'gunicorn/20.1.0'
...
我的 DNS 配置在两个域名上,mydomain.ca 和 mydomain.com。我之前为每个子域名设置了一个 DNS 配置,但现在我只将mydomain.ca
*.mydomain.ca
mydomain.com
*.mydomain.com
它们都设置为同一个 IP。这会是个问题吗?
这是我的虚拟主机:
首先001-mydomain.ca.conf
将任何 80 端口请求重定向到 443 端口
<VirtualHost *:80>
ServerName mydomain.ca
ServerAlias www.mydomain.com www.mydomain.ca mydomain.com sub1.mydomain.ca sub2.mydomain.ca sub3.mydomain.ca
ErrorLog ${APACHE_LOG_DIR}/mydomain.ca.error.log
LogLevel info
CustomLog ${APACHE_LOG_DIR}/mydomain.ca.access.log combined
RewriteEngine on
RewriteCond %{SERVER_NAME} =www.mydomain.ca [OR]
RewriteCond %{SERVER_NAME} =mydomain.com [OR]
RewriteCond %{SERVER_NAME} =www.mydomain.com [OR]
RewriteCond %{SERVER_NAME} =mydomain.ca
RewriteRule ^ https://mydomain.ca%{REQUEST_URI} [END,QSA,R=permanent]
RewriteCond %{SERVER_NAME} =sub1.mydomain.ca
RewriteRule ^ https://sub1.mydomain.ca%{REQUEST_URI} [END,QSA,R=permanent]
RewriteCond %{SERVER_NAME} =sub2.mydomain.ca
RewriteRule ^ https://sub2.mydomain.ca%{REQUEST_URI} [END,QSA,R=permanent]
RewriteCond %{SERVER_NAME} =sub3.mydomain.ca
RewriteRule ^ https://sub3.mydomain.ca%{REQUEST_URI} [END,QSA,R=permanent]
</VirtualHost>
010-mydomain.ca-ssl.conf
<VirtualHost *:443>
ServerName mydomain.ca
ServerAlias www.mydomain.ca sub1.mydomain.ca sub2.mydomain.ca
DocumentRoot /var/www/mydomain.ca
ErrorLog ${APACHE_LOG_DIR}/mydomain.ca.error.log
LogLevel debug
CustomLog ${APACHE_LOG_DIR}/mydomain.ca.access.log combined
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/mydomain.ca/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/mydomain.ca/privkey.pem
RewriteEngine On
RewriteMap exceptions /var/www/mydomain.ca/maintenance_exceptions.map
RewriteCond /var/www/mydomain.ca/maintenance.html -f
RewriteCond /var/www/mydomain.ca/maintenance.enable -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteCond ${exceptions:%{REMOTE_ADDR}} !OK
RewriteRule ^.*$ /maintenance.html [R=503,L]
ErrorDocument 503 /maintenance.html
ProxyRequests Off
ProxyPreserveHost On
RequestHeader set X_FORWARDED_PROTO 'https' env=HTTPS
ProxyPass /static/ !
ProxyPass /media/ !
ProxyPass /favicon.ico !
ProxyPass /maintenance.html !
ProxyPass / http://localhost:8000/
ProxyPassReverse / http://localhost:8000/
Alias /favicon.ico /var/www/mydomain.ca/favicon.ico
Alias /media/ /var/www/mydomain.ca/media/
Alias /static/ /var/www/mydomain.ca/static/
<Directory /var/www/mydomain.ca>
Order allow,deny
Allow from all
</Directory>
<Directory /var/www/mydomain.ca/static>
Header set Cache-Control "max-age=86400, must-revalidate"
</Directory>
</VirtualHost>
<VirtualHost *:443>
ServerName mydomain.com
ServerAlias www.mydomain.com
RewriteEngine On
RewriteRule ^ https://mydomain.ca%{REQUEST_URI} [END,QSA,R=permanent]
</VirtualHost>
其中一个子域名被重定向到另一个 Web 服务器,011-sub3.mydomain.ca-ssl.conf
<VirtualHost *:443>
ServerName sub3.mydomain.ca
ErrorLog ${APACHE_LOG_DIR}/sub3.mydomain.ca.error.log
LogLevel debug
CustomLog ${APACHE_LOG_DIR}/sub3.mydomain.ca.access.log combined
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/mydomain.ca/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/mydomain.ca/privkey.pem
ProxyPreserveHost On
ProxyRequests off
AllowEncodedSlashes NoDecode
ProxyPass /.well-know !
ProxyPass /robots.txt !
ProxyPass / http://localhost:3000/ nocanon
</VirtualHost>
我终于管理了其他子域名,并直接在020-default.mydomain.ca.conf
<VirtualHost *:80 *:443>
ServerName default.mydomain.ca
ServerAlias *.mydomain.ca *.mydomain.com
Redirect 404 /
CustomLog ${APACHE_LOG_DIR}/mydomain.ca.other.log combined
</VirtualHost>
<VirtualHost *:80 *:443>
ServerName <IP>
Redirect 403 /
ErrorDocument 403 "Direct IP access not allowed"
UseCanonicalName Off
CustomLog ${APACHE_LOG_DIR}/mydomain.ca.other.log combined
</VirtualHost>
任何提示、建议或神奇答案都将不胜感激。谢谢。
答案1
除了 AlexD 的回答默认 VirtualHost 应该是第一个,但<VirtualHost *:80 *:443>
不起作用,因为*:80
是用于纯 HTTP 的,而 是*:443
用于 HTTPS 的。您需要将这些配置分开,并添加 TLS 设置(包括 的任何证书)<VirtualHost *:443>
。
此外,RewriteRule
HTTP 到 HTTPS 重定向中的 s 有点过于复杂。
对于子域名,您可以使用mod_rewrite使用带有变量的单一规则:
<VirtualHost *:80>
ServerName sub1.example.net
ServerAlias sub2.example.net sub3.example.net
RewriteEngine On
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>
对于应重定向到规范主机名的主机名,mod_alias将会可取的:
<VirtualHost *:80>
ServerName example.net
ServerAlias www.example.com www.example.net example.com
Redirect "/" "https://www.example.net/"
</VirtualHost>
答案2
摘录自Apache 文档
收到请求后,服务器首先根据本地 IP 地址和端口组合将其映射到最佳匹配项。非通配符具有更高的优先级。如果完全没有基于 IP 和端口的匹配项,则使用“主”服务器配置。
如果多个虚拟主机包含最佳匹配的 IP 地址和端口,则服务器会根据请求的主机名从这些虚拟主机中选择最佳匹配。如果未找到匹配的基于名称的虚拟主机,则将使用与 IP 地址匹配的第一个列出的虚拟主机。因此,给定 IP 地址和端口组合的第一个列出的虚拟主机是该 IP 和端口组合的默认虚拟主机。
您需要重命名您的020-default.mydomain.ca.conf
,000-default.mydomain.ca.conf
以便它是第一个。