Apache Tomcat mod ajp - apache

I am trying a very simple setup with "demo00" successfully working on Tomcat and accessible by public IP:Port/demo00. However when I try the virtual host below it fails to even find the website. The website can be pinged, I do not want to serve any static content just take every request to "demo00". Below is the Apache(2.4.54) virtual host second below is the Tomcat(9.0.64) configuration.
Apache
<VirtualHost *:80>
ServerName www.mydemo.com
ServerAlias mydemo.com
ProxyPass / ajp://localhost:8009/demo00 secret=123
ProxyPassReverse / ajp://localhost:8009/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Tomcat
<Connector protocol="AJP/1.3"
port="8009"
redirectPort="8443" address="::1" secretRequired="true" secret="123"
/>

The problem is probably the localhost in httpd.conf plus the address="::1" in Tomcat. I'll bet httpd is trying to use an IPv4 address but Tomcat is only listening with IPv6. Try address="localhost" instead.
The configuration guide says that the default is to listen on all local interfaces. It does this by using "localhost" as the default address. When using "localhost", the behavior depends upon the local DNS resolver. Some systems will return only 127.0.0.1 while others will return 127.0.0.1 and ::1, and I'm not sure they will be returned in a predictable order (i.e. there is no DNS requirement that IPv4 precede IPv6 addresses in responses). Tomcat uses whatever Java returns from InetAddress.getByName(String host) which doesn't specify which IP will be returned if the hostname maps to multiple IPs.
It is highly likely that using "localhost" for both httpd and Tomcat will result in a connection which is reliable, since the DNS resolver is likely to be consistent if not predictable a priori. When in doubt, always use specific IP addresses in all places.
Incidentally, if you are building a new setup, I would highly recommend against using AJP. Instead, use mod_proxy_http and a plain-old HTTP(S) connector on the Tomcat side. You can read a presentation about why to migrate from AJP to HTTP on the Tomcat web site.

Related

Apache HTTP VM Behind HTTPS Lets Encrypt

I've read a lot of questions and answers which seem exactly the same as mine, but I can't seem to get my setup to work. I have a VM running Apache with only HTTP support at 192.168.2.101:32773. I can access it on my local network as such just fine. I now am ready to expose it through my Apache web server that has Lets Encrypt setup to generate SSL certificates. So I added this to my server conf file:
<VirtualHost *:32773>
ServerName server.com
SSLEngine on
SSLProxyEngine On
SSLCertificateFile /etc/letsencrypt/live/server.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/server.com/privkey.pem
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://192.168.2.101:32773/
ProxyPassReverse / http://192.168.2.101:32773/
</VirtualHost>
However, I get an ERR_SSL_PROTOCOL_ERROR when I try to load it up as https://server.com:32773. If I however change my address to http://server.com:32773, it loads just fine. Anything look wrong in this snippet? Thanks!
HTTP and HTTPS need to be on different ports. Typically HTTPS is served on port 443.
This is embarrassing... At some point I changed my port forward rules to point 32773 directly to 192.168.2.101 so I could validate that the rules were working at all. The above config worked as soon as I realized I wasn't even sending traffic to my Apache SSL enabled server.

Apache Httpd - How to proxy-redirect two virtual hosts according to the path in requesting url?

