问题
I have deployed a WSGI application with uWSGI, but I am not using NGINX. How can I use uWSGI's internal routing to redirect http
requests to https
?
I have tried uwsgi --route-uri="^http:\/\/(.+)$ redirect-permanent:https://\$1"
but get an error from uWSGI: unrecognized option '--route-uri=^https:\/\/(.+)$ redirect-permanent:https://\$1'
回答1:
to redirect http to https, use following config:
[uwsgi]
; privileged port can only be opened as shared socket
shared-socket = 0.0.0.0:80
shared-socket = 0.0.0.0:443
;enable redirect to https
http-to-https = =0
; enable https, spdy is optional
https2 = addr==1,cert=server.crt,key=server.key,spdy=1
; alternative
; https = =1,server.crt,server.key
; force change of user after binding to ports as root
uid = user
gid = usergroup
; where original app will be running on IP or UNIX socket
socket = 127.0.0.1:8001
module = smthg.wsgi
回答2:
If your reverse proxy or load balancer passes X-Forwarded-Proto header along with the request, the following config will work:
[uwsgi]
http-socket = :3031
<... your uwsgi config options here ... >
route-if=equal:${HTTP_X_FORWARDED_PROTO};http redirect-permanent:https://<your_host_name_here>${REQUEST_URI}
Some load balancers, such as AWS ELB pass this header automatically.
回答3:
To build on Oleg's answer: For this to work, you'll need to manually add some headers to stop UWSGI causing the 502 errors at the ELB.
route-if=equal:${HTTP_X_FORWARDED_PROTO};http addheader:Content-Type: */*; charset="UTF-8"
route-if=equal:${HTTP_X_FORWARDED_PROTO};http addheader:Content-Length: 0
route-if=equal:${HTTP_X_FORWARDED_PROTO};http redirect-permanent:https://<your_host_name_here>${REQUEST_URI}
For the ELB to recognise the 302, you need to manually add the Content-Length and Content-Type header. This was not obvious, even if you add ELB logging.
To debug you need to remember to actually send the X-Forwarded-Proto
header with curl:
curl -v -H "X-Forwarded-Proto: http" http://localhost:port
回答4:
Just another answer. Doing
[uwsgi]
<... other uwsgi configs ... >
plugins = router_redirect
route-if-not = equal:${HTTPS};on redirect-permanent:https://${HTTP_HOST}${REQUEST_URI}
will force HTTPS for the whole site.
Tested.
回答5:
Here is how you can redirect & force HTTPS directly in uWSGI, for anyone who does not want to run nginx.
[uwsgi]
master = True
enable-threads = True
thunder-lock = True
shared-socket = :443
https2 = addr==0,cert=yourdomain.crt,key=yourdomain.key,HIGH,spdy=1
http-to-https = 0.0.0.0:80
route-if-not = equal:${HTTPS};on redirect-permanent:https://${HTTP_HOST}${REQUEST_URI}
route-if = equal:${HTTPS};on addheader:Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Tested and works with docker too (python:3.6.7-alpine3.8) Also, if you will debug an HTTP request you will see the 1st response header is 301 to HTTPS.
Then if you will try again (from the same browser) you will see 307 since HSTS is enabled.
[uWSGI] getting INI configuration from uwsgi.ini
*** Starting uWSGI 2.0.17.1 (64bit) on [Fri Dec 21 20:06:47 2018] ***
compiled with version: 6.4.0 on 21 December 2018 20:05:49
os: Linux-3.10.0-514.26.2.el7.x86_64 #1 SMP Tue Jul 4 15:04:05 UTC 2017
nodename: web1
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 4
current working directory: /usr/src/app
detected binary path: /usr/local/bin/uwsgi
*** dumping internal routing table ***
[rule: 0] subject: ${HTTPS};on func: !equal action: redirect-permanent:https://${HTTP_HOST}${REQUEST_URI}
[rule: 1] subject: ${HTTPS};on func: equal action: addheader:Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
*** end of the internal routing table ***
uwsgi shared socket 0 bound to TCP address :443 fd 3
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
chdir() to /usr/src/app
your memory page size is 4096 bytes
detected max file descriptor number: 65536
lock engine: pthread robust mutexes
thunder lock: enabled
uWSGI http bound on :443 fd 3
uWSGI http bound on 0.0.0.0:80 fd 5
uwsgi socket 0 bound to TCP address 127.0.0.1:45870 (port auto-assigned) fd 4
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
Python version: 3.6.7 (default, Dec 21 2018, 03:29:53) [GCC 6.4.0]
Python main interpreter initialized at 0x7fdf16663b40
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
python threads support enabled
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 364600 bytes (356 KB) for 4 cores
*** Operational MODE: preforking ***
WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x7fdf16663b40 pid: 1 (default app)
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 1)
spawned uWSGI worker 1 (pid: 18, cores: 1)
spawned uWSGI worker 2 (pid: 19, cores: 1)
spawned uWSGI worker 3 (pid: 20, cores: 1)
spawned uWSGI worker 4 (pid: 21, cores: 1)
spawned uWSGI http 1 (pid: 22)
Note it runs as root
Hope this helps.
回答6:
For those who have tried both answers above and unfortunately failed, leave uWSGI what it is and add the Nginx CONF:
server {
listen 80;
server_name <your_domain>;
rewrite ^/(.*) https://<your_domain>/$1 permanent;
}
I feel like uWSGI is not that friendly when it comes to internal routing.
来源:https://stackoverflow.com/questions/33682770/how-can-i-redirect-http-to-https-with-uwsgi-internal-routing