Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Make your Website faster - a safe htaccess way
#
# Sources:
# http://stackoverflow.com/questions/7704624/how-can-i-use-gzip-compression-for-css-and-js-files-on-my-websites
# http://codex.wordpress.org/Output_Compression
# http://www.perun.net/2009/06/06/wordpress-websites-beschleuinigen-4-ein-zwischenergebnis/#comment-61086
# http://www.smashingmagazine.com/smashing-book-1/performance-optimization-for-websites-part-2-of-2/
# http://gtmetrix.com/configure-entity-tags-etags.html
# http://de.slideshare.net/walterebert/die-htaccessrichtignutzenwchh2014
# http://de.slideshare.net/walterebert/mehr-performance-fr-wordpress
#
<IfModule mod_deflate.c>
# Insert filters / compress text, html, javascript, css, xml:
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/vtt
AddOutputFilterByType DEFLATE text/x-component
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/js
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/x-httpd-php
AddOutputFilterByType DEFLATE application/x-httpd-fastphp
AddOutputFilterByType DEFLATE application/atom+xml
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/ld+json
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-web-app-manifest+json
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
# Exception: Images
SetEnvIfNoCase REQUEST_URI \.(?:gif|jpg|jpeg|png)$ no-gzip dont-vary
# Drop problematic browsers
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
# Make sure proxies don't deliver the wrong content
<IfModule mod_headers.c>
Header append Vary User-Agent env=!dont-vary
</IfModule>
</IfModule>
## EXPIRES CACHING ##
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 week"
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
ExpiresByType text/html "access plus 1 minute"
ExpiresByType text/plain "access plus 1 month"
ExpiresByType text/x-component "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType text/x-javascript "access plus 1 month"
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType application/javascript "access plus 1 months"
ExpiresByType application/x-javascript "access plus 1 months"
ExpiresByType application/x-shockwave-flash "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 year"
ExpiresByType application/json "access plus 0 seconds"
ExpiresByType application/ld+json "access plus 0 seconds"
ExpiresByType application/xml "access plus 0 seconds"
ExpiresByType text/xml "access plus 0 seconds"
ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds"
ExpiresByType text/cache-manifest "access plus 0 seconds"
ExpiresByType audio/ogg "access plus 1 month"
ExpiresByType video/mp4 "access plus 1 month"
ExpiresByType video/ogg "access plus 1 month"
ExpiresByType video/webm "access plus 1 month"
ExpiresByType application/atom+xml "access plus 1 hour"
ExpiresByType application/rss+xml "access plus 1 hour"
ExpiresByType application/font-woff "access plus 1 month"
ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
ExpiresByType application/x-font-ttf "access plus 1 month"
ExpiresByType font/opentype "access plus 1 month"
</IfModule>
## EXPIRES CACHING ##
#Alternative caching using Apache's "mod_headers", if it's installed.
#Caching of common files - ENABLED
<IfModule mod_headers.c>
<FilesMatch "\.(ico|pdf|flv|swf|js|css|gif|png|jpg|jpeg|txt|html|htm)$">
Header set Cache-Control "max-age=2592000, public"
</FilesMatch>
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(js|css|xml|gz)$">
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>
# Set Keep Alive Header
# This *just* sets the header - maybe your hoster is not allowing this feature
# Please check if it is working with tools like http://www.webpagetest.org
<IfModule mod_headers.c>
Header set Connection keep-alive
</IfModule>
# If your server don't support ETags deactivate with "None" (and remove header)
<IfModule mod_expires.c>
<IfModule mod_headers.c>
Header unset ETag
</IfModule>
FileETag None
</IfModule>

filchos commented Sep 20, 2015

Theres a mismatch between dont_vary and dont-vary. Glitch or intended?

Owner

Zodiac1978 commented Sep 28, 2015

After checking the docs it seems to be typo @filchos:
http://httpd.apache.org/docs/2.0/mod/mod_deflate.html#recommended
Is fixed now. Thanks for the hint and sorry for the trouble!