I got a problem here, which could look trivial, but my basic knowledge in configuring apache and all the stuff I searched today didn't lead me to any satisfying solution.
I have two physical servers, and I run two applications on each one : one contained in a node.js instance, reachable and responding on port 4200 and another one contained in Tomcat on port 8080 (respectively my front-end and my back-end).
The requests from http client arrive on node server through port 80 and I configured an httpd to redirect them to the two instances according the path after the url.
The target behaviour is that httpd redirects every request to the node instance by default, and redirects to the remote tomcat the requests matching the following structure : physical_server_ip/api/*
So here's what I included in my httpd.conf on server hosting node instance and httpd :
<VirtualHost *:80>
#Filter on '/api/' path in url for node instance
ProxyPass /api/ !
ProxyPass / http://localhost:4200/
ProxyPassReverse / http://localhost:4200/
ProxyPreserveHost On
</VirtualHost>
<VirtualHost *:80>
# Proxy to remote machine on which tomcat runs and provides services
ProxyPass /api/ http://<tomcat_machine_alias>:8080/xd-service/api/
ProxyPassReverse /api/ http://<tomcat_machine_alias>:8080/xd-service/api/
ProxyPreserveHost On
</VirtualHost>
When i request my node machine through Apache, I can see the response from the first block (the node instance), but the others requests (those whose path begin with /api/) not.
In the browser console, it appears that these ones (the requests design to interrogate apis) are not proxied by apache and are sent to the node instance and not the tomcat.
What am I missing ?
Dusan Bajic's answer resolved the problem : the two proxy rules sets needed to be merged in one virtual host, ordered from the most specific to the less specific.

connect to alternate alternate host alias with ajp protocol

I am connecting to two tomcat application via the ajp protocol.
both of which are running in separate tomcat virtual host as ROOT.war.
On the server, I have configured the /etc/hosts file
127.0.0.1 localhost tcvh1 tcvh2
apache httpd.conf:
Listen 80
NameVirtualHost *:80
<VirtualHost *:80>
#ProxyPreserveHost On
ServerName app1.example.com
ProxyPass / ajp://tcvh1:8082/
ProxyPassReverse / ajp://tcvh1:8082/
</VirtualHost>
<VirtualHost *:80>
#ProxyPreserveHost On
ServerName app2.example.com
ProxyPass / ajp://tcvh2:8082/
ProxyPassReverse / ajp://tcvh2:8082/
</VirtualHost>
Tomcat :
I have the applications deployed as:
app1 -- $CATALINA_HOME/tcvh1/ROOT.war
app2 -- $CATALINA_HOME/tcvh2/ROOT.war
Now,
If I changed the tomcat to run on port 8080, and changed the proxy pass to connect to http://tcvh1:8080, then it works. but if I used the configuration with AJP, it does NOT work.
Why does my host alias not work with AJP? is there a way to make it work?
It doesn't work because the mod_proxy_ajp always passes the host header received by httpd to Tomcat whereas the mod_proxy_http will use the host defined in the ProxyPass unless ProxyPreserveHost is set to On.
Since - as far as httpd is concerned - your virual hosts are app1.example.com and app2.example.com, these are what get passed to your Tomcat instance. Tomcat has no record of these virtual hosts. It has tcvh1 and tcvh2. Therefore all the requests will get routed to the default virtual host (which ever one is defined on your Engine element in server.xml).
There are several ways to fix this:
Rename you Tomcat virtual hosts to match your httpd virtual hosts
Add aliases ( see http://tomcat.apache.org/tomcat-7.0-doc/config/host.html#Host_Name_Aliases) to your Tomcat virtual hosts.
Personally, I'd go with option 2. Quicker and simpler.

Send subdomain to node.js

My work runs a couple different internal web apps on an ubuntu server (10.10) running apache. I'm currently developing another web app, and am seriously considering developing on top of a custom-built node.js web server. My reasoning for wanting to do this is:
Speed/Scalability
Security - Pages will be served with a switch...case, instead of just serving the (potentially malicious) user whatever they ask for.
Ease of setup - my intentions are for this to be an open-source project, and node.js is much easier for users to set up, rather than dealing with apache/IIS/etc.
My question is, on a server where I've got apache listening to port 80, how can I pass off a certain subdomains to node.js. I've seen a couple articles about using apache virtual hosts to pass it off, but that seems to defeat the purpose of using node.js. If I have to go through apache, then all three of my reasons for avoiding apache/IIS have voided themselves.
I know I could use a different port (:8080?), but from an end-user standpoint, it's pretty confusing having to put in custom ports. Any alternative ideas?
Thanks
<VirtualHost *:80>
ServerName subdomain.yourdomain.com
ProxyPreserveHost on
ProxyPass / http://localhost:8080/
</VirtualHost>
Thanks to http://www.chrisshiplet.com/2013/how-to-use-node-js-with-apache-on-port-80/
if socket.io node is running, be sure to enable also few apache mods:
a2enmod proxy
a2enmod proxy_balancer
a2enmod proxy_express
a2enmod proxy_http
in file /etc/apache2/sites-available/chat.example.com.conf
<VirtualHost *:80>
ServerName chat.example.com
<Location "/">
ProxyPreserveHost On
ProxyPass http://localhost:3000/
ProxyPassReverse http://localhost:3000/
</Location>
</VirtualHost>
then of course service apache2 reload
How about doing things the other way round : bind node to port 80, handle the traffic targeted at the subdomain and use it as a reverse proxy to apache for everything else ?
Let me start from the ground up:
You have a DNS. And a dns server maps one DNS to one IP!
You then have apache running on your computer that listens for connections on port 80 for http:// and on port 443 for https://. http://example/ is actually a request on http://example:80/.
You can't use node.js to listen on the same machine on the same port as apache. That's why using port 8080 is viable.
You can also map the subdomain to a different IP. The only caveat here is that you need to have a public IP Address.
You can't serve port 80 from both Apache and node.js. Having Apache as a reverse proxy wouldn't be much efficient and that's why nginx is popular in this scenario. Other alternative than nginx based reverse proxy can be as Khez suggested mapping your subdomain to different IP address which will node.js program listen to or maybe use node.js itself as a reverse proxy for Apache.
You could configure a virtual host in apache for your new site and add a permanent redirect within it to the localhost and port used by node.js.
This is how I do it on a server with several other virtual hosts and my node.js application running on port 3000:
NameVirtualHost *:80
[Other virtual hosts omitted for brevity]
...
ServerName mynewsite.com
RedirectMatch (.*) http://localhost:3000$1

Apache Name Virtual Host with SSL

I am attempting to setup our servers to allow traffic over SSL. I am aware that SSL does not work with Name Virtual Host, but we have all of our Apache servers on virtual machines with dedicated private IPs. We have a primary virtual machine that has mod_proxy setup to route traffic to the appropriate VMs.
However, in order to route HTTPS traffic we need to have the certificate installed on the proxy as well as the VMs. We have a wildcard certificate that can be used across all of our hosts. Everything appears to work properly, but I receive the following in the Apache logs for the proxy:
[warn] Init: SSL server IP/port conflict: host1.example.com:443 (/etc/apache2/sites-enabled/host1:1) vs. host2.example.com:443 (/etc/apache2/sites-enabled/host2:1)
There is one of these error message for each host we have setup on the proxy. Our Virtual Host setup for the proxy is posted below:
<VirtualHost ipaddress:443>
ServerName host1.example.com
ProxyPreserveHost On
ProxyRequests Off
ProxyPass / https://privateip:443/
ProxyPassReverse / https://privateip:443/
SSLProxyEngine on
SSLEngine on
SSLCertificateFile /etc/ssl/certs/server.crt
SSLCertificateKeyFile /etc/ssl/private/server.key
</VirtualHost>
Is there any way that I can get this to work?
It sounds like Apache is warning you that you have multiple <VirtualHost> sections with the same IP address and port... as far as getting it to work without warnings, I think you would need to use something like Server Name Indication (SNI), a way of identifying the hostname requested as part of the SSL handshake. Basically it lets you do name-based virtual hosting over SSL, but I'm not sure how well it's supported by browsers. Other than something like SNI, you're basically limited to one SSL-enabled domain name for each IP address you expose to the public internet.
Of course, if you are able to access the websites properly, you'll probably be fine ignoring the warnings. These particular ones aren't very serious - they're mainly an indication of what to look at if you are experiencing problems
As far as I know, Apache supports SNI since Version 2.2.12
Sadly the documentation does not yet reflect that change.
Go for http://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI until that is finished
You may be able to replace the:
VirtualHost ipaddress:443
with
VirtualHost *:443
You probably need todo this on all of your virt hosts.
It will probably clear up that message. Let the ServerName directive worry about routing the message request.
Again, you may not be able to do this if you have multiple ip's aliases to the same machine.
The VirtualHost would look like this:
NameVirtualHost IP_Address:443
<VirtualHost IP_Address:443>
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/ca.crt # Where "ca" is the name of the Certificate
SSLCertificateKeyFile /etc/pki/tls/private/ca.key
ServerAdmin webmaster#example.com
DocumentRoot /var/www/html
ServerName www.example.com
ErrorLog logs/www.example.com-error_log
CustomLog logs/www.example.com-access_log common
</VirtualHost>
First you need NameVirtualHost ip:443 in you config file!
You probably have one with 80 at the end, but you will also need one with 443.
Second you need a *.domain certificate (wildcard) (it is possible to make one)
Third you can make only something.domain webs in one ip (because of the certificate)
You MUST add below part to enable NameVirtualHost functionality with given IP.
NameVirtualHost IP_Address:443
Apache doesn't support SSL on name-based virtual host, only on IP based Virtual Hosts.
Source: Apache 2.2 SSL FAQ question Why is it not possible to use Name-Based Virtual Hosting to identify different SSL virtual hosts?
Unlike SSL, the TLS specification allows for name-based hosts (SNI as mentioned by someone else), but Apache doesn't yet support this feature. It supposedly will in a future release when compiled against openssl 0.9.8.
Also, mod_gnutls claims to support SNI, but I've never actually tried it.