Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #28739: Fix static asset caching when using Puma #788

Merged
merged 1 commit into from
Feb 19, 2020

Conversation

ehelms
Copy link
Member

@ehelms ehelms commented Jan 9, 2020

No description provided.

SetEnv no-gzip
</FilesMatch>
</IfModule>
<LocationMatch "(assets|webpack)">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this works because I don't see expire headers. Compare:

$ curl -I https://foreman.example.com/webpack/bundle-c61d31ff17f4bee60391.css
HTTP/1.1 200 OK
Date: Thu, 09 Jan 2020 12:25:13 GMT
Server: Apache
Last-Modified: Tue, 10 Dec 2019 18:31:56 GMT
Content-Type: text/css
Vary: Accept-Encoding
Strict-Transport-Security: max-age=631139040; includeSubdomains
X-Frame-Options: sameorigin
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Content-Security-Policy: default-src 'self'; child-src 'self'; connect-src 'self' ws: wss:; img-src 'self' data: *.gravatar.com; script-src 'unsafe-eval' 'unsafe-inline' 'self'; style-src 'unsafe-inline' 'self'
Content-Length: 35810
Via: 1.1 foreman.example.com
Cache-Control: max-age=31536000
Expires: Fri, 08 Jan 2021 12:25:13 GMT

When I add ProxyPass /webpack !:

$  curl -I https://foreman.example.com/webpack/bundle-c61d31ff17f4bee60391.css
HTTP/1.1 200 OK
Date: Thu, 09 Jan 2020 12:24:52 GMT
Server: Apache
Last-Modified: Tue, 10 Dec 2019 18:31:56 GMT
Accept-Ranges: bytes
Content-Length: 35810
Vary: Accept-Encoding
Cache-Control: max-age=31536000
Expires: Fri, 08 Jan 2021 12:24:52 GMT
Content-Type: text/css

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit confused here, both of your examples show Expires and Cache-Control headers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So your change is an improvement, but you still hit the application server. The hint is that the security headers are added in the Rails code. IMHO we want to reduce the load on the actual application server if we can.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passenger does the same thing today as far as I can tell. Apache then caches after the first time it's fetched. In the Passenger case, Passenger is the application server.

Why do I think it works this way? If you don't proxy requests to /assets or /webpack and try to let Apache serve them statically, all plugins will fail to load their serve assets because their assets don't exist in /usr/share/foreman/public. In order to adopt Apache serving it statically we will need to change our installations to identify and put plugin public folders as symlinks to the main /usr/share/foreman/public directory.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I learned something new today. I guess that's why we have this PassengerEnabled off for pulp.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you would want this model as well if you ever wanted to deploy multiple application servers exposed directly with a load balancer separately. We generally don't have a ton of UI users hammering our application so requesting once and then having that cached from there on out I think should be fine. Most of our app load comes from the API.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So on a Foreman with passenger installation (1.23.1):

$ curl -Ik https://foreman.example.com/assets/Redhat-ba7bc908b35f4073bc0565a27f635b706b71288581b26a94c8a3a390ee68c98e.png
HTTP/1.1 200 OK
Date: Fri, 10 Jan 2020 15:20:22 GMT
Server: Apache
Last-Modified: Mon, 04 Nov 2019 14:43:11 GMT
Accept-Ranges: bytes
Content-Length: 1914
Cache-Control: max-age=31536000
Expires: Sat, 09 Jan 2021 15:20:22 GMT
Content-Type: image/png

So this doesn't appear to hit Passenger and just straight up serve the file via Apache.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is only true for Foreman assets and not plugins, this is what I get when using passenger:

