├── .editorconfig ├── .travis.yml ├── LICENSE.md ├── README.md ├── composer.json ├── h5bp-htaccess.conf ├── ruleset.xml └── wp-h5bp-htaccess.php /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: php 3 | php: 4 | - nightly 5 | - 5.6 6 | - 5.5 7 | - 5.4 8 | - hhvm 9 | 10 | matrix: 11 | allow_failures: 12 | - php: nightly 13 | 14 | install: 15 | - composer self-update && composer --version 16 | - export PATH="$HOME/.composer/vendor/bin:$PATH" 17 | - composer global require squizlabs/php_codesniffer 18 | 19 | script: 20 | - phpcs --standard=ruleset.xml --extensions=php -n -s . 21 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) Roots 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HTML5 Boilerplate's `.htaccess` for WordPress 2 | [![Build Status](https://travis-ci.org/roots/wp-h5bp-htaccess.svg)](https://travis-ci.org/roots/wp-h5bp-htaccess) 3 | 4 | Add [HTML5 Boilerplate's `.htaccess`](https://github.com/h5bp/server-configs-apache) to your WordPress installation. 5 | 6 | ## Installation 7 | 8 | You can install this plugin via the command-line or the WordPress admin panel. 9 | 10 | ### via Command-line 11 | 12 | If you're [using Composer to manage WordPress](https://roots.io/using-composer-with-wordpress/), add wp-h5bp-htaccess to your project's dependencies. 13 | 14 | ```sh 15 | composer require roots/wp-h5bp-htaccess 2.0.1 16 | ``` 17 | 18 | Then activate the plugin via [wp-cli](http://wp-cli.org/commands/plugin/activate/). 19 | 20 | ```sh 21 | wp plugin activate wp-h5bp-htaccess 22 | ``` 23 | 24 | ### via WordPress Admin Panel 25 | 26 | 1. Download the [latest zip](https://github.com/roots/wp-h5bp-htaccess/archive/master.zip) of this repo. 27 | 2. In your WordPress admin panel, navigate to Plugins->Add New 28 | 3. Click Upload Plugin 29 | 4. Upload the zip file that you downloaded. 30 | 31 | ## Configuration 32 | 33 | The plugin will work right out of the box, but we have made some options available to developers who wish to fine-tune the resulting `.htaccess` file. 34 | 35 | ### !!! WARNING !!! 36 | 37 | Using these configuration options can result in unexpected, undesired, and even damaging behaviors. You must understand that changing the output of this plugin will change what WordPress puts into your `.htaccess` file. Misconfigured `.htaccess` files will likely result server errors. Be sure that you have a way of removing the `.htaccess` file if necessary. 38 | 39 | ### Use a custom server config (`server_configs.conf`) 40 | 41 | You can use your own server config instead of the included Apache Server Config by H5BP. Do this by placing a file named `server_configs.conf` in the root of your theme directory. 42 | 43 | ``` 44 | / 45 | ├── wp-admin/ 46 | ├── wp-content/ 47 | │ └── themes/ 48 | │ └── your-theme-here/ 49 | │ └── server_configs.conf 50 | └── wp-includes/ 51 | ``` 52 | 53 | ### Hooks 54 | 55 | There are a few WordPress filters into which a developer can hook to modify the resulting `.htaccess` file. The rules below are listed in the order in which they are applied in the code. 56 | 57 | #### `roots/h5bp-htaccess-filters` 58 | 59 | This hook passes an associative array of modification filters to be applied to the rules where the keys of the array represent a string that is to be searched and the values of the array represent a replacement. 60 | 61 | Use this for simple string replacements, such as commenting out lines. 62 | 63 | ```php 64 | add_filter('roots/h5bp-htaccess-filters', function($rules_filters) { 65 | // comments out all `RewriteRule`s 66 | $rules_filters['RewriteRule'] = '# RewriteRule'; 67 | return $rules_filters; 68 | }); 69 | ``` 70 | 71 | #### `roots/h5bp-htaccess-rules` 72 | 73 | This hook passes a string containing all of the rules that are going to be added to your `.htaccess` file by this plugin. 74 | 75 | ```php 76 | add_filter('roots/h5bp-htaccess-rules', function($server_config_rules) { 77 | // Removes all comments and whitespace 78 | return preg_replace(['/#.*/', '/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/'], ['',PHP_EOL], $server_config_rules); 79 | }); 80 | ``` 81 | 82 | ## Changelog 83 | 84 | ### 2.0.1: April 29th, 2015 85 | * Fix reference error ([#12](https://github.com/roots/wp-h5bp-htaccess/issues/12)) 86 | * Update link to h5bp server config repo ([#13](https://github.com/roots/wp-h5bp-htaccess/issues/13)) 87 | 88 | ### 2.0.0: April 11th, 2015 89 | * Update to Apache Server Configs v2.14.0 90 | * Rewrote plugin as a class 91 | * Rewrote logic so that server and WordPress configurations are only checked when plugin is actively in use 92 | * Added filters to provide users with more control over the rules that are being applied 93 | * Added a dedicated WordPress section to the bottom of h5bp-htaccess 94 | 95 | ### 1.1.0: June 7th, 2014 96 | * Update to Apache Server Configs v2.4.1 97 | 98 | ### 1.0.0: April 30th, 2013 99 | * Removed from [Roots Theme](http://www.rootstheme.com/), moved to plugin 100 | 101 | ## License 102 | 103 | * [Apache Server Configs](https://github.com/h5bp/server-configs-apache): MIT License 104 | * Everything else: MIT License 105 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "roots/wp-h5bp-htaccess", 3 | "type": "wordpress-plugin", 4 | "license": "MIT", 5 | "description": "HTML5 Boilerplate's .htaccess for WordPress", 6 | "homepage": "http://roots.io/plugins/html5-boilerplate-htaccess/", 7 | "authors": [ 8 | { 9 | "name": "Ben Word", 10 | "email": "ben@benword.com", 11 | "homepage": "https://github.com/retlehs" 12 | }, 13 | { 14 | "name": "Scott Walkinshaw", 15 | "email": "scott.walkinshaw@gmail.com", 16 | "homepage": "https://github.com/swalkinshaw" 17 | } 18 | ], 19 | "keywords": [ 20 | "wordpress" 21 | ], 22 | "support": { 23 | "issues": "https://github.com/roots/wp-h5bp-htaccess/issues", 24 | "forum": "https://discourse.roots.io/" 25 | }, 26 | "require": { 27 | "php": ">=5.4.0", 28 | "composer/installers": "^1.4" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /h5bp-htaccess.conf: -------------------------------------------------------------------------------- 1 | # Apache Server Configs v2.14.0 | MIT License 2 | # https://github.com/h5bp/server-configs-apache 3 | 4 | # (!) Using `.htaccess` files slows down Apache, therefore, if you have 5 | # access to the main server configuration file (which is usually called 6 | # `httpd.conf`), you should add this logic there. 7 | # 8 | # https://httpd.apache.org/docs/current/howto/htaccess.html. 9 | 10 | # ###################################################################### 11 | # # CROSS-ORIGIN # 12 | # ###################################################################### 13 | 14 | # ---------------------------------------------------------------------- 15 | # | Cross-origin requests | 16 | # ---------------------------------------------------------------------- 17 | 18 | # Allow cross-origin requests. 19 | # 20 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS 21 | # http://enable-cors.org/ 22 | # http://www.w3.org/TR/cors/ 23 | 24 | # 25 | # Header set Access-Control-Allow-Origin "*" 26 | # 27 | 28 | # ---------------------------------------------------------------------- 29 | # | Cross-origin images | 30 | # ---------------------------------------------------------------------- 31 | 32 | # Send the CORS header for images when browsers request it. 33 | # 34 | # https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image 35 | # https://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html 36 | 37 | 38 | 39 | 40 | SetEnvIf Origin ":" IS_CORS 41 | Header set Access-Control-Allow-Origin "*" env=IS_CORS 42 | 43 | 44 | 45 | 46 | # ---------------------------------------------------------------------- 47 | # | Cross-origin web fonts | 48 | # ---------------------------------------------------------------------- 49 | 50 | # Allow cross-origin access to web fonts. 51 | 52 | 53 | 54 | Header set Access-Control-Allow-Origin "*" 55 | 56 | 57 | 58 | # ---------------------------------------------------------------------- 59 | # | Cross-origin resource timing | 60 | # ---------------------------------------------------------------------- 61 | 62 | # Allow cross-origin access to the timing information for all resources. 63 | # 64 | # If a resource isn't served with a `Timing-Allow-Origin` header that 65 | # would allow its timing information to be shared with the document, 66 | # some of the attributes of the `PerformanceResourceTiming` object will 67 | # be set to zero. 68 | # 69 | # http://www.w3.org/TR/resource-timing/ 70 | # http://www.stevesouders.com/blog/2014/08/21/resource-timing-practical-tips/ 71 | 72 | # 73 | # Header set Timing-Allow-Origin: "*" 74 | # 75 | 76 | 77 | # ###################################################################### 78 | # # ERRORS # 79 | # ###################################################################### 80 | 81 | # ---------------------------------------------------------------------- 82 | # | Custom error messages/pages | 83 | # ---------------------------------------------------------------------- 84 | 85 | # Customize what Apache returns to the client in case of an error. 86 | # https://httpd.apache.org/docs/current/mod/core.html#errordocument 87 | 88 | # ErrorDocument 404 /404.html 89 | 90 | # ---------------------------------------------------------------------- 91 | # | Error prevention | 92 | # ---------------------------------------------------------------------- 93 | 94 | # Disable the pattern matching based on filenames. 95 | # 96 | # This setting prevents Apache from returning a 404 error as the result 97 | # of a rewrite when the directory with the same name does not exist. 98 | # 99 | # https://httpd.apache.org/docs/current/content-negotiation.html#multiviews 100 | 101 | # Options -MultiViews 102 | 103 | 104 | # ###################################################################### 105 | # # INTERNET EXPLORER # 106 | # ###################################################################### 107 | 108 | # ---------------------------------------------------------------------- 109 | # | Document modes | 110 | # ---------------------------------------------------------------------- 111 | 112 | # Force Internet Explorer 8/9/10 to render pages in the highest mode 113 | # available in the various cases when it may not. 114 | # 115 | # https://hsivonen.fi/doctype/#ie8 116 | # 117 | # (!) Starting with Internet Explorer 11, document modes are deprecated. 118 | # If your business still relies on older web apps and services that were 119 | # designed for older versions of Internet Explorer, you might want to 120 | # consider enabling `Enterprise Mode` throughout your company. 121 | # 122 | # https://msdn.microsoft.com/en-us/library/ie/bg182625.aspx#docmode 123 | # http://blogs.msdn.com/b/ie/archive/2014/04/02/stay-up-to-date-with-enterprise-mode-for-internet-explorer-11.aspx 124 | 125 | 126 | 127 | Header set X-UA-Compatible "IE=edge" 128 | 129 | # `mod_headers` cannot match based on the content-type, however, 130 | # the `X-UA-Compatible` response header should be send only for 131 | # HTML documents and not for the other resources. 132 | 133 | 134 | Header unset X-UA-Compatible 135 | 136 | 137 | 138 | 139 | # ---------------------------------------------------------------------- 140 | # | Iframes cookies | 141 | # ---------------------------------------------------------------------- 142 | 143 | # Allow cookies to be set from iframes in Internet Explorer. 144 | # 145 | # https://msdn.microsoft.com/en-us/library/ms537343.aspx 146 | # http://www.w3.org/TR/2000/CR-P3P-20001215/ 147 | 148 | # 149 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" 150 | # 151 | 152 | 153 | # ###################################################################### 154 | # # MEDIA TYPES AND CHARACTER ENCODINGS # 155 | # ###################################################################### 156 | 157 | # ---------------------------------------------------------------------- 158 | # | Media types | 159 | # ---------------------------------------------------------------------- 160 | 161 | # Serve resources with the proper media types (f.k.a. MIME types). 162 | # 163 | # https://www.iana.org/assignments/media-types/media-types.xhtml 164 | # https://httpd.apache.org/docs/current/mod/mod_mime.html#addtype 165 | 166 | 167 | 168 | # Data interchange 169 | 170 | AddType application/atom+xml atom 171 | AddType application/json json map topojson 172 | AddType application/ld+json jsonld 173 | AddType application/rss+xml rss 174 | AddType application/vnd.geo+json geojson 175 | AddType application/xml rdf xml 176 | 177 | 178 | # JavaScript 179 | 180 | # Normalize to standard type. 181 | # https://tools.ietf.org/html/rfc4329#section-7.2 182 | 183 | AddType application/javascript js 184 | 185 | 186 | # Manifest files 187 | 188 | AddType application/manifest+json webmanifest 189 | AddType application/x-web-app-manifest+json webapp 190 | AddType text/cache-manifest appcache 191 | 192 | 193 | # Media files 194 | 195 | AddType audio/mp4 f4a f4b m4a 196 | AddType audio/ogg oga ogg opus 197 | AddType image/bmp bmp 198 | AddType image/svg+xml svg svgz 199 | AddType image/webp webp 200 | AddType video/mp4 f4v f4p m4v mp4 201 | AddType video/ogg ogv 202 | AddType video/webm webm 203 | AddType video/x-flv flv 204 | 205 | # Serving `.ico` image files with a different media type 206 | # prevents Internet Explorer from displaying then as images: 207 | # https://github.com/h5bp/html5-boilerplate/commit/37b5fec090d00f38de64b591bcddcb205aadf8ee 208 | 209 | AddType image/x-icon cur ico 210 | 211 | 212 | # Web fonts 213 | 214 | AddType application/font-woff woff 215 | AddType application/font-woff2 woff2 216 | AddType application/vnd.ms-fontobject eot 217 | 218 | # Browsers usually ignore the font media types and simply sniff 219 | # the bytes to figure out the font type. 220 | # https://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern 221 | # 222 | # However, Blink and WebKit based browsers will show a warning 223 | # in the console if the following font types are served with any 224 | # other media types. 225 | 226 | AddType application/x-font-ttf ttc ttf 227 | AddType font/opentype otf 228 | 229 | 230 | # Other 231 | 232 | AddType application/octet-stream safariextz 233 | AddType application/x-bb-appworld bbaw 234 | AddType application/x-chrome-extension crx 235 | AddType application/x-opera-extension oex 236 | AddType application/x-xpinstall xpi 237 | AddType text/vcard vcard vcf 238 | AddType text/vnd.rim.location.xloc xloc 239 | AddType text/vtt vtt 240 | AddType text/x-component htc 241 | 242 | 243 | 244 | # ---------------------------------------------------------------------- 245 | # | Character encodings | 246 | # ---------------------------------------------------------------------- 247 | 248 | # Serve all resources labeled as `text/html` or `text/plain` 249 | # with the media type `charset` parameter set to `UTF-8`. 250 | # 251 | # https://httpd.apache.org/docs/current/mod/core.html#adddefaultcharset 252 | 253 | AddDefaultCharset utf-8 254 | 255 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 256 | 257 | # Serve the following file types with the media type `charset` 258 | # parameter set to `UTF-8`. 259 | # 260 | # https://httpd.apache.org/docs/current/mod/mod_mime.html#addcharset 261 | 262 | 263 | AddCharset utf-8 .atom \ 264 | .bbaw \ 265 | .css \ 266 | .geojson \ 267 | .js \ 268 | .json \ 269 | .jsonld \ 270 | .manifest \ 271 | .rdf \ 272 | .rss \ 273 | .topojson \ 274 | .vtt \ 275 | .webapp \ 276 | .webmanifest \ 277 | .xloc \ 278 | .xml 279 | 280 | 281 | 282 | # ###################################################################### 283 | # # REWRITES # 284 | # ###################################################################### 285 | 286 | # ---------------------------------------------------------------------- 287 | # | Rewrite engine | 288 | # ---------------------------------------------------------------------- 289 | 290 | # (1) Turn on the rewrite engine (this is necessary in order for 291 | # the `RewriteRule` directives to work). 292 | # 293 | # https://httpd.apache.org/docs/current/mod/mod_rewrite.html#RewriteEngine 294 | # 295 | # (2) Enable the `FollowSymLinks` option if it isn't already. 296 | # 297 | # https://httpd.apache.org/docs/current/mod/core.html#options 298 | # 299 | # (3) If your web host doesn't allow the `FollowSymlinks` option, 300 | # you need to comment it out or remove it, and then uncomment 301 | # the `Options +SymLinksIfOwnerMatch` line (4), but be aware 302 | # of the performance impact. 303 | # 304 | # https://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks 305 | # 306 | # (4) Some cloud hosting services will require you set `RewriteBase`. 307 | # 308 | # https://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-modrewrite-not-working-on-my-site 309 | # https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase 310 | # 311 | # (5) Depending on how your server is set up, you may also need to 312 | # use the `RewriteOptions` directive to enable some options for 313 | # the rewrite engine. 314 | # 315 | # https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriteoptions 316 | # 317 | # (6) Set %{ENV:PROTO} variable, to allow rewrites to redirect with the 318 | # appropriate schema automatically (http or https). 319 | 320 | 321 | 322 | # (1) 323 | RewriteEngine On 324 | 325 | # (2) 326 | Options +FollowSymlinks 327 | 328 | # (3) 329 | # Options +SymLinksIfOwnerMatch 330 | 331 | # (4) 332 | # RewriteBase / 333 | 334 | # (5) 335 | # RewriteOptions 336 | 337 | # (6) 338 | RewriteCond %{HTTPS} =on 339 | RewriteRule ^ - [env=proto:https] 340 | RewriteCond %{HTTPS} !=on 341 | RewriteRule ^ - [env=proto:http] 342 | 343 | 344 | 345 | # ---------------------------------------------------------------------- 346 | # | Forcing `https://` | 347 | # ---------------------------------------------------------------------- 348 | 349 | # Redirect from the `http://` to the `https://` version of the URL. 350 | # https://wiki.apache.org/httpd/RewriteHTTPToHTTPS 351 | 352 | # 353 | # RewriteEngine On 354 | # RewriteCond %{HTTPS} !=on 355 | # RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L] 356 | # 357 | 358 | # ---------------------------------------------------------------------- 359 | # | Suppressing / Forcing the `www.` at the beginning of URLs | 360 | # ---------------------------------------------------------------------- 361 | 362 | # The same content should never be available under two different 363 | # URLs, especially not with and without `www.` at the beginning. 364 | # This can cause SEO problems (duplicate content), and therefore, 365 | # you should choose one of the alternatives and redirect the other 366 | # one. 367 | # 368 | # By default `Option 1` (no `www.`) is activated. 369 | # http://no-www.org/faq.php?q=class_b 370 | # 371 | # If you would prefer to use `Option 2`, just comment out all the 372 | # lines from `Option 1` and uncomment the ones from `Option 2`. 373 | # 374 | # (!) NEVER USE BOTH RULES AT THE SAME TIME! 375 | 376 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 377 | 378 | # Option 1: rewrite www.example.com → example.com 379 | 380 | 381 | RewriteEngine On 382 | RewriteCond %{HTTPS} !=on 383 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 384 | RewriteRule ^ %{ENV:PROTO}://%1%{REQUEST_URI} [R=301,L] 385 | 386 | 387 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 388 | 389 | # Option 2: rewrite example.com → www.example.com 390 | # 391 | # Be aware that the following might not be a good idea if you use "real" 392 | # subdomains for certain parts of your website. 393 | 394 | # 395 | # RewriteEngine On 396 | # RewriteCond %{HTTPS} !=on 397 | # RewriteCond %{HTTP_HOST} !^www\. [NC] 398 | # RewriteCond %{SERVER_ADDR} !=127.0.0.1 399 | # RewriteCond %{SERVER_ADDR} !=::1 400 | # RewriteRule ^ %{ENV:PROTO}://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] 401 | # 402 | 403 | 404 | # ###################################################################### 405 | # # SECURITY # 406 | # ###################################################################### 407 | 408 | # ---------------------------------------------------------------------- 409 | # | Clickjacking | 410 | # ---------------------------------------------------------------------- 411 | 412 | # Protect website against clickjacking. 413 | # 414 | # The example below sends the `X-Frame-Options` response header with 415 | # the value `DENY`, informing browsers not to display the content of 416 | # the web page in any frame. 417 | # 418 | # This might not be the best setting for everyone. You should read 419 | # about the other two possible values the `X-Frame-Options` header 420 | # field can have: `SAMEORIGIN` and `ALLOW-FROM`. 421 | # https://tools.ietf.org/html/rfc7034#section-2.1. 422 | # 423 | # Keep in mind that while you could send the `X-Frame-Options` header 424 | # for all of your website’s pages, this has the potential downside that 425 | # it forbids even non-malicious framing of your content (e.g.: when 426 | # users visit your website using a Google Image Search results page). 427 | # 428 | # Nonetheless, you should ensure that you send the `X-Frame-Options` 429 | # header for all pages that allow a user to make a state changing 430 | # operation (e.g: pages that contain one-click purchase links, checkout 431 | # or bank-transfer confirmation pages, pages that make permanent 432 | # configuration changes, etc.). 433 | # 434 | # Sending the `X-Frame-Options` header can also protect your website 435 | # against more than just clickjacking attacks: 436 | # https://cure53.de/xfo-clickjacking.pdf. 437 | # 438 | # https://tools.ietf.org/html/rfc7034 439 | # http://blogs.msdn.com/b/ieinternals/archive/2010/03/30/combating-clickjacking-with-x-frame-options.aspx 440 | # https://www.owasp.org/index.php/Clickjacking 441 | 442 | # 443 | 444 | # Header set X-Frame-Options "DENY" 445 | 446 | # # `mod_headers` cannot match based on the content-type, however, 447 | # # the `X-Frame-Options` response header should be send only for 448 | # # HTML documents and not for the other resources. 449 | 450 | # 451 | # Header unset X-Frame-Options 452 | # 453 | 454 | # 455 | 456 | # ---------------------------------------------------------------------- 457 | # | Content Security Policy (CSP) | 458 | # ---------------------------------------------------------------------- 459 | 460 | # Mitigate the risk of cross-site scripting and other content-injection 461 | # attacks. 462 | # 463 | # This can be done by setting a `Content Security Policy` which 464 | # whitelists trusted sources of content for your website. 465 | # 466 | # The example header below allows ONLY scripts that are loaded from 467 | # the current website's origin (no inline scripts, no CDN, etc). 468 | # That almost certainly won't work as-is for your website! 469 | # 470 | # To make things easier, you can use an online CSP header generator 471 | # such as: http://cspisawesome.com/. 472 | # 473 | # http://content-security-policy.com/ 474 | # http://www.html5rocks.com/en/tutorials/security/content-security-policy/ 475 | # http://www.w3.org/TR/CSP11/). 476 | 477 | # 478 | 479 | # Header set Content-Security-Policy "script-src 'self'; object-src 'self'" 480 | 481 | # # `mod_headers` cannot match based on the content-type, however, 482 | # # the `Content-Security-Policy` response header should be send 483 | # # only for HTML documents and not for the other resources. 484 | 485 | # 486 | # Header unset Content-Security-Policy 487 | # 488 | 489 | # 490 | 491 | # ---------------------------------------------------------------------- 492 | # | File access | 493 | # ---------------------------------------------------------------------- 494 | 495 | # Block access to directories without a default document. 496 | # 497 | # You should leave the following uncommented, as you shouldn't allow 498 | # anyone to surf through every directory on your server (which may 499 | # includes rather private places such as the CMS's directories). 500 | 501 | 502 | Options -Indexes 503 | 504 | 505 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 506 | 507 | # Block access to all hidden files and directories with the exception of 508 | # the visible content from within the `/.well-known/` hidden directory. 509 | # 510 | # These types of files usually contain user preferences or the preserved 511 | # state of an utility, and can include rather private places like, for 512 | # example, the `.git` or `.svn` directories. 513 | # 514 | # The `/.well-known/` directory represents the standard (RFC 5785) path 515 | # prefix for "well-known locations" (e.g.: `/.well-known/manifest.json`, 516 | # `/.well-known/keybase.txt`), and therefore, access to its visible 517 | # content should not be blocked. 518 | # 519 | # https://www.mnot.net/blog/2010/04/07/well-known 520 | # https://tools.ietf.org/html/rfc5785 521 | 522 | 523 | RewriteEngine On 524 | RewriteCond %{REQUEST_URI} "!(^|/)\.well-known/([^./]+./?)+$" [NC] 525 | RewriteCond %{SCRIPT_FILENAME} -d [OR] 526 | RewriteCond %{SCRIPT_FILENAME} -f 527 | RewriteRule "(^|/)\." - [F] 528 | 529 | 530 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 531 | 532 | # Block access to files that can expose sensitive information. 533 | # 534 | # By default, block access to backup and source files that may be 535 | # left by some text editors and can pose a security risk when anyone 536 | # has access to them. 537 | # 538 | # http://feross.org/cmsploit/ 539 | # 540 | # (!) Update the `` regular expression from below to 541 | # include any files that might end up on your production server and 542 | # can expose sensitive information about your website. These files may 543 | # include: configuration files, files that contain metadata about the 544 | # project (e.g.: project dependencies), build scripts, etc.. 545 | 546 | 547 | 548 | # Apache < 2.3 549 | 550 | Order allow,deny 551 | Deny from all 552 | Satisfy All 553 | 554 | 555 | # Apache ≥ 2.3 556 | 557 | Require all denied 558 | 559 | 560 | 561 | 562 | # ---------------------------------------------------------------------- 563 | # | HTTP Strict Transport Security (HSTS) | 564 | # ---------------------------------------------------------------------- 565 | 566 | # Force client-side SSL redirection. 567 | # 568 | # If a user types `example.com` in their browser, even if the server 569 | # redirects them to the secure version of the website, that still leaves 570 | # a window of opportunity (the initial HTTP connection) for an attacker 571 | # to downgrade or redirect the request. 572 | # 573 | # The following header ensures that browser will ONLY connect to your 574 | # server via HTTPS, regardless of what the users type in the browser's 575 | # address bar. 576 | # 577 | # (!) Remove the `includeSubDomains` optional directive if the website's 578 | # subdomains are not using HTTPS. 579 | # 580 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ 581 | # https://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-6.1 582 | # http://blogs.msdn.com/b/ieinternals/archive/2014/08/18/hsts-strict-transport-security-attacks-mitigations-deployment-https.aspx 583 | 584 | # 585 | # Header always set Strict-Transport-Security "max-age=16070400; includeSubDomains" 586 | # 587 | 588 | # ---------------------------------------------------------------------- 589 | # | Reducing MIME type security risks | 590 | # ---------------------------------------------------------------------- 591 | 592 | # Prevent some browsers from MIME-sniffing the response. 593 | # 594 | # This reduces exposure to drive-by download attacks and cross-origin 595 | # data leaks, and should be left uncommented, especially if the server 596 | # is serving user-uploaded content or content that could potentially be 597 | # treated as executable by the browser. 598 | # 599 | # http://www.slideshare.net/hasegawayosuke/owasp-hasegawa 600 | # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx 601 | # https://msdn.microsoft.com/en-us/library/ie/gg622941.aspx 602 | # https://mimesniff.spec.whatwg.org/ 603 | 604 | 605 | Header set X-Content-Type-Options "nosniff" 606 | 607 | 608 | # ---------------------------------------------------------------------- 609 | # | Reflected Cross-Site Scripting (XSS) attacks | 610 | # ---------------------------------------------------------------------- 611 | 612 | # (1) Try to re-enable the cross-site scripting (XSS) filter built 613 | # into most web browsers. 614 | # 615 | # The filter is usually enabled by default, but in some cases it 616 | # may be disabled by the user. However, in Internet Explorer for 617 | # example, it can be re-enabled just by sending the 618 | # `X-XSS-Protection` header with the value of `1`. 619 | # 620 | # (2) Prevent web browsers from rendering the web page if a potential 621 | # reflected (a.k.a non-persistent) XSS attack is detected by the 622 | # filter. 623 | # 624 | # By default, if the filter is enabled and browsers detect a 625 | # reflected XSS attack, they will attempt to block the attack 626 | # by making the smallest possible modifications to the returned 627 | # web page. 628 | # 629 | # Unfortunately, in some browsers (e.g.: Internet Explorer), 630 | # this default behavior may allow the XSS filter to be exploited, 631 | # thereby, it's better to inform browsers to prevent the rendering 632 | # of the page altogether, instead of attempting to modify it. 633 | # 634 | # https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities 635 | # 636 | # (!) Do not rely on the XSS filter to prevent XSS attacks! Ensure that 637 | # you are taking all possible measures to prevent XSS attacks, the 638 | # most obvious being: validating and sanitizing your website's inputs. 639 | # 640 | # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx 641 | # http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx 642 | # https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29 643 | 644 | # 645 | 646 | # # (1) (2) 647 | # Header set X-XSS-Protection "1; mode=block" 648 | 649 | # # `mod_headers` cannot match based on the content-type, however, 650 | # # the `X-XSS-Protection` response header should be send only for 651 | # # HTML documents and not for the other resources. 652 | 653 | # 654 | # Header unset X-XSS-Protection 655 | # 656 | 657 | # 658 | 659 | # ---------------------------------------------------------------------- 660 | # | Server-side technology information | 661 | # ---------------------------------------------------------------------- 662 | 663 | # Remove the `X-Powered-By` response header that: 664 | # 665 | # * is set by some frameworks and server-side languages 666 | # (e.g.: ASP.NET, PHP), and its value contains information 667 | # about them (e.g.: their name, version number) 668 | # 669 | # * doesn't provide any value as far as users are concern, 670 | # and in some cases, the information provided by it can 671 | # be used by attackers 672 | # 673 | # (!) If you can, you should disable the `X-Powered-By` header from the 674 | # language / framework level (e.g.: for PHP, you can do that by setting 675 | # `expose_php = off` in `php.ini`) 676 | # 677 | # https://php.net/manual/en/ini.core.php#ini.expose-php 678 | 679 | 680 | Header unset X-Powered-By 681 | 682 | 683 | # ---------------------------------------------------------------------- 684 | # | Server software information | 685 | # ---------------------------------------------------------------------- 686 | 687 | # Prevent Apache from adding a trailing footer line containing 688 | # information about the server to the server-generated documents 689 | # (e.g.: error messages, directory listings, etc.) 690 | # 691 | # https://httpd.apache.org/docs/current/mod/core.html#serversignature 692 | 693 | ServerSignature Off 694 | 695 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 696 | 697 | # Prevent Apache from sending in the `Server` response header its 698 | # exact version number, the description of the generic OS-type or 699 | # information about its compiled-in modules. 700 | # 701 | # (!) The `ServerTokens` directive will only work in the main server 702 | # configuration file, so don't try to enable it in the `.htaccess` file! 703 | # 704 | # https://httpd.apache.org/docs/current/mod/core.html#servertokens 705 | 706 | #ServerTokens Prod 707 | 708 | 709 | # ###################################################################### 710 | # # WEB PERFORMANCE # 711 | # ###################################################################### 712 | 713 | # ---------------------------------------------------------------------- 714 | # | Compression | 715 | # ---------------------------------------------------------------------- 716 | 717 | 718 | 719 | # Force compression for mangled `Accept-Encoding` request headers 720 | # https://developer.yahoo.com/blogs/ydn/pushing-beyond-gzipping-25601.html 721 | 722 | 723 | 724 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding 725 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding 726 | 727 | 728 | 729 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 730 | 731 | # Compress all output labeled with one of the following media types. 732 | # 733 | # (!) For Apache versions below version 2.3.7 you don't need to 734 | # enable `mod_filter` and can remove the `` 735 | # and `` lines as `AddOutputFilterByType` is still in 736 | # the core directives. 737 | # 738 | # https://httpd.apache.org/docs/current/mod/mod_filter.html#addoutputfilterbytype 739 | 740 | 741 | AddOutputFilterByType DEFLATE "application/atom+xml" \ 742 | "application/javascript" \ 743 | "application/json" \ 744 | "application/ld+json" \ 745 | "application/manifest+json" \ 746 | "application/rdf+xml" \ 747 | "application/rss+xml" \ 748 | "application/schema+json" \ 749 | "application/vnd.geo+json" \ 750 | "application/vnd.ms-fontobject" \ 751 | "application/x-font-ttf" \ 752 | "application/x-javascript" \ 753 | "application/x-web-app-manifest+json" \ 754 | "application/xhtml+xml" \ 755 | "application/xml" \ 756 | "font/eot" \ 757 | "font/opentype" \ 758 | "image/bmp" \ 759 | "image/svg+xml" \ 760 | "image/vnd.microsoft.icon" \ 761 | "image/x-icon" \ 762 | "text/cache-manifest" \ 763 | "text/css" \ 764 | "text/html" \ 765 | "text/javascript" \ 766 | "text/plain" \ 767 | "text/vcard" \ 768 | "text/vnd.rim.location.xloc" \ 769 | "text/vtt" \ 770 | "text/x-component" \ 771 | "text/x-cross-domain-policy" \ 772 | "text/xml" 773 | 774 | 775 | 776 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 777 | 778 | # Map the following filename extensions to the specified 779 | # encoding type in order to make Apache serve the file types 780 | # with the appropriate `Content-Encoding` response header 781 | # (do note that this will NOT make Apache compress them!). 782 | # 783 | # If these files types would be served without an appropriate 784 | # `Content-Enable` response header, client applications (e.g.: 785 | # browsers) wouldn't know that they first need to uncompress 786 | # the response, and thus, wouldn't be able to understand the 787 | # content. 788 | # 789 | # https://httpd.apache.org/docs/current/mod/mod_mime.html#addencoding 790 | 791 | 792 | AddEncoding gzip svgz 793 | 794 | 795 | 796 | 797 | # ---------------------------------------------------------------------- 798 | # | Content transformation | 799 | # ---------------------------------------------------------------------- 800 | 801 | # Prevent intermediate caches or proxies (e.g.: such as the ones 802 | # used by mobile network providers) from modifying the website's 803 | # content. 804 | # 805 | # https://tools.ietf.org/html/rfc2616#section-14.9.5 806 | # 807 | # (!) If you are using `mod_pagespeed`, please note that setting 808 | # the `Cache-Control: no-transform` response header will prevent 809 | # `PageSpeed` from rewriting `HTML` files, and, if the 810 | # `ModPagespeedDisableRewriteOnNoTransform` directive isn't set 811 | # to `off`, also from rewriting other resources. 812 | # 813 | # https://developers.google.com/speed/pagespeed/module/configuration#notransform 814 | 815 | # 816 | # Header merge Cache-Control "no-transform" 817 | # 818 | 819 | # ---------------------------------------------------------------------- 820 | # | ETags | 821 | # ---------------------------------------------------------------------- 822 | 823 | # Remove `ETags` as resources are sent with far-future expires headers. 824 | # 825 | # https://developer.yahoo.com/performance/rules.html#etags 826 | # https://tools.ietf.org/html/rfc7232#section-2.3 827 | 828 | # `FileETag None` doesn't work in all cases. 829 | 830 | Header unset ETag 831 | 832 | 833 | FileETag None 834 | 835 | # ---------------------------------------------------------------------- 836 | # | Expires headers | 837 | # ---------------------------------------------------------------------- 838 | 839 | # Serve resources with far-future expires headers. 840 | # 841 | # (!) If you don't control versioning with filename-based 842 | # cache busting, you should consider lowering the cache times 843 | # to something like one week. 844 | # 845 | # https://httpd.apache.org/docs/current/mod/mod_expires.html 846 | 847 | 848 | 849 | ExpiresActive on 850 | ExpiresDefault "access plus 1 month" 851 | 852 | # CSS 853 | 854 | ExpiresByType text/css "access plus 1 year" 855 | 856 | 857 | # Data interchange 858 | 859 | ExpiresByType application/atom+xml "access plus 1 hour" 860 | ExpiresByType application/rdf+xml "access plus 1 hour" 861 | ExpiresByType application/rss+xml "access plus 1 hour" 862 | 863 | ExpiresByType application/json "access plus 0 seconds" 864 | ExpiresByType application/ld+json "access plus 0 seconds" 865 | ExpiresByType application/schema+json "access plus 0 seconds" 866 | ExpiresByType application/vnd.geo+json "access plus 0 seconds" 867 | ExpiresByType application/xml "access plus 0 seconds" 868 | ExpiresByType text/xml "access plus 0 seconds" 869 | 870 | 871 | # Favicon (cannot be renamed!) and cursor images 872 | 873 | ExpiresByType image/vnd.microsoft.icon "access plus 1 week" 874 | ExpiresByType image/x-icon "access plus 1 week" 875 | 876 | # HTML 877 | 878 | ExpiresByType text/html "access plus 0 seconds" 879 | 880 | 881 | # JavaScript 882 | 883 | ExpiresByType application/javascript "access plus 1 year" 884 | ExpiresByType application/x-javascript "access plus 1 year" 885 | ExpiresByType text/javascript "access plus 1 year" 886 | 887 | 888 | # Manifest files 889 | 890 | ExpiresByType application/manifest+json "access plus 1 week" 891 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" 892 | ExpiresByType text/cache-manifest "access plus 0 seconds" 893 | 894 | 895 | # Media files 896 | 897 | ExpiresByType audio/ogg "access plus 1 month" 898 | ExpiresByType image/bmp "access plus 1 month" 899 | ExpiresByType image/gif "access plus 1 month" 900 | ExpiresByType image/jpeg "access plus 1 month" 901 | ExpiresByType image/png "access plus 1 month" 902 | ExpiresByType image/svg+xml "access plus 1 month" 903 | ExpiresByType image/webp "access plus 1 month" 904 | ExpiresByType video/mp4 "access plus 1 month" 905 | ExpiresByType video/ogg "access plus 1 month" 906 | ExpiresByType video/webm "access plus 1 month" 907 | 908 | 909 | # Web fonts 910 | 911 | # Embedded OpenType (EOT) 912 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month" 913 | ExpiresByType font/eot "access plus 1 month" 914 | 915 | # OpenType 916 | ExpiresByType font/opentype "access plus 1 month" 917 | 918 | # TrueType 919 | ExpiresByType application/x-font-ttf "access plus 1 month" 920 | 921 | # Web Open Font Format (WOFF) 1.0 922 | ExpiresByType application/font-woff "access plus 1 month" 923 | ExpiresByType application/x-font-woff "access plus 1 month" 924 | ExpiresByType font/woff "access plus 1 month" 925 | 926 | # Web Open Font Format (WOFF) 2.0 927 | ExpiresByType application/font-woff2 "access plus 1 month" 928 | 929 | 930 | # Other 931 | 932 | ExpiresByType text/x-cross-domain-policy "access plus 1 week" 933 | 934 | 935 | 936 | # ---------------------------------------------------------------------- 937 | # | File concatenation | 938 | # ---------------------------------------------------------------------- 939 | 940 | # Allow concatenation from within specific files. 941 | # 942 | # e.g.: 943 | # 944 | # If you have the following lines in a file called, for 945 | # example, `main.combined.js`: 946 | # 947 | # 948 | # 949 | # 950 | # Apache will replace those lines with the content of the 951 | # specified files. 952 | 953 | # 954 | # 955 | # Options +Includes 956 | # AddOutputFilterByType INCLUDES application/javascript \ 957 | # application/x-javascript \ 958 | # text/javascript 959 | # SetOutputFilter INCLUDES 960 | # 961 | # 962 | # Options +Includes 963 | # AddOutputFilterByType INCLUDES text/css 964 | # SetOutputFilter INCLUDES 965 | # 966 | # 967 | 968 | # ---------------------------------------------------------------------- 969 | # | Filename-based cache busting | 970 | # ---------------------------------------------------------------------- 971 | 972 | # If you're not using a build process to manage your filename version 973 | # revving, you might want to consider enabling the following directives 974 | # to route all requests such as `/style.12345.css` to `/style.css`. 975 | # 976 | # To understand why this is important and even a better solution than 977 | # using something like `*.css?v231`, please see: 978 | # http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/ 979 | 980 | # 981 | # RewriteEngine On 982 | # RewriteCond %{REQUEST_FILENAME} !-f 983 | # RewriteRule ^(.+)\.(\d+)\.(bmp|css|cur|gif|ico|jpe?g|js|png|svgz?|webp|webmanifest)$ $1.$3 [L] 984 | # 985 | 986 | 987 | # ###################################################################### 988 | # # WORDPRESS # 989 | # ###################################################################### 990 | 991 | # ---------------------------------------------------------------------- 992 | # | Redirect all requests to home_url() | 993 | # ---------------------------------------------------------------------- 994 | 995 | # http://moz.com/blog/301-redirect-or-relcanonical-which-one-should-you-use 996 | 997 | # 998 | # RewriteCond %{HTTP_HOST} !^www\.example\.com$ 999 | # RewriteRule ^ %{ENV:PROTO}://www.example.com%{REQUEST_URI} [R=301,L] 1000 | # 1001 | # RewriteCond %{THE_REQUEST} index(\.php)? 1002 | # RewriteRule ^index(\.php)?$ %{ENV:PROTO}://www.example.com/ [R=301,L] 1003 | # 1004 | 1005 | # ---------------------------------------------------------------------- 1006 | # | Block potentially unwanted or undesired requests | 1007 | # ---------------------------------------------------------------------- 1008 | 1009 | # Many of these were taken from iThemes Security 1010 | # https://github.com/wp-plugins/better-wp-security/blob/master/modules/free/tweaks/class-itsec-tweaks-admin.php 1011 | 1012 | # 1013 | 1014 | # # Block HTTP request methods that are unused by browsers 1015 | # RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD) [NC] 1016 | # RewriteRule ^(.*)$ - [F] 1017 | # 1018 | # # Block suspicious queries 1019 | # RewriteCond %{QUERY_STRING} \.\.\/ [NC,OR] 1020 | # RewriteCond %{QUERY_STRING} ^.*\.(bash|git|hg|log|svn|swp|cvs) [NC,OR] 1021 | # RewriteCond %{QUERY_STRING} etc/passwd [NC,OR] 1022 | # RewriteCond %{QUERY_STRING} boot\.ini [NC,OR] 1023 | # RewriteCond %{QUERY_STRING} ftp\: [NC,OR] 1024 | # RewriteCond %{QUERY_STRING} http\: [NC,OR] 1025 | # RewriteCond %{QUERY_STRING} https\: [NC,OR] 1026 | # RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR] 1027 | # RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|%3D) [NC,OR] 1028 | # RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [NC,OR] 1029 | # RewriteCond %{QUERY_STRING} ^.*(%24&x).* [NC,OR] 1030 | # RewriteCond %{QUERY_STRING} ^.*(127\.0).* [NC,OR] 1031 | # RewriteCond %{QUERY_STRING} ^.*(globals|encode|localhost|loopback).* [NC,OR] 1032 | # RewriteCond %{QUERY_STRING} ^.*(request|concat|insert|union|declare).* [NC] 1033 | # RewriteCond %{QUERY_STRING} !^loggedout=true 1034 | # RewriteCond %{QUERY_STRING} !^action=jetpack-sso 1035 | # RewriteCond %{QUERY_STRING} !^action=rp 1036 | # RewriteCond %{HTTP_COOKIE} !^.*wordpress_logged_in_.*$ 1037 | # RewriteCond %{HTTP_REFERER} !^http://maps\.googleapis\.com(.*)$ 1038 | # RewriteRule ^(.*)$ - [F] 1039 | 1040 | # # Block foreign characters in queries 1041 | # RewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F).* [NC] 1042 | # RewriteRule ^(.*)$ - [F] 1043 | 1044 | # 1045 | 1046 | # ---------------------------------------------------------------------- 1047 | # | Block outside access to WordPress includes files | 1048 | # ---------------------------------------------------------------------- 1049 | 1050 | 1051 | RewriteRule ^wp-admin/includes/ - [F,L] 1052 | RewriteRule !^wp-includes/ - [S=3] 1053 | 1054 | RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L] 1055 | RewriteRule ^wp-includes/theme-compat/ - [F,L] 1056 | 1057 | RewriteCond %{SCRIPT_FILENAME} !^(.*)wp-includes/ms-files.php 1058 | RewriteRule ^wp-includes/[^/]+\.php$ - [F,L] 1059 | 1060 | 1061 | # ---------------------------------------------------------------------- 1062 | # | Block sensitive WordPress files | 1063 | # ---------------------------------------------------------------------- 1064 | 1065 | 1066 | 1067 | # Apache < 2.3 1068 | 1069 | Order allow,deny 1070 | Deny from all 1071 | Satisfy All 1072 | 1073 | 1074 | # Apache ≥ 2.3 1075 | 1076 | Require all denied 1077 | 1078 | 1079 | -------------------------------------------------------------------------------- /ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Roots Coding Standards 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /wp-h5bp-htaccess.php: -------------------------------------------------------------------------------- 1 | HTML5 Boilerplate's .htaccess 7 | Version 2.0.0 8 | Author: Roots 9 | Author URI: http://roots.io/plugins/html5-boilerplate-htaccess/ 10 | License: MIT License 11 | License URI: http://opensource.org/licenses/MIT 12 | */ 13 | 14 | add_action('generate_rewrite_rules', __NAMESPACE__ . '\\ApacheServerConfig::init', -9999, 0); 15 | 16 | class ApacheServerConfig { 17 | const MARKER = 'Roots Server Config'; 18 | const TEXT_DOMAIN = 'roots'; 19 | 20 | private static $instance; 21 | 22 | public static $rules_filters = []; 23 | 24 | protected static $mod_rewrite_enabled; 25 | protected static $home_path; 26 | protected static $wp_htaccess_file; 27 | protected static $roots_htaccess_file; 28 | 29 | protected $errors = []; 30 | 31 | public static function init() { 32 | if (!self::$instance) { 33 | self::$instance = new static(); 34 | } 35 | return self::$instance; 36 | } 37 | 38 | protected function __construct() { 39 | require_once ABSPATH . '/wp-admin/includes/file.php'; 40 | require_once ABSPATH . '/wp-admin/includes/misc.php'; 41 | 42 | self::$mod_rewrite_enabled = got_mod_rewrite(); 43 | self::$home_path = get_home_path(); 44 | self::$wp_htaccess_file = self::$home_path . '.htaccess'; 45 | self::$roots_htaccess_file = locate_template(['server_configs.conf', 'h5bp-htaccess.conf']); 46 | if (!self::$roots_htaccess_file) { 47 | self::$roots_htaccess_file = __DIR__ . '/h5bp-htaccess.conf'; 48 | } 49 | 50 | if (!$this->verifySetup()) { 51 | $this->alerts(); 52 | } else { 53 | self::setRulesFilters(); 54 | $this->write(); 55 | } 56 | } 57 | 58 | public static function setRulesFilters() { 59 | $home_url = parse_url(is_multisite() ? network_home_url('/') : home_url('/')); 60 | extract($home_url); 61 | self::$rules_filters = [ 62 | 'www\\.example\\.com' => preg_quote($host), 63 | 'www.example.com/' => $host . $path, 64 | 'www.example.com' => $host, 65 | '/wordpress' => parse_url(site_url(), PHP_URL_PATH) 66 | ]; 67 | self::$rules_filters = apply_filters('roots/h5bp-htaccess-filters', self::$rules_filters); 68 | } 69 | 70 | protected function verifySetup() { 71 | if (!get_option('permalink_structure')) { 72 | $this->errors[] = sprintf(__('Please enable %s.', self::TEXT_DOMAIN), 'Permalinks'); 73 | } 74 | 75 | if (!$this->isWritable()) { 76 | $this->errors[] = sprintf(__('Please make sure your %s file is writable.', self::TEXT_DOMAIN), '.htaccess'); 77 | } 78 | 79 | if (!self::$mod_rewrite_enabled) { 80 | $this->errors[] = sprintf(__('Please enable %s.', self::TEXT_DOMAIN), 'Apache mod_rewrite'); 81 | } 82 | 83 | if (!file_exists(self::$roots_htaccess_file)) { 84 | $this->errors[] = sprintf(__('Cannot find the file %s.', self::TEXT_DOMAIN), self::$roots_htaccess_file); 85 | } 86 | 87 | return empty($this->errors); 88 | } 89 | 90 | protected function isWritable() { 91 | return is_writable(self::$home_path) || (file_exists(self::$wp_htaccess_file) && is_writable(self::$wp_htaccess_file)); 92 | } 93 | 94 | protected function write() { 95 | $server_config_rules = extract_from_markers(self::$wp_htaccess_file, self::MARKER); 96 | if (empty($server_config_rules)) { 97 | $server_config_rules = implode('', file(self::$roots_htaccess_file)); 98 | $server_config_rules = str_replace(array_keys(self::$rules_filters), array_values(self::$rules_filters), $server_config_rules); 99 | $server_config_rules = apply_filters('roots/h5bp-htaccess-rules', $server_config_rules); 100 | insert_with_markers(self::$wp_htaccess_file, self::MARKER, explode(PHP_EOL, $server_config_rules)); 101 | } 102 | } 103 | 104 | public function alerts() { 105 | $alert = function ($message) { 106 | echo '

' . $message . '

'; 107 | }; 108 | if (current_user_can('activate_plugins')) { 109 | add_action('admin_notices', function () use ($alert) { 110 | array_map($alert, $this->errors); 111 | }); 112 | } 113 | } 114 | } 115 | --------------------------------------------------------------------------------