SSL certificate for NGINX reverse proxy website?

Hi
I have a problem to install and maintain a working SSL certificate for a virtual website that is only a proxy reverse. As it has none root directory setup (not needed for proxy reverse configuration), Let’s Encrypt doesn’t work. Is there a workaround for that ? I’m with Virtualmin GPL.
Here is my NGinx configuration for that virtual server:

upstream odoo {
     server 127.0.0.1:8069;
}
upstream odoochat {
	server 127.0.0.1:8072;
}
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

server {
  listen 80;
  server_name mywebsiteurl;
  rewrite ^(.*) https://$host$1 permanent;
}

server {
  listen 443 ssl;
  server_name mywebsiteurl;
  proxy_read_timeout 720s;
  proxy_connect_timeout 720s;
  proxy_send_timeout 720s;

  # SSL parameters
  ssl_certificate /etc/ssl/virtualmin/1767625228267252/ssl.cert;
  ssl_certificate_key /etc/ssl/virtualmin/1767625228267252/ssl.key;
  ssl_session_timeout 30m;
  ssl_protocols TLSv1.2;
  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
  ssl_prefer_server_ciphers off;

  # Redirect websocket requests to odoo gevent port
  location /websocket {
    proxy_pass http://odoochat;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    proxy_cookie_flags session_id samesite=lax secure;  # requires nginx 1.19.8
  }

  # Redirect requests to odoo backend server
  location / {
    # Add Headers for odoo proxy mode
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_redirect off;
    proxy_pass http://odoo;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    proxy_cookie_flags session_id samesite=lax secure;  # requires nginx 1.19.8
  }

  location /web/database/ {
    # Add Headers for odoo proxy mode
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_redirect off;
    proxy_pass http://odoo;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    proxy_cookie_flags session_id samesite=lax secure;  # requires nginx 1.19.8
	allow 192.168.1.0/24;
	deny all;
  }

  # common gzip
  gzip_types text/css text/scss text/plain text/xml application/xml application/json application/javascript;
  gzip on;
}

Thanks for your help

Vincèn

Maybe look at DNS request, but with Virtualmin you need it to handle the DNS.
Apart from that I have no clue about reverse proxy.

hum it’s unrelated with DNS :wink:

why not allow normal root directory public_htm that will allow normal LE to grant a cert then block/configure in the site’s .conf this has worked for my NodeJS reverse proxies.

there may be other ways, though I have not tried them

Unhappy it doesn’t work :frowning: I added that in both http and https section of NGinx but LE still fails :frowning:

server {
	listen 0.0.0.0:80 default_server;
	listen [::]:80 ipv6only=on default_server;
	server_name xxxxxxxxxxxx;
  rewrite ^(.*) https://$host$1 permanent;
	location /.well-known/ {
	root /var/www/html;
	allow all;
	}
	if ($scheme = http) {
		rewrite "^/(?!.well-known)(.*)$" "https://$host/$1" redirect;
	}
	location / {
	root /var/www/html;
	}
}

server {
	listen 0.0.0.0:443 ssl;
	listen [::]:443 ipv6only=on;
	server_name xxxxxxxxxxxx;
  proxy_read_timeout 720s;
  proxy_connect_timeout 720s;
  proxy_send_timeout 720s;

  # SSL parameters
  ssl_certificate /etc/ssl/virtualmin/1767625228267252/ssl.cert;
  ssl_certificate_key /etc/ssl/virtualmin/1767625228267252/ssl.key;
  ssl_session_timeout 30m;
  ssl_protocols TLSv1.2;
  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
  ssl_prefer_server_ciphers off;

  location /.well-known/ {
	root /var/www/html;
	allow all;
	}

Running out of ideas here :frowning: Any suggestions ?
Thanks

For LE, either web validation or DNS validation is required to verify domain ownership:

  • HTTP/web validation: the domain must resolve and serve the challenge file over the web (i.e., using the public_html directory).
  • DNS validation: a specific TXT record must be created and publicly visible (this can work if Virtualmin manages your DNS).

There’s no other way to handle it.

Unhappy the DNS validation is impossible as DNS is not managed on the Virtualmin/webmin host.
For http/web validation, it looks like it’s impossible with a NGInx web server configured in reverse proxy even with extra options I added to pass-through LE :frowning:

Have you tried using certbot? Use the temporary web server option to obtain the certificate, to do this you must stop nginx for this to work, then restart nginx after you have added the newly obtained certificate to your nginx configuration restart nginx

no not impossible, have a closer look at those “extra” options, they just look wrong. /var/www/html means nothing.:man_shrugging:

Did you use Virtualmin to configure this proxy path, or did you set it up manually?

From your configuration, it looks like everything on port 80 is being redirected to port 443. That won’t work correctly for LE validation process. You need to exclude the .well-known directory from the redirect, e.g.:

server {
    listen 80;
    server_name mywebsiteurl;

    location ^~ /.well-known/ {
        root /var/www/html;
        allow all;
        try_files $uri =404;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}
1 Like

yep tried already but same result :frowning:

manually as I could not find a way to do it through GUI. I have setup an account in Virtualmin for the fqdn so it made the basic nginx config that I edited manually to transform it in a reverse proxy configuration.

Thanks a lot for that,I thought LE just needed to check fqdn points at a website that requests the certificate whatever 80 or 443 :pleading_face:
So now it looks to work better but I’m facing a new error that looks to be a bug in the certbot version of Debian 12 (although it’s strange as I have other servers in Debian 12 that never got that issue).

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Renewing an existing certificate for mywebsite
An unexpected error occurred:
AttributeError: can't set attribute
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.

in logs file it list among first errors fact that I hitted the rate limit due to all failures. So I have deactivated automatic renewal in Virtualmin and will try again in few hours to see how it goes.

@Ilia All good now, LE succeeded to renew the certificate without problems :wink: Thanks again for your very valuable help :+1:

1 Like

This topic was automatically closed 8 days after the last reply. New replies are no longer allowed.