nmaxcom commented Oct 30, 2015

Line 95: ico appears twice

When:

ExpiresByType application/pdf "access plus 1 month"
ExpiresByType application/javascript "access plus 1 months"

I assume plural / no plural makes no difference?

If there were more comments it would be more educational. For example # Ausnahme: Grafiken I don't know what that is.

But thank you for the work, it's useful.

RomanMUG commented Dec 5, 2015

@nmaxcom:

Both are correct.
I found this comment at httpd.apache.org:

Yes both are correct, as 'mo' would also have been.
In fact anything starting with:
y --> years
mo --> months
w --> weeks
d --> days
h --> hours
mi --> minutes
s --> second

Source: https://httpd.apache.org/docs/2.2/mod/mod_expires.html

# Ausnahme: Grafiken is german and means: # Exception: Graphics

grantdb commented Dec 13, 2015

Line 71 and 74 are the same,

I am thinking of excluding application/font-woff2 from gzip but haven't run into any problems yet.

Thanks!

Owner

Zodiac1978 commented Jan 26, 2016

@nmaxcom and @grantdb - Thanks for the heads up. Fixed now.

Owner

Zodiac1978 commented Jan 26, 2016

@RomanMUG Thanks for the link and the clarification! :)

Owner

Zodiac1978 commented Jan 27, 2016

@grantdb: It is not necessary to gzip woff as it is already compressed: https://en.wikipedia.org/wiki/Web_Open_Font_Format#Specification

Thanks @Zodiac1978 👍

Clear code. Thanks a lot..

marfert commented Apr 26, 2016

@Zodiac1978 Would it be safe to not exclude SVG from being compressed? I tried that and I got rid of Google PageSpeed Insights message that some of my included SVGs are not compressed.

Owner

Zodiac1978 commented Jun 7, 2016

@marfert Yes, SVG can be compressed. I will remove SVG from the exception list too. Thanks for the heads up!

Cool. Gave me 2 % better performance! :-)

fengler-it commented Sep 29, 2016

Hi. Very nice code.
I use it and still pingdom tells me

Leverage browser caching
The following cacheable resources have a short freshness lifetime. Specify an expiration at least one week in the future for the following resources:

https://assets.pinterest.com/js/pinit.js
https://assets.pinterest.com/js/pinit_main.js?0.9677980106789619
https://connect.facebook.net/en_US/all.js
https://apis.google.com/js/plusone.js
https://platform.twitter.com/widgets.js
https://fonts.googleapis.com/css?family=Oswald%3A400%2C700%2C300&ver=4.6.1

<<<<

Why?


Update: Found out myself.
Had to add following line:

AddOutputFilterByType DEFLATE text/javascript
<<<

Works on two sites, but one site gives me an "Internel Server Error 500", when adding following line:

Header append Vary User-Agent env=!dont-vary
<<<

PageSpeed Insights Errors:

/fonts/RobotoBold/RobotoBold.woff (expiration not specified)
/fonts/RobotoRegular/RobotoRegular.woff (expiration not specified)
/js/common.js (expiration not specified)
/js/libs.min.js (expiration not specified)

How it fix?

Owner

Zodiac1978 commented Feb 10, 2017

@fengler-it These assets are all from an external server, so your change shouldn't have any impact.

@fengler-it I missed to add a check to this line. Is fixed now. Thanks for the heads up!

@Vvvetal-90 Woff is already compressed, no need to do it again, see: https://gist.github.com/Zodiac1978/3145830#gistcomment-1681099
About js files: Have you tried AddOutputFilterByType DEFLATE text/javascript?

ginocremer commented Jul 13, 2017

Hey Thorsten, my Javascripts weren't correctly cached, I think you should update your gist with the following (after that everything has been cached perfectly):

AddOutputFilterByType DEFLATE text/javascript

