Mapping hudson to a subdomain through nginx proxying
I'm now trying to setup nginx as a reverse proxy for Hudson so it can be access on
http://build.example.comdirectly. I've already installed Hudson on Tomcat and verified that I can access Hudson on
http://127.0.0.1:8080/hudson
It was pretty straight forward to get to where it's possible to access hudson on http://build.example.com/hudson. But when I tried to setup the proxy to remap the /hudson directory, things starts to go wrong. None of the css or image files are being loaded.
A quick look at the nginx access log tells me that lots of requests are being made to resources at /hudson or /hudson/static. These requests are not being forwarded (or rewritten) to Tomcat correctly. But after digging around for several hours, I'm at a lost at how to fix this simple problem.
The nginx settings I'm using looks like
server {
listen 80;
server_name build.example.com;
location / {
proxy_pass http://127.0.0.1:8080/hudson;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Can somebody shed some light on this? It's gotta be really simple to setup, but I can't seem to find the solution anywhere on the net.
Update
My sincere thanks to all those who took the time to answer this question. After trying various solutions, I think the most straight forward way to deal with this particular problem is either to...
A) Leave it alone As @VonC suggested, let it stay in a sub-directory. It's straight forward and we'll be certain that nothing will break. Or...
B) Deploy the app to the ROOT of tomcat webapp directory Perhaps this is not the best way of doing things if you want to host multiple webapps with a tomcat installation. But an admin might want to setup a separate tomcat install just to run Hudson/Jenkins anyway. Tomcat isn't capable of running different hosted apps as different users and that anyone setting up Hudson/Jenkins for CI will likely want to run it as a specific user ("build" for example). In this case, deploying in ROOT makes the most sense, which can be mapped to build.example.com very simply.
Here is my nginx configuration file, even though I access Hudson through https (port 443):
The trick with reverse proxy (Apache or Nginx) is to always keep the same path:
If you want to redirect to a_long_and_complex_address/hudson
, keep the /hudson part: myserver/hudson
.
Don't try to redirect myserver
to a_long_and_complex_address/hudson
: all sorts of scripts and pictures, with absolute paths ('/
') will broke.
Redirect myserver/hudson
to a_long_and_complex_address/hudson
.
Plus, you can redirect myserver/other_services
to a_long_and_complex_address/other_services
as well ;)
worker_processes 1;
error_log logs/error.log debug;
pid logs/nginx.pid;
events {
worker_connections 250;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 150;
#gzip on;
port_in_redirect on;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
server {
listen 443;
server_name (some alias);
# default max client body size was 1m! => Error code is 413
# here: max 10Go
client_max_body_size 10000m;
ssl on;
ssl_certificate /home/xxx/.ssl/my.crt;
ssl_certificate_key /home/xxx/.ssl/my.key;
ssl_session_timeout 5m;
#ssl_protocols SSLv2 SSLv3 TLSv1; # NO: SSLv2 prohibited
ssl_protocols SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
rewrite ^/hudson$ https://myserver/hudson/ redirect;
location /hudson/ {
proxy_pass https://complex_address:8xx3/hudson/;
}
}
}
From the experiences I've had with nginx, the way you specify urls to proxy is a bit strange (because you have to specify the full url rather than just a directory). I believe your configuration could go something like this:
upstream 127.0.0.1:8080 {
ip_hash;
server 127.0.0.1:8080;
}
location ~* ^/(.*) {
proxy_pass http://127.0.0.1:8080/hudson/$1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Let me know if it works for you.
Edit: To work around absolute requests you'll have to add in a second location definition that does
location ~* ^/hudson/(.*) {
proxy_pass http://127.0.0.1:8080/hudson/$1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
or add in the redirect that Alaz has recommended:
location /hudson {
rewrite ^/hudson(.*)$ $1 redirect;
}
Unfortunately, unless you rewrite the source for hudson to retrieve resource files by relative path this is your only workaround, unless nginx has an http stream modifying plugin that I don't know of like mod_proxy_html for apache...