Put vCenter 7.0 behind a reverse proxy
In a previous post, we were discussing about the necessary config to put a vCenter 6.X (HTML5) behind nginx reverse proxy.
As VMware updated the way the single sign-on works, thsi configuration was not valid anymore…
This gave me some headaches, but after looking at the local, the redirections and the failing URL, I had to modifiy it a little and add a line to the 6.X configuration.
Here is the working configuration:
server { listen 443 ssl http2; server_name my_internet_vcenter_fqdn; ssl_certificate /etc/letsencrypt/live/my_letsencrypt_domain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/my_letsencrypt_domain/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; location / { proxy_set_header Host "your_vCenter_fqdn"; proxy_set_header Origin "your_vCenter_fqdn"; proxy_set_header X-Real-IP $remote_addr; proxy_ssl_verify off; proxy_pass https://your_vCenter_fqdn; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_buffering off; client_max_body_size 0; proxy_read_timeout 36000s; proxy_redirect https://your_vCenter_fqdn/ https://my_internet_vcenter_fqdn/; } location /websso/SAML2 { sub_filter "your_vCenter_fqdn" "my_internet_vcenter_fqdn"; proxy_set_header Host your_vCenter_fqdn; proxy_set_header X-Real-IP $remote_addr; proxy_ssl_verify off; proxy_pass https://your_vCenter_fqdn; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_buffering off; client_max_body_size 0; proxy_read_timeout 36000s; proxy_ssl_session_reuse on; proxy_redirect https://your_vCenter_fqdn/ https://my_internet_vcenter_fqdn/; } }
Hope this will help you and of course, if you have some suggestions, be my guest!
(and no: the concept of reverse-proxiing vCenter is still not debated !!!)
Does this still work for you with latest vcenter? It almost works for me, but get 403 on websocket connection …
WebSocket connection to ‘wss://_MY_internet_vcenter_FQDN/ui/app-fabric/fabric’ failed: Error during WebSocket handshake: Unexpected response code: 403
Hi,
I just tried with very last update (build 7.0.1.00300) and it still works for mine so problem should be somewhere else.
Do you see anything in NGINX logs? Did it worked before?
PS: might be important: I run NGINX 1.18.0 (on a Fedora 33 server)
Fab thank you 🙂
Good info but I also get 403 from v-center for the webconsole. Used to work but not after upgrade to 7.0.2.00200. Not sure if it ever worked with version 7.
Nginx log:
request=”GET /ui/webconsole/authd?host=xxxxxxxx&port=902&cfgFile=%2Fvmfs%2Fvolumes%2F5dbac1a0-038ef105-3f82-f403435862b8%2Fxxxxx%2Fxxxxx.vmx&thumbprint=1C:B7:D6:D6:3B:F6:FA:2D:DD:12:FC:5F:2D:7E:B2:CE:AC:13:8A:43&ticket=52792b00-3d9f-9867-b269-cd1696a9879a&vmId=vm-25679&encoding=UTF-8 HTTP/1.1″ status=”403″
On Nginx 1.16.1 since that is what CentOS 7 comes with.
Hi Bjorn,
It did work before 7U2 but I also confirm that it is not working anymore. I didn’t notice it since I’m almost working 100% from home since COVID so I don’t use my reverse that much… Thanks for sharing.
Can you post your / location configuration, so I can test it too and update the article?
Thanks in advance! 😉
PS: I’m running now NGINX 1.21 on CentOS 8 (with plan to migrate to Alma Linux or another)
v-center logs this for the HTML5 remote console(websocket):
ui-runtime – – – Request with origin:https:// and URL: https:///ui/webconsole/authd blocked!
I needed:
proxy_set_header Origin “https://your_vCenter_fqdn”;
Under / location to get html5 web-console to work. Otherwise v-center blocks it.
Hey guys, it seems I have the same was:// 403 error issue with my nginx reverse proxy config.
How were you able to fix it? I tried adding proxy_set_header Origin “https://your_vCenter_fqdn”; in my config but still getting this 403.
Something else? Someone to post a full working config with webconsole working?
I coped your config and put in my vcenter host name and my ngnix server name and I still get this workflow
public.vcenter.com/ui -> internal.vcenter.com/websso/SAML2/…/… -> public.vcenter.com/ui/…/….
I still can not get
public.vcenter.com/ui -> public.vcenter.com/websso/SAML2/…/… -> public.vcenter.com/ui/…/….
What would cause my SSO to still load the internal.vcenter.com hostname?
Hi,
I’ve recheck the config, there was a missing “proxy_set_header Origin “your_vCenter_fqdn”;” in the first block.
The modification was mentioned by Bjorn on a previous comment but the article was not corrected.
Please try and let me know 😉
Do you know how to do the same thing in Apache2?
Unfortunately not, I never used Apache as a reverse proxy 🙂
Thanks for this! It’s a step closer in the right direction.
I got it to work in a pod based on latest nginx but still face some issues as mentioned in earlier comments.
– my vCenter redirects to ADFS and this redirects back to internal url (the internal URL is in the request URI sent to ADFS)
– websocket fails to connect for the console
– had to configure ‘listen 443 ssl’ as haproxy in ssl passthrough mode behaves really weird and mixes backends when http2 is used
I’m on latest vcenter 7.
Also, are you not concerned about exposing vCenter to the public internet?
Hi,
ADFS is probably on my wish list and you’re right, it’s probably complicated!
For now, my vCenter is not exposed to Internet since the last 2 updates as when they wanted to correct the last big issue, they also put some vulnerable libraries back… 😒
But my reverse proxy is behind a firewall with IPS and with also different IP filtering lists, so the risk, even if present, is reduced. 😊
I really need to learn NGINX the deep way!!!
Hello,
I configured my vcenter behind a nginx reverse proxy.
It works fine with Vcenter 6.X, but not for Vcenter 7X.
Did you find a solution on your side ?
Hi,
Well, not yet but I didn’t work on it. I think now I’ll will first try with vCenter 8 and figure a solution for this one! 😉
Hello,
I think I made it work using Apache instead of Nginx (not the purpose of your article but it may help future readers of your article).
Tested with Apache version 2.4.51 on Alma Linux 9 :
Listen 443
ServerName sub.domain.com
SSLEngine On
SSLCertificateFile /etc/ssl/mysitename.crt
SSLCertificateKeyFile /etc/ssl/mysitename.key
# Protocol ‘h2’ is only supported on Apache 2.4.17 or newer.
Protocols h2 http/1.1
ProxyPass / http://real_vcenter_ip/
RewriteEngine on
RewriteCond %{HTTP:Upgrade} =websocket
RewriteRule /(.*) wss://real_vcenter_ip/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket
RewriteRule /(.*) http://real_vcenter_ip/$1 [P,L]
https://gitlab.com/-/snippets/2434424
Hi,
Always good for the others! 😉
At work I might have some NGINX specialists, I have to ask them someday, there is probably a solution for it.
I can not believe NGINX is not capable to do that but it is so complex to understand every little option with interations to the others.
Hello,
I made it working on NGINX following your syntax. Thank you so much as i spent days trying to fix it. Your guide works like a charm…. Below is working config without sensitive data…anyway, vcenter is not exposed to internet but only to internal network…. I am using simple access list using apache .htpasswd where you can filter the access based on IP, otherwise it will ask for password ..sensitive data and IPs are ****** public fqdn is vsphere. and private/real fqdn is vcenter…hope it helps…
server {
server_name vsphere.*********.****;
listen 443 ssl;
server_tokens off;
include /etc/nginx/snippets/strong-ssl.conf;
error_log /var/log/nginx/vsphere.error;
access_log /var/log/nginx/vsphere.access;
satisfy any;
allow *.*.*.*/24;
allow *.*.*.*/24;
allow *.*.*.*;
deny all;
# Basic Auth to protect the site
auth_basic “Restricted”;
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_set_header Host vcenter.***.***;
proxy_set_header Origin vcenter.***.***;
proxy_set_header X-Real-IP $remote_addr;
proxy_ssl_verify off;
proxy_pass https://vcenter.***.***;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
proxy_buffering off;
client_max_body_size 0;
proxy_read_timeout 36000s;
proxy_redirect https://vcenter.***.***/ https://vsphere.***.***/;
}
location /websso/SAML2 {
sub_filter vcenter.***.** vsphere.***.**;
proxy_set_header Host vcenter.***.**;
proxy_set_header X-Real-IP $remote_addr;
proxy_ssl_verify off;
proxy_pass https://vcenter.***.**;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
proxy_buffering off;
client_max_body_size 0;
proxy_read_timeout 36000s;
proxy_ssl_session_reuse on;
proxy_redirect https://vcenter.***.**/ https://vsphere.***.**/;
}
ssl_certificate /etc/nginx/*_dd/*_bund.crt;
ssl_certificate_key /etc/nginx/*_dd/*_dd.key;
}
server {
if ($host = vsphere.***.**) {
return 301 https://$host$request_uri;
}
listen 80;
server_name vsphere.***.**;
return 404;
}
i got same err too when i open web console 403 with nginx.conf as menthioned ,
i fix this issue with set proxy_buffering on; then i can use web console to operate ,thanks a lot
my vcenter version is 7.0u2
i got the same err too when i opened the web console it return 403 immediately with nginx.conf as menthioned
i fix this issue with set proxy_buffering on;
thank you guys for your support
my vcenter version is 7.0.3;
I must have read this guide a thousand times over the weekend…..i cannot get this working with vCentre 7.0.3
My issue is that when accessing EXTERNAL.vcentre and clicking on login, I get redirected to INTERNAL.vcentre/websso/SAML2/SSO/etc
Has any bright spark managed to get a solution?
Same my issues
i fix this issue with set :
proxy_set_header Origin “https://yourvcenter.*.*.*”;
It is my config
server {
listen 0.0.0.0:443 ssl;
server_name vcenter.xxx.xxx;
ssl_certificate server.crt;
ssl_certificate_key server.key;
ssl_session_timeout 5m;
ssl_prefer_server_ciphers on;
ssl_ciphers HIGH:!aNULL:!MD5:!DES:!3DES;
client_max_body_size 10240m;
location / {
add_header ‘Access-Control-Allow-Origin’ ‘*’;
add_header ‘Access-Control-Allow-Methods’ ‘GET, POST, OPTIONS’;
add_header ‘Access-Control-Allow-Headers’ ‘DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization’;
add_header ‘Access-Control-Allow-Credentials’ ‘true’;
# 当处理预检请求时,确保响应正确
if ($request_method = ‘OPTIONS’) {
add_header ‘Access-Control-Allow-Origin’ ‘*’;
add_header ‘Access-Control-Allow-Methods’ ‘GET, POST, OPTIONS’;
add_header ‘Access-Control-Allow-Headers’ ‘DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization’;
add_header ‘Access-Control-Allow-Credentials’ ‘true’;
add_header ‘Access-Control-Max-Age’ 1728000;
add_header ‘Content-Type’ ‘text/plain charset=UTF-8’;
add_header ‘Content-Length’ 0;
return 204;
}
sub_filter “vcenterlocal.xx.xx.xx” “vcenter.xxx.xxx”;
proxy_set_header Host “vcenterlocal.xx.xx.xx”;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Origin “https://vcenterlocal.xx.xx.xx”;
proxy_buffering off;
proxy_ssl_verify off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
proxy_pass https://vcenterlocal.xx.xx.xx;
}
location /ui/app-fabric/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_buffering on;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
proxy_pass https://vcenterlocal.xx.xx.xx;
}
location /websso/SAML2 {
sub_filter “vcenterlocal.xx.xx.xx” “vcenter.xxx.xxx”;
proxy_set_header Host “vcenterlocal.xx.xx.xx”;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_buffering on;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
proxy_ssl_session_reuse on;
proxy_pass https://vcenterlocal.xx.xx.xx;
}
}