Nginx部署
介绍
尽管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
https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/
作为服务运行
这一部分针对的是基于 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