介绍
尽管Sanic可以直接在互联网上运行,但在它前面使用一个代理服务器(如Nginx)可能会很有用。这对于在同一个IP上运行多个虚拟主机,在一个Sanic应用程序旁边提供NodeJS或其他服务特别有用,它还允许高效地提供静态文件。SSL和HTTP/2也很容易在这种代理上实现。
我们将Sanic应用程序设置为仅在本地提供服务 127.0.0.1:8000 ,Nginx安装负责向域内公共互联网提供服务 example.com . 静态文件将从 /var/www/ .
代理Sanic应用程序
应用程序需要设置一个用于识别可信代理的密钥,以便能够识别真实的客户端IP和其他信息。这可以防止任何人在互联网上发送假标题来欺骗他们的IP地址和其他细节。选择任意随机字符串并在app和Nginx config中配置它。
from sanic import Sanic from sanic.response import text app = Sanic("proxied_example") app.config.FORWARDED_SECRET = "YOUR SECRET" @app.get("/") def index(request): # This should display external (public) addresses: return text( f"{request.remote_addr} connected to {request.url_for('index')}\n" f"Forwarded: {request.forwarded}\n" ) if __name__ == '__main__': app.run(host='127.0.0.1', port=8000, workers=8, access_log=False)
由于这将是一个系统服务,请将代码保存到 /srv/sanicexample/sanicexample.py .
要进行测试,请在终端中运行应用程序。
Nginx配置
允许快速透明代理需要相当多的配置,但在大多数情况下,这些都不需要修改,所以请容忍我。
上游服务器需要单独配置 upstream 块来启用HTTP keep alive,这可以极大地提高性能,因此我们使用它而不是直接在中提供上游地址 proxy_pass 指令。在本例中,上游段命名为 server_name ,即公共域名,然后在 Host 标题。您可以根据需要更改命名。还可以为负载平衡和故障转移提供多个服务器。
更改 example.com 你的真实域名,而不是 YOUR SECRET 使用你为你的应用选择的秘密。
upstream example.com { keepalive 100; server 127.0.0.1:8000; #server unix:/tmp/sanic.sock; } server { server_name example.com; listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; # Serve static files if found, otherwise proxy to Sanic location / { root /var/www; try_files $uri @sanic; } location @sanic { proxy_pass http://$server_name; # Allow fast streaming HTTP/1.1 pipes (keep-alive, unbuffered) proxy_http_version 1.1; proxy_request_buffering off; proxy_buffering off; # Proxy forwarding (password configured in app.config.FORWARDED_SECRET) proxy_set_header forwarded "$proxy_forwarded;secret=\"YOUR SECRET\""; # Allow websockets proxy_set_header connection "upgrade"; proxy_set_header upgrade $http_upgrade; } }
为了避免cookie可见性问题和搜索引擎上地址不一致,最好将所有访问者重定向到一个真正的域,始终使用HTTPS:
# Redirect all HTTP to HTTPS with no-WWW server { listen 80 default_server; listen [::]:80 default_server; server_name ~^(?:www\.)?(.*)$; return 301 https://$1$request_uri; } # Redirect WWW to no-WWW server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name ~^www\.(.*)$; return 301 $scheme://$1$request_uri; }
上面的节可以放在配置中 /etc/nginx/sites-available/default 或在其他站点配置中(确保将它们符号链接到 sites-enabled 如果您创建新的)。
确保在主配置中配置了SSL证书,或者添加 ssl_certificate 和 ssl_certificate_key 对每个人的指令 server 侦听SSL的部分。
另外,将这些复制粘贴到 nginx/conf.d/forwarded.conf :
# RFC 7239 Forwarded header for Nginx proxy_pass # Add within your server or location block: # proxy_set_header forwarded "$proxy_forwarded;secret=\"YOUR SECRET\""; # Configure your upstream web server to identify this proxy by that password # because otherwise anyone on the Internet could spoof these headers and fake # their real IP address and other information to your service. # Provide the full proxy chain in $proxy_forwarded map $proxy_add_forwarded $proxy_forwarded { default "$proxy_add_forwarded;by=\"_$hostname\";proto=$scheme;host=\"$http_host\";path=\"$request_uri\""; } # The following mappings are based on # https://www.nginx.com/resources/wiki/start/topics/examples/forwarded/ map $remote_addr $proxy_forwarded_elem { # IPv4 addresses can be sent as-is ~^[0-9.]+$ "for=$remote_addr"; # IPv6 addresses need to be bracketed and quoted ~^[0-9A-Fa-f:.]+$ "for=\"[$remote_addr]\""; # Unix domain socket names cannot be represented in RFC 7239 syntax default "for=unknown"; } map $http_forwarded $proxy_add_forwarded { # If the incoming Forwarded header is syntactically valid, append to it "~^(,[ \\t]*)*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*([ \\t]*,([ \\t]*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*)?)*$" "$http_forwarded, $proxy_forwarded_elem"; # Otherwise, replace it default "$proxy_forwarded_elem"; }
对于不使用 conf.d 和 sites-available ,所有上述配置也可以放在 http 主截面 nginx.conf .
更改后重新加载Nginx配置:
sudo nginx -s reload
现在你应该可以在上连接你的应用了 https://example.com/ . 任何404错误都将由Sanic的错误页处理,并且每当静态文件出现在给定的路径上时,它将由Nginx提供服务。
SSL证书
如果您还没有在服务器上配置有效的证书,现在就可以这样做了。安装 certbot 和 python3-certbot-nginx ,然后运行
certbot --nginx -d example.com -d www.example.com
作为服务运行
这一部分针对的是基于 systemd . 创建单位文件 /etc/systemd/system/sanicexample.service ::
[Unit] Description=Sanic Example [Service] User=nobody WorkingDirectory=/srv/sanicexample ExecStart=/usr/bin/env python3 sanicexample.py Restart=always [Install] WantedBy=multi-user.target
然后重新加载服务文件,启动服务并在引导时启用它:
sudo systemctl daemon-reload sudo systemctl start sanicexample sudo systemctl enable sanicexample