[root@centos7-katello-nightly vagrant]# curl -I https://192.168.121.244/assets/bastion_katello/bastion_katello-2f98ac7d4342ebfb94ad6f0dd73f2ea270b67d5c62bfd6825c7ae9838eba24bc.css -k
HTTP/1.1 200 OK
Date: Mon, 13 Jan 2020 13:08:46 GMT
Server: Apache
Vary: Accept-Encoding
Cache-Control: no-cache
X-Request-Id: 774494ee-a89e-40b0-9a9d-512db7321f07
X-Runtime: 0.000449
Strict-Transport-Security: max-age=631139040; includeSubdomains
X-Frame-Options: sameorigin
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Content-Security-Policy: default-src 'self'; child-src 'self'; connect-src 'self' ws: wss:; img-src 'self' data:; script-src 'unsafe-eval' 'unsafe-inline' 'self'; style-src 'unsafe-inline' 'self'
X-Powered-By: Phusion Passenger 4.0.53
Last-Modified: Mon, 30 Dec 2019 12:36:06 GMT
Content-Length: 1598
Status: 200 OK
Cache-Control: max-age=31536000
Expires: Tue, 12 Jan 2021 13:08:46 GMT
Content-Type: text/css

For me, this implies that with this change we are still caching after the initial request of an asset, and this is only changing for core Foreman assets as plugins are already treated this way. That is, plugin assets are not served statically from Apache and this levels the playing field.

From testing, I saw no change in page load times especially after the first request given all of the cache headers are being set.

If we want all assets to be served statically from Apache we need to make a bigger change overall that affects both deployment models. Given, if we support serving static assets from Apache with Puma we break plugins.

To support serving static assets with Apache, we'd have to for all plugins likely add to their RPM and Deb builds a symlink from /usr/share/foreman/public/assets to their install directory's public asset and webpack folders.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears you might be correct. With webpack we do symlink but this isn't the case with the Rails assets pipeline. What kind of rabbit hole did we just uncover.

With all of the above in mind, I think that we should merge this now. It's still a slight regression for Foreman and webpack resources compared to the Passenger setup, but by correctly adding headers it's at least mitigated on subsequent page loads.

SetEnv no-gzip
</FilesMatch>
</IfModule>
<LocationMatch "(assets|webpack)">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears you might be correct. With webpack we do symlink but this isn't the case with the Rails assets pipeline. What kind of rabbit hole did we just uncover.

With all of the above in mind, I think that we should merge this now. It's still a slight regression for Foreman and webpack resources compared to the Passenger setup, but by correctly adding headers it's at least mitigated on subsequent page loads.

@ekohl
Copy link
Member

ekohl commented Jan 13, 2020

Before I hit the green merge button, can we make a Redmine issue for this as well?

@ehelms
Copy link
Member Author

ehelms commented Jan 13, 2020

Will do, I think the indenting is also a bit off so I will fix that

@ehelms ehelms changed the title Fix static asset caching when using Puma Fixes #28739: Fix static asset caching when using Puma Jan 13, 2020
Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After our discussion I think that your new implementation should actually work for passenger as well. My only concern is that you have a LocationMatch which matches anything in the path. That means that it can also apply to a resource which has the name assets in it (/hosts/assets01.example.com). It should take $suburi into account and match the beginning of the path (^) to avoid this.

After that, I think there's no need to make a distinction between Passenger and non-Passenger.

@ehelms ehelms force-pushed the puma-cache branch 3 times, most recently from 4102762 to d9aca51 Compare February 11, 2020 14:31
</FilesMatch>
</IfModule>

<LocationMatch "^/(assets|webpack)">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to include start of line

@ehelms
Copy link
Member Author

ehelms commented Feb 11, 2020

This now handles the assets one way for both Passenger and Puma

Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now a static file. Should we change it in apache.pp to call file('foreman/_assets.conf') and move it to files?

@ehelms
Copy link
Member Author

ehelms commented Feb 12, 2020

Moved to files

@ekohl ekohl added the Bug label Feb 12, 2020
@ekohl
Copy link
Member

ekohl commented Feb 12, 2020

Looks like the unit tests expect the old <Directory> statement, other than that I think this can be merged.

@ehelms ehelms force-pushed the puma-cache branch 2 times, most recently from f7b705c to 8144202 Compare February 17, 2020 13:21
@ehelms
Copy link
Member Author

ehelms commented Feb 19, 2020

The same Debian failure as is on master. Merging.

@ehelms ehelms merged commit 6a02be6 into theforeman:master Feb 19, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants