Serve Rails API and Ionic mobile website together - ruby-on-rails

Basing on How to run Ionic serve permanently? and Deploy Ionic as a website, nginx should be able to serve the code from the Ionic's www folder. I am exploiting the idea of serving it with its Rails back-end together using the same domain address... so that no CORS traffic and overhead will be added. Another requirement for the Rails WEB is to still handle the desktop (HTML) version of the website. Essentially, there will be 3 types of requests coming to the nginx server:
loading html, js, css files from the mobile/www/ directory
mobile website and APP JSON calls to Rails API
desktop website HTML calls to Rails
Type 2 requests may be simple because they all have the .json extension. With sub-domains are taken by the username, i.e. username.example.com, any ideas on how to have nginx route the html, js, and css requests correctly? Or is this too much of a challenge?

Take #1: Come up with a Nginx config that returns Ionic files when Rails signals it in a hidden manner. May be clumsy, so please feel free to offer criticism, pitfalls, or improvements.
Nginx config:
server {
# Development logging
access_log /home/builder/projects/web/log/access.log;
error_log /home/builder/projects/web/log/error.log notice;
listen 80;
server_name projects.host www.projects.host;
# Eusure Rails' index route gets uri "/" first.
index index.html;
# All API json calls and requests to Rails controllers.
location ~ ^\/(.+\.json$|others.*|users.*|index\.html$) {
# Rails server
proxy_pass http://127.0.0.1:3000;
# The Rails server may request Ionic mobile website with a temporary redirect (status 307)
proxy_intercept_errors on;
error_page 307 = #temp_redirect;
}
# If a temporary redirect is to /mobile_web, response with Ionic mobile root.
location #temp_redirect {
if ($upstream_http_location ~ ^http.+\/\/.+\/mobile_web$) {
set $mobile true;
root /home/builder/projects/mobile/www;
}
# Something else, return it.
if ($mobile != true) {
return 307 $upstream_http_location;
}
}
# Ionic mobile root
location / {
root /home/builder/projects/mobile/www;
}
}
In RoR:
# Decide whether to handle the root action within Rails app or to
# signal the downstream server (nginx) to return Ionic mobile web.
def index
# TODO: Needs a bit of logic before the following redirect.
redirect_to '/mobile_web', status: :temporary_redirect # 307
end
Two birds with one APP :).

Related

Multiple Docker Containers Hosted In Nginx With URL Instead Of Subdomain

I'm a noob to docker, Nginx, and devops, so go easy on me.
I've followed a few tutorials that show me how to host multiple web apps through docker containers using Nginx and subdomains. I cannot create a new A Record for this domain, so I can't use subdomains, it has to be a url. If I could create a new A Record, I found a million tutorials that show me how to host it on ProjectA.example.com but since I don't have access to create a new A Record for the domain, I need to find a way to host it on something like example.com/ProjectA. Another obstacle is only port 80 is open to the outside, so all traffic must come through port 80 and be reverse proxied to whatever port the docker container is forwarding from.
So far I have an Nginx configuration that looks something like this
server {
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
listen 80;
server\_name \_;
location / {
try\_files $uri $uri/ =404;
}
location /projectA {
proxy\_pass http://127.0.0.1:9001/;
}
location /projectB {
proxy\_pass http://127.0.0.1:9002/;
}
}
This works getting me to the homepage of the project. But the CSS of the website doesn't load, and whenever I click a link, it sends me to something like example.com/signup instead of example.com/projectA/signup. I tried making a wildcard location (location \~ /projectA.\*) but Nginx didn't like that. I was thinking there's probably a way I could get something like if the referring uri contains projectA, send them to example.com/projectA$uri but I couldn't find the documentation on the syntax.
Basically the question is, is this a good way to tackle the problem, and does anyone have a link to a tutorial or some documentation on how to do this?
Using a trailing slash behind location should do it:
location /projectA/ {
proxy_pass http://127.0.0.1:9001/;
leads /projectA/whatever to http://127.0.0.1:9001/whatever
If you want to use regex to rewrite, it's something like that:
location ~ ^/projectA/(.*)$ {
proxy_pass http://127.0.0.1:9001/$1;
or
location /projectA/ {
rewrite ^/projectA/whatever/(.*)$ /whatever.php?path=$1 break;
proxy_pass http://127.0.0.1:9001/;
}
leads /projectA/whatever/foo to http://127.0.0.1:9001/whatever.php?path=foo

How to serve a single page application in a Swift iOS app?

I have a Swift project with a webview that is serving files from a local folder vai GCDwebserver, however the website is designed as a single page application, is there any way I can rewrite all url requests to index.html?
I'm currently using GCDwebserver but I'm willing to change servers to get the SPA to load in the webview.
With nginx I'd do somthing like
server {
listen 8080;
listen [::] 8080;
root /root/bundled;
location / {
try_files $uri $uri/ /index.html;
}
}
How do I get the same rewrite effect on a webview in osx?
Simply use a default handler to catch all GET request:
- (void)addDefaultHandlerForMethod:(NSString*)method requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block;
Or a regex one if you want to do more fancy matching:
- (void)addHandlerForMethod:(NSString*)method pathRegex:(NSString*)regex requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block
Or even go all the way to a match block:
- (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)processBlock;
I must admit I've never used GCDWebserver, but if you have any requirement in an iOS app to redirect a url you can use NSURLProtocol. You can read more about it here https://www.raywenderlich.com/76735/using-nsurlprotocol-swift. Once you've read the link you basically need to use the method canonicalRequestForRequest to capture the current request and return a new one. Hope that helps.

How can I have nginx return 304 Not Modified based on a Redis cache?

I'm looking at setting up a Redis cache to speed up a Ruby on Rails application deployed with nginx. I want nginx to send a 304 Not Modified either based on a timestamp in the Redis db (e.g. last modified), or based on the existence of a key. The only thing I found so far is how to cache full pages in Redis, like the following example from the HttpRedis module:
server {
location / {
set $redis_key $uri;
redis_pass name:6379;
default_type text/html;
error_page 404 = /fallback;
}
location = /fallback {
proxy_pass backend;
}
}
Does anyone know if this is possible? Or would you recommend another way to send 304 responses without going to the Rails stack?
You should be able to do this with the HttpRedis2Module and the HttpLuaModule.

Nginx and rails maintenance pages, getting Squid 2.7 to not cache them, or alternatives to squid

I'm running Squid 2.7 on a load balancer and it seems to want to happily cache anything that comes its way, including (and especially annoyingly)maintenance pages.
The maintenance pages are served through a nginx error page hook, so I don't seem to have that much control over their cache headers, I'd like to just tell squid not to cache non 200 pages. Is there a way to do that without upgrading squid? (I know newer squid has a way to match the http status on acl rules)
The page itself already has meta tags for no cache, but that doesn't seem to help squid.
Here is the bit of config from nginx that sends the error page:
location / {
passenger_enabled on;
passenger_friendly_error_pages off;
recursive_error_pages on;
if (-f $document_root/system/maintenance.html) {
return 503;
}
error_page 503 #503;
}
location #503 {
if (-f $request_filename) {
return 200;
break;
}
error_page 405 = /system/maintenance.html;
rewrite ^(.*)$ /system/maintenance.html break;
}
Maybe there is a better way to do this on nginx end, or maybe some way to add extra stuff to these error pages ot make them behave better with squid.
The general idea is that if document_root/system/maintenance.html exists, the system is in maintenance mode and that page should be rendered for all requests (except static files so that the page can reference stylesheets or images or whatnot)
As for the squid end, I don't really have anything specific to show for it, its a pretty cookie cutter setup for a caching reverse proxy.
On a flip note, maybe there is a better alternative to using squid, I'm open to that suggestion too.
I know this isn't what you are looking for however something like this is much nicer on the system, this serves files then the maintenance page if it is in place then falls back to the backed server
try_files $uri $uri.html /maintenance.html #unicorn_story;
This does work well enough for us via squid but I would test it.
You could also clear squid after coming out of maintainance.

application stopped loading static assets after the use of nginx

I am trying to set up multiple proxies using nginx to various rails apps on one domain. These apps can be found in the domain as such: example.com/app1, example.com/app2.
After implementing this, example.com/app1 stopped loading any static assets (ex. css images). Would anyone have an idea why this is so, and how to fix this?
The URLs generated by Rails reference the root URL: /javascripts/filse.js, which is clearly incorrect. It should instead be /app1/path/to.asset
Here's a portion of my server configuration:
server {
listen 80;
location /app1/ {
root /www/app1/public;
proxy_pass http://127.0.0.1:3000/;
include proxy.conf;
}
}

Resources