We have a java web server which is able to serve content over h2c (HTTP/2 clear text)
We would like to reverse proxy connections established using h2 (i.e. standard HTTP/2 over SSL) to the java server in h2c.
Enabling HTTP/2 on nginx is simple enough and handling incoming h2 connections works fine.
How do we tell nginx to proxy the connection using h2c rather than http/1.1 ?
Note: a non-nginx solution may be acceptable
server {
listen 443 ssl http2 default_server;
server_name localhost;
ssl_certificate /opt/nginx/certificates/???.pem;
ssl_certificate_key /opt/nginx/certificates/???.pk8.key.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:8080/; ## <---- h2c here rather than http/1.1
}
}
CONCLUSION (June 2016)
This can be done with haproxy using a configuration file as simple as the one below.
Querying (HttpServletRequest) req.getProtocol() clearly returns HTTP/2.0
global
tune.ssl.default-dh-param 1024
defaults
timeout connect 10000ms
timeout client 60000ms
timeout server 60000ms
frontend fe_http
mode http
bind *:80
# Redirect to https
redirect scheme https code 301
frontend fe_https
mode tcp
bind *:443 ssl no-sslv3 crt mydomain.pem ciphers TLSv1.2 alpn h2,http/1.1
default_backend be_http
backend be_http
mode tcp
server domain 127.0.0.1:8080
HAProxy does support that.
HAProxy can offload TLS and forward to a backend that speaks h2c.
Details on how to setup this configuration are available in this blog post.
Related
I have a wordpress application deployed on an Apache server running on port 80 and I also have a java web application deployed on a Tomact server running on port 443.
So basically I have:
http ://mysite.com (Apache)
https: //mysite.com/application (Tomcat)
Now I need to start using my SSL certificate for my website. I know that these processes cannot share the same port. Is there a way to keep both urls without adding an extra port? So both can be accessed via:
https ://mysite.com (Apache)
https ://mysite.com/application (Tomcat)
I'm basing this answer on my configuration with Apache in the front of a Tomcat instance. I don't have your exact configuration but I believe the following should work.
I have an SSL configuration which is where things get forwarded to Tomcat.
I've modified it to be what I think you need:
<VirtualHost _default_:443>
ServerName www.example.com
ProxyPreserveHost on
ProxyPass /application http://localhost:8080/application
ProxyTimeout 360
# rest of the ssl configuration
</VirtualHost>
This should forward everything under /application to Tomcat and keep the rest being served by Apache. Note that this assumes that you have the proxy (a.k.a. mod_proxy) module enabled for your server.
An easy way of doing this is to mount an Nginx server and manage the redirection according to the URL hit:
server {
listen 80;
server_name *.domain.me;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name *.domain.me;
ssl_certificate /path/to/crt;
ssl_certificate_key /path/to/key;
location / {
proxy_pass http://destinationIp:destinationPort;
proxy_set_header Host $host;
}
}
Consider this HAProxy configuration here:
global
chroot /var/lib/haproxy
user haproxy
group haproxy
defaults
timeout connect 10s
timeout client 50s
timeout server 50s
frontend fe_https_tomcat
mode tcp
bind *:443 ssl crt /path/cert.pem alpn h2,http/1.1
default_backend be_tomcat
backend be_tomcat
mode tcp
server localhost localhost:8081 check
The issue I have is that WebSocket do not seem to get through. My guess was that in tcp mode everything would pass through. Looks like it doesn't ... :-)
The server responds with an error 403 when the WebSocket connection is getting established.
Note that with the following http-mode setup, the WebSocket just works:
frontend fe_http_8080
mode http
bind *:8080
default_backend be_tomcat_8080
backend be_tomcat_8080
mode http
server localhost localhost:8081 check
Note that I need tcp-mode to have http/2 working.
The issue was not related to HAProxy at the end, but to the WebSocket setup in Spring.
This fixed it:
-registry.addHandler(webSocketHandler, "/ws");
+registry.addHandler(webSocketHandler, "/ws").setAllowedOrigins("*");
I am using haproxy for port forwarding to Bitbucket server ssh. Here's haproxy config:
frontend sshd
bind *:7999
default_backend ssh
timeout client 1h
backend ssh
mode tcp
server localhost-bitbucket-ssh 127.0.0.1:7999 check port 7999
However if i do:
sudo haproxy -f haproxy.cfg
i am getting the following error:
[ALERT] 305/201411 (4168) : http frontend 'sshd' (haproxy.cfg:38) tries to use incompatible tcp backend 'ssh' (haproxy.cfg:43) as its default backend (see 'mode').
[ALERT] 305/201411 (4168) : Fatal errors found in configuration.
But i was referring to an official atlassian guide: https://confluence.atlassian.com/bitbucketserver/setting-up-ssh-port-forwarding-776640364.html are they wrong?
Also if i start haproxy before bitbucket server, bitbucket server cannot start on port 7999. I am totally confused. I have paid for that software and now i need to figure it out myself how to configure it for more than 2 days...
UPDATE
It was UFW as Thomj mentioned. But for what purposes do i need haproxy? If i can't bind Bitbucket's ssh to 22 port? I don't like to set port number.
The frontend configuration is defaulting to a mode of http which can't use a backend that's configured for tcp. Try adding 'mode tcp' to the frontend:
frontend sshd
bind *:7999
default_backend ssh
timeout client 1h
mode tcp
So I am using HAProxy in front of Jetty servlets.
The goal at the moment is just proof of concept and load and stress testing once everything's configured.
However I have a problem configuring haproxy. I know that it's not a problem with my application cause I have nginx(tengine) running and everything works properly. So it has to be something with the haproxy configuration or just the way haproxy works is not suitable for my needs.
So what my client tries to do is connect to haproxy using two different connections and keep them open:
Connect with a chunked streaming mode for upload.
Connect with a normal mode and establish a download channel.
Here's how my haproxy.conf file looks like:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
# ca-base /etc/ssl/certs
# crt-base /etc/ssl/private
# Default ciphers to use on SSL-enabled listening sockets.
# For more information, see ciphers(1SSL).
ssl-default-bind-ciphers kEECDH+aRSA+AES:kRSA+AES:+AES256:RC4-SHA:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL
maxconn 2048
defaults
log global
mode http
option forwardfor
option http-server-close
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
stats enable
stats uri /stats
stats realm Haproxy\ Statistics
stats auth user:password
frontend www-http
bind *:80
reqadd X-Forwarded-Proto:\ http
default_backend www-backend
frontend www-https
bind *:443 ssl crt /etc/haproxy/server.pem
reqadd X-Forwarded-Proto:\ https
default_backend www-backend
backend www-backend
redirect scheme https if !{ ssl_fc }
server www-1 localhost:8080 check maxconn 2048
And here's what my logs say when I try to access port 443:
Sep 17 11:10:18 xxxxx-pc haproxy[15993]: 127.0.0.1:32875 [17/Sep/2014:11:10:18.464] www- https~ www-backend/www-1 0/0/0/-1/1 502 212 - - PH-- 0/0/0/0/0 0/0 "GET /test HTTP/1.1"
Any ideas what the problem might be?
An issue with the configuration or ?
Thanks.
PH means that haproxy rejected the header from the backend because it was malformed.
http://www.haproxy.org/download/1.4/doc/configuration.txt
PH - The proxy blocked the server's response, because it was invalid,
incomplete, dangerous (cache control), or matched a security filter.
In any case, an HTTP 502 error is sent to the client. One possible
cause for this error is an invalid syntax in an HTTP header name
containing unauthorized characters. It is also possible but quite
rare, that the proxy blocked a chunked-encoding request from the
client due to an invalid syntax, before the server responded. In this
case, an HTTP 400 error is sent to the client and reported in the
logs.
I'm writing a simple HTTPS proxy program with Java for educational purposes. My program listens on a port (say 7443) for incoming HTTPS requests from a browser (say Firefox), parses the request and forwards it to the desired destination (say https://www.comodo.com).
Firefox's proxy settings are set to use my port for SSL connections ( 127.0.0.1 : 7443 ).
My code is short and simple:
static // initializer
{
System.setProperty("javax.net.ssl.keyStore", "MyKeyStore");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
}
SSLServerSocketFactory ssFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
try {
SSLServerSocket listener = (SSLServerSocket) ssFactory.createServerSocket(port, 64);
listener.setUseClientMode(false);
listener.setWantClientAuth(false);
listener.setNeedClientAuth(false);
SSLSocket connection = (SSLSocket) listener.accept();
browser.startHandshake(); /* <<== Exception throws at this line */
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
But I'm catching the following exception:
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
The exception says that the connection could be plain-text, but only HTTPS connections from Firefox are set to use this port. I have logged what Firefox is sending to my application which is this:
CONNECT www.comodo.com:443 HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:20.0) Gecko/20100101 Firefox/20.0
Proxy-Connection: keep-alive
Connection: keep-alive
Host: www.comodo.com
Firefox is talking palin-text, and I think CONNECT is a SOCKS command (I'm not sure though), where I haven't set anything in Firefox's SOCKS settings. Below is a screenshot of Firefox's proxy settings:
What am I missing here ?! What I need to do to make this work with Firefox or any other browser ?!
------------------------------------------------------------------------------
For those who think this is a duplicate of another question and that it has been answered in the other one I have to say: Yes, both questions have roots in a similar problem but the only answer in the cited question directs at using SSL Sockets which turned out to be misleading and resulted in this new question. So although they are aimed at a similar problem, this question shows a completely different and yet mislead path to go for solving the problem and so it could provide useful guidance for future persons facing such a problem.
Get rid of all the SSL. Just process the incoming CONNECT command, make a plaintext connection to the upstream server, and then start copying bytes. The browser and the server will speak SSL but you don't need to at all.
Your setup is using HTTP tunneling, where the initial request sent to the proxy is not SSL encrypted; since the SSL-enabled socket is expecting an SSL handshake, it throws an exception.
In this mechanism, the client asks an HTTP Proxy server to forward the
TCP connection to the desired destination using the "CONNECT" HTTP
method. The server then proceeds to make the connection on behalf of
the client. Once the connection has been established by the server,
the Proxy server continues to proxy the TCP stream to and from the
client. Note that only the initial connection request is HTTP - after
that, the server simply proxies the established TCP connection.
You can read more about it at HTTP Tunneling wiki page. To see this in action, you can start off a netcat server and set the Firefox proxy to point to that port:
nc -l 8000
Now in Firefox type in https://www.google.com, and examine the nc output:
CONNECT www.google.com:443 HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0)
Proxy-Connection: keep-alive
Connection: keep-alive
Host: www.google.com
And this is completely in plaintext. Below diagram demonstrates how Firefox proxy expects to communicate.