Edit: Sorry, just read your post above. Isn't it a good idea to update the gist anyway?

Owner

Zodiac1978 commented Jul 19, 2017

@ginocremer I've added the line. Thanks for the reminder!

bestfitbybrazil commented Oct 15, 2017

Hi Zodiac1978. I just stepped into this and have been having trouble with fluctuating CPU performance jumping anywhere from 30% to beyond 77% in an instance. Not a whole lot of traffic when this is happening. This is my complete .htaccess file now.

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

<IfModule mod_expires.c>
# Enable expirations
ExpiresActive On 
# Default directive
ExpiresDefault "access plus 1 month"
# My favicon
ExpiresByType image/x-icon "access plus 1 year"
# Images
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
# CSS
ExpiresByType text/css "access plus 1 month"
# Javascript
ExpiresByType application/javascript "access plus 1 year"
</IfModule>
# END WordPress

i added the ifmodule mod_expires portion. can you give me complete i can use so as to cover everything else. Still getting low performance from test on gtMetrics. Here's message i get now.

There are 12 static components without a far-future expiration date.

https://fonts.googleapis.com/css?family=Poppins%3A300%2C400%2C500%2C600%2C700%7CLibre+Baskerville%3A400italic&subset=latin%2Clatin-ext&ver=4.8.2
https://bestfitbybrazil.com/wp-content/plugins/wp-spamshield/js/jscripts.php
https://www.livehelpnow.net/lhn/widgets/chatbutton/lhnchatbutton-current.min.js
https://apis.google.com/js/platform.js?onload=renderBadge
https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit2
https://www.google-analytics.com/analytics.js
https://translate.googleapis.com/translate_static/css/translateelement.css
https://translate.googleapis.com/translate_static/js/element/main.js
https://loader.wisepops.com/get-loader.js?v=1&user_id=2166
https://popup.wisepops.com/my-wisepop?uid=2166
https://translate.googleapis.com/translate_a/l?client=te&alpha=true&hl=en&cb=_callbacks____0j8stitkp
https://www.livehelpnow.net/lhn/scripts/livehelpnow.min.aspx?lhnid=19096&iv=0&ivid=0&d=0&ver=5.3&rnd=0.8954146259070273

The second "High priority" fix needed is:
Make fewer HTTP requests | F (0) | CONTENT | HIGH
-- | -- | -- | --
What's this mean?This page has 82 external Javascript scripts. Try combining them into one.This page has 39 external stylesheets. Try combining them into one.

APlusDesign commented Nov 14, 2017

Why not combine some of the rules, for example.

#Alternative caching using Apache's "mod_headers", if it's installed.
#Caching of common files - ENABLED
<IfModule mod_headers.c>
	<FilesMatch "\.(ico|pdf|flv|swf|js|css|gif|png|jpg|jpeg|txt|html|htm)$">
		Header set Cache-Control "max-age=2592000, public"
	</FilesMatch>
	<FilesMatch "\.(js|css|xml|gz)$">
    	Header append Vary Accept-Encoding
  	</FilesMatch>
  	# Set Keep Alive Header
	# This *just* sets the header - maybe your hoster is not allowing this feature
	# Please check if it is working with tools like http://www.webpagetest.org
	Header set Connection keep-alive
</IfModule>
Owner

Zodiac1978 commented Nov 15, 2017

@bestfitbybrazil 11 of 12 of these files are not on your server, but on 3rd-party-sites, so you cannot cache them with a server setting on your server. ;) The second one is on your server, but is dynamically generated (PHP file generating JS I assume). Not meant to be cached.

82 JS files + 39 CSS files are really a huge amount of files. You should definitely try to get rid of them. Caching is good, but doesn't solve the issue of having too much files loaded.

If you have reduced this to a smaller amount of files you can try to combine them with a tool like Autoptimize.

Owner

Zodiac1978 commented Nov 15, 2017

@APlusDesign Nice idea, but I prefer the longer, more readable version. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment