Heroku Cedar and nginx (gzip) - heroku

According to the comments in the accepted answer here Rails how to Gzip Javascript? (Heroku) and the official cedar documentation (http://devcenter.heroku.com/articles/http-routing#the_herokuappcom_http_stack):
Since requests to Cedar apps are made directly to the application server – not proxied through an HTTP server like nginx – any compression of responses must be done within your application. For Rack apps, this can be accomplished with the Rack::Deflater middleware. For gzipped static assets, make sure that Rack::Deflater is loaded before ActionDispatch::Static in your middleware stack.
However, as far as I can tell, my app is running on herokuapp.com (cedar) and, according to the heroku logs, is using nginx to serve data (which is great). I've also confirmed via the Content-Encoding HTTP header that it is gzipping data to the browser. According to the documentation, that is NOT supposed to happen on cedar. Am I missing something here?

You must be accessing these apps through a domain pointing to these IPs:
75.101.163.44
75.101.145.87
174.129.212.2
These are the apex faces and they are in front of both bamboo and cedar apps. Varnish is there for bamboo, but any request that goes through them ends up going through varnish too.
These faces are only for apex domains. If your app is under a subdomain such as www, it should be setup as a CNAME pointing to appname.herokuapp.com. When setup like that, requests will not go through varnish.
For more on Apex's and Heroku, see here: http://neilmiddleton.com/the-dangers-of-a-records-and-heroku/

Related

How to host a website on Heroku without using heroku's own http router?

I need to host a website on Heroku, but I need to have direct access to the HTTP traffic without Heroku's own http router meddling in.
That's not possible.
Heroku doesn't provide a full server infrastruture.
It's rather a limited platform to host HTTP services.

Reverse proxy same naked domain to different hosts

I'm managing the DNS of my domain with Cloudflare.
The marketing pages for are hosted with Netlify.
The main application is hosted with Heroku.
Is it possible with cloudflare + a naked domain (my-example.com) to have some paths being served by Netlify and other paths by Heroku?
Or am I forced to put one of the hosting services on a subdomain?
Disclaimer: I work for Netlify.
You can definitely do this without running your own server or paying anything extra.
Since Netlify already has a CDN, it's suboptimal to put cloudflare's CDN (activated with the 'orange cloud' in their settings) in front of Netlify's. Besides being inefficient, doing so breaks Netlify's atomic deploys and rollbacks and also slows down page service from our observations. It may work, but is not recommended. However, CloudFlare's DNS is quite performant and can be used without their CDN (turn off the 'orange cloud'). Their DNS works well with content hosted on Netlify's CDN.
Here's how to set things up to accomplish this via Netlify.
Deploy your static assets to a Netlify site at your main custom domain, let's say it's my-example.com. For testing purposes you can use the built-in sitename at Netlify (something-something-1234.netlify.com) instead of my-example.com. The below example redirects are "host agnostic" so will work with the Netlify hostname, Netlify deploy previews, AND the production hostname.
Find all the paths for your dynamic content - for this example, let's say it's /main/* and /app/* that are dynamic and your backend is hosted on Heroku.
Create proxy redirect rules to point to those paths. They could be hosted via CloudFlare's CDN to protect your API if you wanted to - Netlify proxying to CloudFlare-fronted sites on Heroku works fine. You could also choose just to proxy straight to Heroku which would be less complicated. Netlify has some DDoS protection built-in and is still "in front of" your Heroku app. Up to you.
Deploy those proxy rules and test.
Netlify's proxying (technically reverse proxying) can connect to whatever backend you'd like and does NOT show the URL to the visitor - it looks to them (URL bar in the browser, HTTPS connection) as though they are connected to my-example.com the whole time, but the content is returned from your backend (including HTTP status codes. This response is cached on Netlify's CDN if indicated by your Cache-Control: HTTP Header directives which the Heroku app sends. Note that CloudFlare WILL CHANGE your Cache-Control header in case you set it on content they proxy to! Netlify won't.)
Here's a common setup:
/main/* https://yourapp.herokuapp.com/main/:splat 200!
/app/* https://yourapp.herokuapp.com/main/:splat 200!
Note that if you deploy ANY assets under /main or /app to Netlify, they will be ignored due to the trailing ! on those rules. See https://www.netlify.com/docs/redirects/#note-on-shadowing for some more details about how that works and the alternatives (TL;DR: deploying some things like /main/logo.png on Netlify but nothing that Heroku should serve vs deploying ALL needed content for /main/* on Heroku).
Note that I suggest using identical paths on Netlify and Heroku (/main/*) rather than proxying to /somethingelse/* since it is easier to debug asset loading when paths match up. This isn't a requirement, though.
As mentioned in the comment, its possible using cloudflare enterprise service.
But you can do it with a simple nginx reverse proxy setup.
Have DNS resolve to nginx reverse proxy and based on the path, appropriately call the upstreams.
eg. example.com, and then direct queries for /path1 to 100.100.100.100 and for /path2 to 200.200.200.200

Setting Google domains to use https

I purchased a domain (say, example.com) from Google and my Django application (say, mysite.herokuapp.com) runs on Heroku. The CNAME is set on Google to forward the http requests to the Django applicaiton on Heroku. Forwarding requests from http://mysite.example.com to mysite.herokuapp.com works just fine.
Recently, I need to introduce progressive-web-application to my application and it requires the https protocol, instead of http, that is, the URL now has to be https://mysite.example.com and it doesn't work for Google domains. I tried https://mysite.herokuapp.com and it works fine, which means Heroku already supports https. However, I tried (and also googled) for a long time without finding a solution.
So how do I set the Google domain to use https protocol?
The DNS answer from Google cannot contain the port or protocol (http vs. https), it just contains the hostname.
You need to add a redirect from http to https in the Heroku django app, see e.g. here for more instructions.
It's not Google you need to change, it's your Django configuration.
Set SECURE_SSL_REDIRECT to True, and enable the SecurityMiddleware in your app, and any requests should automatically be redirected from HTTP to HTTPS.
When switching to HTTPS you need to add certs to heroku and that process updates the host from "mysite.heroku.com" to something like "tokyo-2121.herokussl.com". You will need to update your DNS to serve HTTPS pages from the new SSL compliant heroku instance for both HTTP and HTTPS.
Here is a tutorial that outlines the process with Godaddy, it should be very similar or all DNS providers.
http://www.joshwright.com/tips/setup-a-godaddy-ssl-certificate-on-heroku
Just got a solution from one of Heroku's engineers:
1) Upgrade the Heroku app to a paid one (e.g., Hobby)
2) On the DNS provider's settings, set the DNS target to <app_name>.<domain>.herokudns.com (e.g., "mysite.example.com.herokudns.com")
3) Run $ heroku certs:auto:refresh -a <app_name> (e.g., $ heroku certs:auto:refresh -a mysite)
I'm not sure if this is the same problem that you ran into, but when forwarding from https://example.com to my wix subdomain https://learn.example.com, I got a "No resource with given identifier found" error in the browser. Forwarding from http://example.com to https://learn.example.com was working just fine.
I had to open Google Domains' advanced forwarding options for my forwarding rule and enable SSL forwarding, like so:

Can I have multiple heroku subdomains for my app?

Say you have two apps hosted on heroku: appA and appB. They will be accessible at appA.herokuapp.com and appB.herokuapp.com. Is there a way to "share" the subdomains? As in, can I have appA listening on both urls?
I suppose I could have appB forward all its traffic to appA, but I'm more curious if it can be done through some heroku setting.
Thanks!
No, this cannot be done through a heroku setting. You either need one of the two apps acting as a reverse proxy to the other app, or else you need a third server running a dedicated reverse proxy such as nginx.
Heroku support once suggested using a third heroku app as an nginx reverse proxy with a custom buildpack to accomplish this, although I decided not to go that route. It is unfortunate that there is no systematic support for multiple apps on the same domain at Heroku, but that would add significant complexity to their currently predictable and transparent routing platform (which is itself a non-configurable reverse proxy).

Maintenance mode in AWS EC2

In heroku we could use the command heroku maintenance on or off... How can I do it in my AWS EC2 web services? I tried just to stop the server using sudo service nginx stop but I don't like the error page that was displayed. It says error in url. In heroku if i use the maintenance command, the error page will display "Under contruction" "Maintenance" or something like that.
How can I do it in Amazon web services? thanks
You have to do it yourself. AWS does not provide that.
Yeah, so heroku has routing magick, think of the default WebBrick server your rails app is running as running outside of rails. Idk, assuming you use passenger you would'nt really notice this but at a high level, nginx is proxying your apps' port 3000 to port 80 for certain requests. I appologize if you don't know what I mean by that.
So (YOUR APP) ---> (NGINX) -----> (Client)
the advantage here, is that nginx keeps running but during maintience mode they most likely start shooting you pages to static content. If you too run you rails app via a proxy rather than via passenger, than you solution is easy. Stop your WebBrick, mongrel, unicorn, thin (what ever app server here) and setup an error message page for bad gateway errors aka 502 route.
If you use passenger. You could write a location block, that would over ride all your routes to a maintence page and switch Passenger to off in that server block, now rather than serving your app you can serve a static maintence page.
Heroku wraps alot of technology and exposes nice tools, so you'll need to do a bit more ground work to automate your stack. But this is a place to start.

Resources