Skip to Content
Menu
This question has been flagged
2 Replies
3066 Views

Does anyone know how to have nginx reverse proxy communicate to Odoo so it uses https for stripe webhooks instead of http?


I have a Odoo docker container running over https with an nginx container as a reverse proxy. Everything works for the most part except when I try to generate or use the Stripe payment webhook Odoo is creating it with http instead of https protocol. While this technically is working, it should be secured. 


It seems Odoo is getting the http protocol from the proxy_pass line in the nginx configuration, where I'm using http to pass traffic to the Odoo container. 


I'm not a python developer, but I think it is related to this chunk of code in payment_provider code on GitHub.  I wasn't able to figure out why it wasn't working based on that though.


My nginx configuration file is below to show what I have currently after swapping out the hostname with comments in areas where I was trying to pass https protocol, but failed. Appreciate any help, hints or feedback.


## Set appropriate X-Forwarded-Ssl header
map $scheme $proxy_x_forwarded_ssl {
  default off;
  https on;
}

upstream test-stream {
   server odoo:8069;
}

server {
    listen      80;
    listen [::]:80;
    server_name example.com www.example.com;

    # ACME-challenge used by Certbot for Let's Encrypt
    location ^~ /.well-known/acme-challenge/ {
      root /var/www/certbot;
    }

    location / {
        rewrite ^ https://$host$request_uri? permanent;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;

    # removed cert, logs, and etc. related lines for brevity

    # Tried this line before the location block to pass https, not working
    proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;

    location / {
          proxy_pass http://test-stream;
          proxy_set_header Host $host;
 
   #####################
    # Tried the following lines to pass https, but none worked
    ####################      
          proxy_set_header Scheme https;
          proxy_set_header X-Forwarded-Scheme https;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header X-Forwarded-Proto https;

   }

}
Avatar
Discard
Best Answer

Hi Liu!

Is your webhook addres correct? When I was testing webhook it was saying, that there is an error because URL is not publicly visible. I had the following error in odoo logs:

ERROR  odoo.addons.payment_stripe.models.payment_provider: invalid API request at https://api.stripe.com/v1/webhook_endpoints with data 
{'url': 'http://localhost:8079/payment/stripe/webhook', 
'enabled_events[]': ['payment_intent.amount_capturable_updated', 
'payment_intent.succeeded', 'payment_intent.payment_failed', 
'setup_intent.succeeded', 'charge.refunded', 'charge.refund.updated'], 
'api_version': '2019-05-16'} 

Also, cancel_url and success_url in the stripe request had localhost as a domain.

What worked for me:

1. Add the following flag in the odoo config file:

[options]
proxy_mode = True

2. Add this header in the nginx config (I added it in the 'location' block):

proxy_set_header X-Forwarded-Host $host;


Explanation: 

When you dig further into payment_provider method (I guess this is the one that you provided in the link, but it does not work for me), you will see that it takes url from url_root method in the Werkzeug's BaseRequest class:


@cached_property
def url_root(self):
"""The full URL root (with hostname), this is the application
root as IRI.
See also: :attr:`trusted_hosts`.
"""
return get_current_url(self.environ, True, trusted_hosts=self.trusted_hosts)


Jumping next, werkzeug will take this url from "HTTP_HOST" key in the ENVIRON dictionary, the WSGI environment configuration. 

def get_host(environ, trusted_hosts=None):
""":param environ: The WSGI environment to get the host from."""
if "HTTP_HOST" in environ:
rv = environ["HTTP_HOST"]
if environ["wsgi.url_scheme"] == "http" and rv.endswith(":80"):
rv = rv[:-3]
elif environ["wsgi.url_scheme"] == "https" and rv.endswith(":443"):
rv = rv[:-4]
else:
rv = environ["SERVER_NAME"]
if (environ["wsgi.url_scheme"], environ["SERVER_PORT"]) not in (
("https", "443"),
("http", "80"),
):
rv += ":" + environ["SERVER_PORT"]
return rv

(irrelevant code omited)

Now we are getting to somewhere. As Werkzeug team says:

When an application is running behind a proxy server, WSGI may see the request as coming from that server rather than the real client. Proxies set various headers to track where the request actually came from.

They also provide a fix for it:
https://werkzeug.palletsprojects.com/en/2.3.x/middleware/proxy_fix/

But what can we do with this? Let's search the odoo code. Then we will find this:

if odoo.tools.config['proxy_mode'] and environ.get("HTTP_X_FORWARDED_HOST"):
# The ProxyFix middleware has a side effect of updating the
# environ, see https://github.com/pallets/werkzeug/pull/2184
def fake_app(environ, start_response):
return []
def fake_start_response(status, headers):
return
ProxyFix(fake_app)(environ, fake_start_response)

Bingo! 

I hope this will help, if not you then somebody in the future ;)

BR, Kajetan Dowda-Tchórzewski.

Avatar
Discard
Author

Thank you for taking the time to not only give the solution (the 2 steps that worked for you did for me as well), but explain what the code.

Thanks Liu, no problemo :) I am glad it works in your case too.
I hope this will be a good base of knowledge and save some struggle for others. I was looking for the answer quite a lot :P

Best Answer

While I have already had the correct parameters in the configuration file.

1. Add the following flag in the odoo config file:

[options]
proxy_mode = True

2. Add this header in the nginx config (I added it in the 'location' block):

proxy_set_header X-Forwarded-Host $host;


my stripe logs and odoo logs return a 200 ok message.
it is only for the following two events webhooks that fail.
payment_intent.succeeded

payment_intent.amount_capturable_updated


The transaction does process well but for some reason the webhook keeps trying to resend it to odoo and i keep getting a 404 error again only for those two methods. After a week there are approx 1400 retries a day and it slows down the server considerably.


Avatar
Discard
Related Posts Replies Views Activity
2
Jul 24
1789
1
Dec 22
2632
1
Oct 24
1489
2
Aug 24
857
1
Mar 24
1808