ws protocol and apache mod_proxy_wstunnel configuration: error 500 - apache

I got an error 500 when trying to access to ws://localhost:8080/ via my Apache2 server. This server runs OpenSuse Leap 42.1 and Apache 2.4.16.
These Apache2 modules are enabled: mod_proxy, mod_proxy_http, mod_proxy_wstunnel.
When the request is called from the local network, everything works fine. URL example: http://<myhost-ip-address>/api/ws/<some-url>. It returns status 101 and the response: Upgrade: websocket. It's OK.
The same kind of request from external network fails. URL example: ws://www.mysite.com/api/ws/<some-url>. It returns error 500.
The Apache access log contains: GET /api/ws/<some-url> HTTP/1.1" 500 ...
The Apache error log contains: [proxy:warn] AH01144: No protocol handler was valid for the URL /api/ws/<some-url>. If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule.
My httpd.conf:
<VirtualHost *:80>
ServerName mysite.com
ServerAlias mysite.com
# Redirection for ws protocol
ProxyPreserveHost On
ProxyVia full
ProxyRequests OffHere
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/api/ws/(.*) [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule /(.*) ws://localhost:8080/$1 [P,L]
# Proxy pass
ProxyPass /api/ws/ ws://localhost:8080/api/ws/
ProxyPassReverse /api/ws/ ws://localhost:8080/api/ws/
# DocumentRoot
DocumentRoot /srv/www/vhosts/mysite.com
<Directory "/srv/www/vhosts/mysite.com">
Options Indexes SymLinksIfOwnerMatch
AllowOverride None
...
</Directory>
# URL as parameter
AllowEncodedSlashes NoDecode
I followed these previous StackOverflow answers (thank to that) :
websockets , node.js , socket-io , but with no luck.
Something must be wrong in my configuration. Any ideas ?
EDIT
As suggested by adona9, here are debug logs:
proxy_util.c(1784): AH00925: initializing worker ws://localhost:8080/api/ws/ shared
proxy_util.c(1826): AH00927: initializing worker ws://localhost:8080/api/ws/ local
...
mod_authz_core.c(809): AH01626: authorization result of Require user <user>: granted
mod_authz_core.c(809): AH01626: authorization result of <RequireAny>: granted
mod_charset_lite.c(219): AH01448: incomplete configuration: src unspecified, dst unspecified
mod_proxy.c(1159): AH01143: Running scheme ws handler (attempt 0)
mod_proxy_http.c(1944): AH01113: HTTP: declining URL ws://localhost:8080/api/ws/<some-url>
mod_proxy_wstunnel.c(341): AH02900: declining URL ws://localhost:8080/api/ws/<some-url> (not WebSocket)
[proxy:warn] H01144: No protocol handler was valid for the URL /api/ws/<some-url>. If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule.
Any ideas ?

So I ended up spending a day and a half researching and reading up on deep apache2 configuration. This is how I was able to solve this problem:
Using both forensic_logs and DumpIO to find out my initial request headers on the apache2 end.
Log the request headers coming from websocket client.
VERIFY that both contain the upgrade header and connection type websocket in the request header. More than likely, these problems are a result of network filtering or removing of specific header files.
My problem was that I was using an AWS classic load balancer which DOES NOT support websocket connections.
While reading other forums, some companies' firewalls also remove specific header files from their connections, so it could also be that.
So more than likely if you've triple-checked to make sure you have the right modules installed, the more than likely error is network related.
If you have a network diagram, check each specific node and gateway and verify that the in and out request headers are the same.

Related

Apache Can't get Virtual host apache to forward to another host on same machine. Almost there

Hello and thank you for reading.
I have a windows 2016 server running apache.
I am attempting to have a virtual host set up on one port (8080) and
have it automatically forward any and everything it sees to the main Apache host
(The not virtual instance? I'm unclear of the correct term to call it)
which lives on port 80
My configuration is below.
I show that the server is listening on both port 80 and 8080.
When I go to port 80. I get the default "It works" page
When I go to port 8080
I get the following error:
Internal Server Error
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator at admin#example.com to inform them of the time this error occurred, and the actions you performed just before this error.
More information about this error may be available in the server error log.
I consult the log and I see the following message
[Thu Sep 24 07:29:16.128967 2020] [proxy:warn] [pid 4860:tid 1076] [client 192.168.50.160:64768] AH01144: No protocol handler was valid for the URL / (scheme 'https'). If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule.
I am attempting to do this without any ssl/or encrypption
A copy of my configuration and loaded modules is listed below.
I have included only the parts of the base conf file that have been modified
What am I missing, or what should i try next to fix?
Thank you community.
You're encountering an issue as your SSL is not configured, and you're trying to go through HTTPS, as Eliezer stated you need to create your key, to do so I use LetsEncrypt (certbot) but the choice is up to you, (and I'm on Ubuntu)
Your ports.conf file should have some lines that look like this like this:
Listen 8080
IfModule ssl_module //add the missing < > around the IfModule
Listen 443
IfModule
You also need to add <VirtualHost *:443> Your configuration inside the tags</VirtualHost> tag in your conf after adding it to the listened port
And then your conf file, you need to enable SSL :
ServerName domain.com
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/domain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/domain.com/privkey.pem
I would also advise to force redirection on https, once your SSL is configured with a rewrite rule:
RewriteEngine on
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [L,QSA,R=permanent]
This answer is base for an Apache Ubuntu config, but I think can you work from it to your Windows Server Apache config
It sounds like you're connecting to 192.168.50.160:8080 using https, not http. If you want to use HTTPS, you'll need to set up your :8080 VirtualHost to support it properly.
https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-in-ubuntu-16-04

Apache reverse proxy help needed

I've got a somewhat unique (maybe not, but unique to me) architecture here for some home apps that variously require PHP 5.6 and PHP 7.1. This is the architecture recommended to me by /r/docker:
One container acting as Apache Reverse Proxy that will ingest a DNS request on port 80 and then pass it to one of the below containers' ports.
One container running Apache with PHP 5.6, listening on port 8081.
One container running Apache with PHP 7.1, listening on port 8080.
I've been able to get domainname.com to work this way, by setting up the following domainname.com.conf in /etc/apache2/sites-available:
<VirtualHost *:80>
ServerName domainname.com
<Proxy *>
Allow from localhost
</Proxy>
ProxyPass "/" "http://public.ip.address:8080/" retry=0
ProxyPreserveHost On
</VirtualHost>
However, one of my subdomains needs to push to an application on the PHP 5.6 side. So I've set up this subdomain.domainname.com.conf:
<VirtualHost *:80>
ServerName subdomain.domainname.com
<Proxy *>
Allow from localhost
</Proxy>
ProxyPass "/" "http://public.ip.address:8081/subdomain/" retry=0
ProxyPreserveHost On
</VirtualHost>
Indeed, going directly to http://public.ip.address:8081/subdomain/ loads the application just fine, but for whatever reason, going to http://subdomain.domain.com gives a 503. Originally it was just showing the Apache on Ubuntu page, which is when I realized I needed to a2ensite and reload Apache, which has since been done.
The logs show this:
[Wed Jul 10 21:36:59.049131 2019] [proxy:error] [pid 2298:tid 139882856969984] (113)No route to host: AH00957: HTTP: attempt to connect to public.ip.address:8081 (3.220.176.240) failed
[Wed Jul 10 21:36:59.049182 2019] [proxy_http:error] [pid 2298:tid 139882856969984] [client 128.229.4.2:58611] AH01114: HTTP: failed to make connection to backend: public.ip.address
We know that the system can access 8080 just fine, so I'm not sure why it's struggling with this traffic. As mentioned above, hitting the ProxyPass URL directly from the outside loads the page fine, so traffic inbound to that container is fine. SELinux is disabled. This is in AWS and Security Groups are configured properly as far as I can tell (see: traffic works from outside).
Using the public IP address is the only way I've been able to get inter-container traffic to work, because using Docker's bridge IPs didn't work previously.
On the old system, when all my apps were just PHP 5.6, I had a standard VirtualHost statement that just took in the subdomain.domain.com and pointed it to a specific DocumentRoot. I can't do that here since the reverse proxy container needs to hand off the traffic to the container with the right PHP version.
Many thanks for any tips or tricks here.

Reverse proxy for external URL - Apache

I configured my apache so that it can forward my requests to external URL like google.com, but the reverse proxy doesn't work.
<VirtualHost *:443>
ServerName authtest.com
ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
Order allow,deny
Allow from All
</Proxy>
<LocationMatch "/google">
ProxyPass https://www.google.com/
ProxyPassReverse https://www.google.com/
</LocationMatch>
</VirtualHost>
Is it possible for me to reverse proxy external websites?
Is it possible for me to reverse proxy external websites?
Yes but with significant downsides.
Note: when I tried your configuration, I got SSL Proxy requested for [...] but not enabled [Hint: SSLProxyEngine] in the logs so I added SSLProxyEngine on.
Host issue
When you make a HTTP/1.1 request to a server, you automatically add the hostname in the request. When you proxy them, you have two possibilites:
[browser] --(Host: authtest.com)--> [apache proxy] --(Host: authtest.com)--> Google
or
[browser] --(Host: authtest.com)--> [apache proxy] --(Host: google.com)--> Google
The first one is what you get with ProxyPreserveHost On. Google servers won't handle requests for authtest.com, you should remove this line.
Even in the second case, you can have issues. ProxyPassReverse will handle redirects but only for the given domain: I'm in France, google.com redirects me to google.fr (a different domain) and the reverse proxy doesn't rewrite the redirect.
An other issue is the referer: if a service sees requests for images/css/js coming from a different web site it may consider it as bandwidth leeching and block them. Now, you need to rewrite the html of the response too (mod_proxy_html will help but it's not a silver bullet).
Path issue
In your example, you proxy <authtest>/google to <google>/. Like above, you need to rewrite the html: absolute links/resources won't work unless your server adds /google everywhere. Same for relative links/resources (but with more edge cases). If you owned the backend server, you could have checked urls in html/css/js files. Here, if the url is built dynamically in the browser using js you can't do anything.
If you can proxy / to / (or /whatever to /whatever) you will avoid a lot of issues here.
Chech this GIT Repo
I forked a GIT Repo and customized it to work with scenario:
[browser] --(Host: google.local)--> [apache proxy] --(Host: google.nl)--> Google
The Apache config as follows:
<VirtualHost *:80>
ServerName google.local
SSLProxyEngine on
ProxyRequests Off
<Proxy *>
Order allow,deny
Allow from All
</Proxy>
ProxyPass / https://www.google.nl/
ProxyPassReverse / https://www.google.nl/
ErrorLog /var/log/apache2/google.local-error.log
CustomLog /var/log/apache2/google.local-access.log combined
</VirtualHost>

Proxy websocket wss:// to ws:// apache

i searched alot but i couldnt connect my websocket to wss:// ,
i found that there is a way to proxy wss://domain.com:9090 and apache apply the proxy on it and redirect request to where the normal ws://domain.com:9090 server is running
ProxyPass /websocket ws://domain.com:9090
ProxyPassReverse /websocket ws://domain.com:9090
this code in apache config will send request from any address ended with /websocket to ws://domain.com:9090
ex : ws://websocket will be ws://domain.com:9090
i want to do it for wss:// also
ex wss://websocket must point to ws://domain.com:9090
it dosnt work and i get this error in browser console :
failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
is there any mistake here ?
thanks you .
i worked 24 hours for find this and searched a lot of forum but no one write about success.
here is my server configuration :
CentOS release 6.7 , Apache 4.2.18
here is what i did finally :
first i found that modules/mod_proxy_wstunnel.so must be enable in apache config file , but my apache didn't have that module and after a lot of search i found that module is Available in apache 2.4.5 and later.
https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html
i downloaded https://archive.apache.org/dist/httpd/httpd-2.4.18.tar.gz
extracted httpd-2.4.18\modules\proxy\mod_proxy_wstunnel.c and uploaded to my server root
then from terminal could compile it again with these commonds :
chmod 755 mod_proxy_wstunnel.c #set permission
pxs -i -a -c mod_proxy_tunnel.c #compile module
pxs command did compile the module and wrote in apache config file to load it
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
after that i added these lines to end of apache config file :
RewriteEngine on
ProxyRequests Off
ProxyPreserveHost on
ProxyPass /myws ws://mysite.com:8091
ProxyPassReverse /myws ws://mysite.com:8091
AND NOW : it works !
in client side js you can set ws url like this :
var protocol = 'ws://';
if (window.location.protocol === 'https:') {
protocol = 'wss://';
}
var wsUri =protocol+ "mysite.com/myws";
var ws = new WebSocket(wsUri);
and it will forward request to ws://mysite.com:8091
doesnt matter the page loaded with https or http , it will direct all request ended with /myws to ws://mysite.com:8091
You need to enable some Apache2 modules:
$ a2enmod proxy proxy_wstunnel proxy_http rewrite
Then you can use this configuration to solve your problem.
ProxyRequests off
ProxyVia on
RewriteEngine On
RewriteEngine On
RewriteCond %{HTTP:Connection} Upgrade [NC]
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteRule /(.*) ws://example.com:9090/$1 [P,L]
ProxyPass /websocket http://example.com:9090/websocket
ProxyPassReverse /websocket http://example.com:9090/websocket
Apache2 automatically upgrades the connection to websocket with ws://, you don't need to set the ws:// manually. I tried dozens of configurations and this is the only one that worked for me.
the problem I was trying to solve was similar to this one. I have a reverse proxy running under Apache 2.4 on CentOs 7 which has to work with both https and wss requests.
Behind the reverse proxy I have my app server running on an internal network. the virtual host configuration in the /etc/httpd/httpd.conf config file is as follows:
<VirtualHost *:443>
ServerName example.com
RewriteCond %(HTTP:Upgrade) websocket [NC] # Required to handle the websocket connection
RewriteCond %(HTTP:Connection) upgrade [NC]
RewriteRule /(.*) ws://192.160.0.1/$1 [P,L]
SSLEngine on # SSL Certificates handling
SSLCertificateFile ssl/cert.pem # Public Certificate
SSLCertificateKeyFile ssl/key.pem # Private certificate
SSLCertificateChainFile ssl/ca.pem # CA or chain certificate
ProxyPreserveHost On
ProxyPass /websocket ws://192.168.0.1 # First you need to write the specific rules
ProxyPassReverse /websocket ws://102.168.0.1
ProxyPass / http://192.168.0.1 # Then the generic rules for the proxy.
ProxyPassReverse / http://192.168.0.1
</VirtualHost>
In your case, you will have to replace the ServerName, the SSL certificates location, and the destination of the proxy.
wss needs following module
Uncomment line at the httpd.conf of apache conf
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
The /websocket path is missing in your ProxyPass configuration path.
Use:
ProxyPass /websocket ws://example.com:9090/websocket
ProxyPassReverse /websocket ws://example.com:9090/websocket
Additional information:
Like others mentioned, you have to uncomment the line:
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
If you are also using a http ProxyPass thats relative path is "/" (forwarding everything directly), the specific "/websocket" path configuration must be configured first, otherwise "/" grabs first.
ProxyPass /websocket ws://example.com:9090/websocket
ProxyPassReverse /websocket ws://example.com:9090/websocket
ProxyPass balancer://ac-cluster/
ProxyPassReverse / http://example.com:9090
I did it for aria 2. I just enabled some modules and added a single line to config. (env: debian buster/apache 2.4).
enabling modes:
sudo a2enmod proxy proxy_balancer proxy_wstunnel proxy_http
and add this line to ssl site config file inside the virtual host directive :
ProxyPass /jsonrpc ws://127.0.0.1:6888/jsonrpc
I want to share this in case it helps somebody else avoid days of wasted time and effort.
I was giving up after researching everything. I was ready to start following the code of the different proxy modules, yes I know, a spiderweb..., but I was desperate. As a last resource I installed wireshark to follow exactly what was going on in my network. After installing wireshark, the instructions asked me to restart my server through a power off/on cycle. So, I did. When I started tracing it, to my complete surprise, the server was proxying perfectly the wss requests to ws, no problems! So I had the correct setup to start with but something got messed up in Ubuntu 20.4 / Apache 2.4.41 / node 14.17.2 that required a complete restart of the machine where the server operates. Crazy! But that was it...

Apache 2.4.16 proxy no longer working

I have been using Gateone behind an Apache proxy for a long time. All of a sudden, probably after the last apt-get update/upgrade of my Debian Jessie install, this no longer works.
The error I get in the error.log is this :
[Sat Sep 12 16:20:47.992400 2015] [proxy:warn] [pid 1870] [client 192.168.0.2:5022] AH01144: No protocol handler was valid for the URL /gateone/. If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule.
All answers I could find were pointing to a missing proxy (sub)module that needed to be loaded. This is the list of proxy modules I have loaded :
proxy.conf proxy_connect.load proxy_html.conf proxy_http.load
proxy.load proxy_html.load proxy_wstunnel.load
And the (unchanged) section in my http conf file looks like this :
ProxyPass /gateone/ ws://localhost:8888/gateone/
ProxyPassReverse /gateone/ ws://localhost:8888/gateone/
ProxyPass /gateone/ wss://localhost:8888/gateone/
ProxyPassReverse /gateone/ wss://localhost:8888/gateone/
ProxyPass /gateone/ http://localhost:8888/gateone/
ProxyPassReverse /gateone/ http://localhost:8888/gateone/
This configuration used to work. Can anyone please tell me if something has changed lately in Debian Jessie, especially regarding proxying (websockets proxying) ?
Thanks,
Hans
2.4.17 has this exact same problem but 2.4.12 was fine.
Interestingly this ALSO occurs on the 2.4.16 and 2.4.17 Windows x64 release using VC14 or VC11 so this is entirely something internal to the proxy modules.
The only resolution appears to be downgrading to 2.4.12 because there exists no combination of proxy modules to make it work and you can use your config in 2.4.12 without issue. Definite websocket proxy break 2.4.16+
*Update: Workaround allows http: fallback from ws: when you use ProxyPass with a very specific URL.
Eg.
#Works 2.4.12 but fails 2.4.16+
ProxyPass /ws/ ws://localhost:8080/ws/
#2.4.16+ seems to want full and exact path and ws: fails but http: failover works
ProxyPass /ws/stomp/ http://localhost:8080/ws/stomp/