Setting up vCenter behind an nginx reverse proxy is simple and easy with these steps.

I found a very helpful post on the VMware forums with a good base configuration - it was able to properly proxy the websockets and remote console, but there was just one problem: it didn't proxy the login page. At the time, I thought this was just something I would have to deal with, since it directly redirected to the vcenter's FQDN.

I soon realized that you can rewrite these 302 redirections using nginx's proxy_redirect. This enabled me to be able to rewrite the "Location" header sent while logging into vCenter, meaning I was able to get it to log in through the nginx proxy rather than directly through the vCenter.

Why would I want to do this?

If you've used vCenter, you might notice that unless you trust the vCenter CA, you'll get a warning every time you go to vCenter how it's "not secure". You could install a Let's Encrypt certificate to the vCenter, but that requires a lot more hassle than simply proxying it through nginx.

That's cool and all, but how do I install it?

This post is assuming you already know how to use nginx and acme.sh, and how to add another nginx configuration file to sites-available and symlink it to sites-enabled.

Getting this configuration to work is simple: Set up acme.sh, install the certificate somewhere, download the vCenter and ssl-params configurations, change the vCenter confirmation to the correct server_name, edit the vcenter-hostname, and modify the ssl-params with the IP of your dns resolver.

Here's the vCenter configuration file:

server {
	listen 80;
	server_name esxi.yourdomain.com;
	return 301 https://$server_name$request_uri;
	}

server {
	listen 443 ssl http2;
	ssl_certificate /etc/nginx/ssl/yourdomain.com/fullchain.pem;
	ssl_certificate_key /etc/nginx/ssl/yourdomain.com/key.pem;
	include /etc/nginx/snippets/ssl-params.conf;
	set $vcenter https://vcenter-hostname.yourdomain.com;
	# Change vcenter-hostname to your actual vcenter hostname.

	server_name esxi.yourdomain.com;
	location / {
		proxy_set_header Host $http_host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_pass https://10.0.0.10; # VCSA IP Address
		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 $vcenter/ https://$server_name/;
		}
		
		location /websso/SAML2 {
		proxy_set_header Host vcenter-hostname.yourdomain.com; # your actual vcenter's hostname
		proxy_set_header X-Real-IP $remote_addr;
		proxy_pass https://10.0.0.10; # VCSA IP Address
		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 $vcenter/ https://$server_name/;
	}
}

server {
	# This is for the flash client's remote console
	listen 9443 ssl http2;
	server_name esxi.yourdomain.com;
	# ssl_certificate and ssl_certificate_key are required
	ssl_certificate /etc/nginx/ssl/yourdomain.com/fullchain.pem;
	ssl_certificate_key /etc/nginx/ssl/yourdomain.com/key.pem;
	include /etc/nginx/snippets/ssl-params.conf;
	set $vcenter https://vcenter-hostname.yourdomain.com;

	location / {
		proxy_set_header Host $http_host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_ssl_verify off;
		proxy_pass https://10.0.0.0:9443; # VCSA IP Address
		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 $vcenter/ https://$server_name/;
		}
	}

And here's the ssl-params.conf (make sure you've changed the resolver to something that can resolve your vcenter's FQDN.

# SSL ciphers from https://mozilla.github.io/server-side-tls/ssl-config-generator/
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers   on;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
resolver 1.1.1.1 1.0.0.1; # change this to your dns resolver's IP if necessary
ssl_stapling on;
ssl_stapling_verify on;

# uncomment this for HSTS
#add_header Strict-Transport-Security 'max-age=63072000';

add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;

Once you do this and reload your configuration, you should be able to properly log in to your vCenter by going to the domain name in your server_name. As long as you already have a proper Let's Encrypt certificate, it should now say "Secure", or just a padlock if you're running newer versions of Chrome.

This site does not have a comment system, however if you need help you can contact me on twitter @en0_org.

Credit: I found the base nginx reverse proxy for vCenter here and how to override the 302 redirection here.