URL Base
Add the ability to set the URL base for use with reverse proxies such as nginx so the mobile app can work remotely.
-
Official comment
Thanks for the input, its greatly appreciated.
Brandon M
RainMachine.Comment actions -
Hi Mark,
I think you want a remote access to the device outside of our remote access solution ?
If so this feature already exists, you can go to your mobile app Devices screen:
1. Press the 3 lines (hamburger) menu from the top left corner
2. Select Network Settings->Direct Access
3. Add the https://< IP >: < PORT> combination that you want to access.
Regards,
Nicholas
-
I host multiple apps on my network that I make accessible externally. From a security perspective I only want one port opened externally. Leveraging a reverse proxy allows me to do so. My external URL for rainmachine is www.mydomain.net:443/rainmachine. I can use nginx to strip off rainmachine and redirect it to my internal rainmachine IP and port number (https://192.168.1.5:8080), but it fails. There seems to be a redirect at that address for the restful API as hitting it frm a browser goes /api/4/ and the api login page. I can append that to the URL with nginx and redirect external traffic to https://192.168.1.5:8080/api/4/. From a browser externally hitting https://www.mydomain.net/rainmachine I can get to the restful api main page. Login however from a browser or the mobile app fails. I am guessing all of the pages after logon are not in the /api/4/ folder or subfolders. I could tell nginx to try different locations if I knew the folder structure for the web site and restful api. All of the other apps I host internally all support a URL base so that they would listen on in this example https://192.168.1.5:8080/rainmachine. In that scenario all one has to do in nginx is pass the external request to https://192.168.1.5:8080/rainmachine. You don't have to strip off rainmachine, add /api/4/ and try to redirect to other folders needed for the web page and app to function properly. A URL base simplifies this greatly and helps keep the environment more secure.
-
I'm not sure atm why it doesn't work, we have a similar functionality on our https://my.rainmachine.com. The api/4/ pages are not static but generated from our internal rest server.
There is indeed a redirect internally on device from https://ip:8080 to http://locahost:18080 so we offload https handling. Maybe your issues are with POST (something in the redirect chain alters headers/body ?) Does GET works for https://www.mydomain.net/rainmachine/api/4/apiVer ?
Regards,
Nicholas
-
I had to add the redirect to my proxy_pass to get anything to work so my external URL is https://www.mydomain.net/rainmachine which gets redirected behind the scenes to https://192.168.1.2:8080/api/4/. When I add apiVER to https://www.mydomain.net/rainmachine making it https://www.mydomain.net/rainmachine/apiVER it gets redirected behind the scenes to https://192.168.1.2:8080/api/4/apiVER/. I do not get an error in the browser, but a blank page is loaded. I would guess that pages needs content outside of /api/4/ which it cannot reach. The proxy_pass command makes the root of the web page be /api/4/. So it if needs files say at /api/3/ or /etc/content/ it does not know how to get to them. Having the ability to set the URL base then makes the reverse proxy base the same as the base for the web site on the appliance and then it knows how to reach them.
-
No there aren't any other "content" outside of /api/4/ even our /apiVer it's a reply from /api/4/apiVer (note there is not / at the end which might add to your errors) the /api/4/ is the URL base for all version 4.x API calls and don't depend on any other paths.
You could try to redirect to http://192.168.1.2:18080/api/4/
Regards,
Nicholas
-
I removed the trailing slash after apiVER and still get just a blank page. I also had already tried to redirect to http://192.168.1.122:18080/api/4/ and get the same results. I can get to the API login page in a browser and from the mobile app, but can get no further.
-
I temporarily opened port 8080 on my firewall and forwarded it to 192.168.1.122:8080. Now if I point the ios app at www.mydomain.net:8080 it works fine. Pointing a browser at www.mydomain.net:8080/api/4/apiVER loads a blank page. That seems to be normal behavior for that page. Get the same result against 192.168.1.122:8080/api/4/apiVER and http://192.168.1.122:18080/api/4/apiVER.
-
https://www.mydomain.net:8080/api/4/apiVer returns {"apiVer": "4.2.0", "hwVer": 3, "swVer": "4.0.750"}.
https://www.mydomain.net/rainmachine/apiVer loads a blank page. Does apiVer need something in say api/4/apiBin or something similiar and if so it is referenced via that absolute path or is it referenced via the relative path ../apiBin? The absolute path would fail behind nginx. The browser will return /rainmachine/apiBin (rainmachine effectively equals /api/4/) where as with an absolute reference the code is expecting rainmachine/api/4/apiBin.
-
For anyone else who stumbles across this and wants to give it a shot.
This works for /api/4/
location /rainmachine/ {
rewrite /rainmachine/([^/]+) /$1 break;
proxy_pass https://192.168.1.122:8080/api/4/;
}This works for /api/4/apiVer
location /rainmachine/ {
rewrite /rainmachine/([^/]+) /api/4/$1 break;
proxy_pass https://192.168.1.122:8080/;
}Cannot seem to find a combination that will overcome the absolute pathing in the code and allow both to work without a URL base.
-
Just got this working for me:
https://gist.github.com/jessegoodier/762563ce3b8c4b9715addafecb5501ca
server {listen443ssl http2;server_name rainmachine.xyz;;
ssl_certificate /etc/nginx/fullchain1.pem;ssl_certificate_key /etc/nginx/privkey1.pem;
location / {
proxy_passhttp://rainmachine-host$request_uri;
proxy_http_version 1.1;proxy_cache_bypass $http_upgrade;proxy_set_header Host $host;proxy_set_header X-Forwarded-Server $host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_ignore_client_abort on;
}}upstream rainmachine-host {server10.0.1.121:8081;} -
I'm looking for a similar setup as @Mark.
I have several services that sit on my network that need to be proxied through NGINX for SSL and authentication. Each service gets a separate "root route", ex https://<mydomain>/octoprint, https://<mydomain>/home-assistant. I would like to have the ability to add a header to the upstream request to specify the root of all requests by the RainMachine instance.
In the case of Octoprint, I can specify this:
proxy_set_header X-Script-Name /octoprint/artistd;
This tells the web application to prefix all of its requests to its resources with "/octoprint/artistd".
This could be detected and a "base" (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) element could be added.
Looking at the unminified JavaScript it appears that all the paths are using an absolute reference:
this.URL = Object.freeze({
auth: '/auth',
provision: '/provision',
dailystats: '/dailystats',
restrictions: '/restrictions',
program: '/program',
zone: '/zone',
watering: '/watering',
parser: '/parser',
mixer: '/mixer',
diag: '/diag',
machine: '/machine',
dev: '/dev',
communityWeather: 'https://raw.githubusercontent.com/sprinkler/rainmachine-developer-resources/master/version-metadata.json'
});Some simple JavaScript could be written to use window.location along with those paths to make them relative to the application root.
For a work around I'm attempting at using the sub_filter module in NGINX to rewrite the JavaScript returned from the server. I haven't had luck yet. I'll post if I'm able to find a workaround.
-
Ok, update. I figured it out. The base element won't work because the script is using fully qualified URLs for requests as opposed to "/api/4". I found the following in code (unminified):
var c = window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/api/4'
I get upset with my developers when they do this. Can't use this in multi-tenant situations, etc.
So here's how I got around it.
First create your base location for "rainmachine":
location /rainmachine/ {
proxy_pass http://192.168.2.98:8081/ui/;
sub_filter '/api/' '/rainmachine/api/';
sub_filter_once off;
sub_filter_types *;
proxy_set_header Host $host;
proxy_redirect http:// https://;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}The key here is the sub_filter* entries. This tell NGINX to modify the response so that "/api/" becomes "/rainmachine/api/". This effectively changes the JS so that it will send requests to the rainmachine location. Also note that I used the /ui/ route on my proxy_pass. This is so that my URLs look like https://<mydomain>/rainmachine/ in the browser.
I then created one more location:
location /rainmachine/api/ {
proxy_pass http://192.168.2.98:8081/api/;
proxy_set_header Host $host;
proxy_redirect http:// https://;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}This captures the "/api" requests and sends them to the correct route on the upstream host. If you set your proxy_pass to be the root of the rainmachine server this may not be necessary.
I'm still testing to see if everything works correctly. I've been able to log in successfully and browse around.
To RainMachine: Please implement a setting so that this isn't necessary! I understand you guys want people on your service but there are some of us that are completely fine with this type of setup. I'm going to be migrating a lot of my internal servers to AWS soon with a VPN link locally so that I can dynamically update DNS records and have automated LetsEncrypt cert updates. Being able to change how the upstreams are accessed would be SUPER helpful. A secondary request would be to have a containerized instance of the UI so that I could deploy that to my k8s host and point that back to a "headless" RainMachine instance would be AWESOME!
Thanks!
Mike G
Please sign in to leave a comment.
Comments
18 comments