Skip to content

Instantly share code, notes, and snippets.

@julianpoemp
Last active August 8, 2024 09:32
Show Gist options
  • Save julianpoemp/bcf277cb56d2420cc53ec630a04a3566 to your computer and use it in GitHub Desktop.
Save julianpoemp/bcf277cb56d2420cc53ec630a04a3566 to your computer and use it in GitHub Desktop.
Optimal .htaccess configuration for Angular 15, Angular 14, Angular 13, Angular 12, Angular 11, Angular 10, Angular 9, Angular 8, Angular 7, Angular 6, Angular 5 (and older) app in production incl. fix for the angular browser caching issue.

New generator

I created a new htaccess generator for angular apps that makes it easier for you to create the optimal htaccess file: https://julianpoemp.github.io/ngx-htaccess-generator/

The goal of this generator is to create the optimal .htaccess file for Angular apps easily. By default the generator creates an .htaccess file that solves the route redirection issue. To make it easier for you I created a kind of interview mode with some questions. As an additional feature the generator supports adding exclusions for example if you have installed a blog in a subdirectory of your web application and more!

The generator 😁: https://julianpoemp.github.io/ngx-htaccess-generator/

The project: https://github.com/julianpoemp/ngx-htaccess-generator

Place for issues and bug reports: https://github.com/julianpoemp/ngx-htaccess-generator/issues

Questions and discussion

If you have questions you can comment below. Please report bugs here.

@ajilijihad
Copy link

me be i know problem :/
my backed and fronted is in the same serveur so if redirection all page to index my backend well be not worked
so can you give me code rederiction to all page but not redirection to page Includes words "api"

@julianpoemp
Copy link
Author

@djbev

As far I can understand your "api" folder is next to your index.html of your Angular app? (so "inside" your app folder)

The generator has an option called "Do you want to exclude subdirectories?". Toggle this to "yes". Type in "api" into the textbox and click on the plus icon. This line is going to be added to the .htaccess code:

  # Excluded directories:
  RewriteRule ^api/?(.*) %{REQUEST_URI} [L,R=301]

This should solve your problem because requests to http://.../api are not going to be redirected to the index.html.

@realshoaib
Copy link

Hi everyone and @julianpoemp. I need help regarding implementing the .htaccess file in my angular project which doesn't have the backend integration yet at all. That is why i can't make http headers to send the 'Cache-Control' header as i want it to. Like currently I'm working on the lighthouse optimization of the project where I need to cache the cacheable resources like images stylesheets and scripts in order to reduce round trip to the server again & again. Currently I'm getting 70+ resources that needs to be cached but I can't cache each single one seperately, so I decided to go with .htaccess way so that simply defining in one place and getting effect everywhere. The problem is, despite placing .htaccess file in root directory, I'm unable to see the desired effect i.e. cache control header is vanished.
Kindly help, Thanks in advance.

@julianpoemp
Copy link
Author

@realshoaib what does your .htaccess look like?

Do you know the .htaccess template from HTML Boilerplate? There is a section for caching. You can find it here:
https://github.com/h5bp/server-configs-apache/blob/a5893aa05178bf395099f8df1e7ef1a97eb5a924/dist/.htaccess#L1090

If you want to apply caching to specific files or folders, you can wrap it with <FilesMatch ...> the similar way I do in order to prevent Browser caching:

# Disable browser caching for all files that don't get a hash string by Angular.
<FilesMatch "^(?!.*\.([0-9a-z]{20})\.).*$">
  <IfModule mod_headers.c>
    FileETag None
    Header unset ETag
    Header unset Pragma
    Header unset Cache-Control
    Header unset Last-Modified
    Header set Pragma "no-cache"
    Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    Header set Expires "Mon, 1 Jan 1900 00:00:00 GMT"
  </IfModule>

</FilesMatch>

In my case I prevent ressources from caching in order to force retrieving ressources from the server on every page reload. In your case you coud combine the caching by mime type with the FilesMatch tag, in order to cache ressource from a specific URI.

@realshoaib
Copy link

@julianpoemp as i mentioned earlier in my post that my project doesn't possess any backend which is why i can't implement it onto the backend.

I'm trying to accomplish .htaccess implementation in Angular(on frontend) only.
Below is my .htaccess code:

## EXPIRES CACHING ##
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType application/javascript "access 1 month"
ExpiresByType application/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 2 days"
</IfModule>
## EXPIRES CACHING ##

Kindly guide in this regard.

@julianpoemp
Copy link
Author

julianpoemp commented Nov 10, 2021

@realshoaib I think that your webserver Apache configuration does not allow the mod_expires.c in .htaccess files. Are you sure that you can't use the Cache-Controll header at all? Perhaps you can try the approach described here: https://serverfault.com/a/316330

@realshoaib
Copy link

@julianpoemp brother, you're not getting my point at all. I've said I DON'T HAVE ANY WEBSERVER AT ALL. Did you got my point? I need to deal with .htaccess on the frontend side

@julianpoemp
Copy link
Author

@realshoaib you can't use .htaccess without any webserver. Your problem can't be solved without a webserver at all.

@realshoaib
Copy link

@julianpoemp Thank you so much for guiding me in regard. I'll definitely be going with the webserver approach.

@UnoRing
Copy link

UnoRing commented Jan 7, 2022

Great job, thanks a lot for sharing!

@benzdouglas
Copy link

Hey Julian, thanks for creating this! It helped me to figure out how to set up an Angular install with a Lumen rest api in a subfolder. I do have one issue that maybe you can help with, and might be a good addition to the generator? I've tried to turn off the Indexes throughout my server but for some reason it still wants to display the index of the api folder. Lumen has it's endpoint in a sub-sub folder /api/public so instead of just ignoring the folder I am rewriting to that directory using:
RewriteRule ^api/(.*)$ /api/public/$1 [L]
And above everything I also added
Options -Indexes
(which I've also added in the apache2.conf file and the sites-available conf file, and for those I also have the +FollowSymLinks after Options).
It shows the index when I go to domain.com/api/ but not when I leave off the trailing / as in domain.com/api so I feel like this is just a small typo - or I'm just going about doing this in the complete wrong way! Any advice?

@julianpoemp
Copy link
Author

hi @benzdouglas, did you also try RewriteRule ^api/?(.*)$ /api/public/$1 [L] ?

@benzdouglas
Copy link

You're a genius! That looks to have worked, thanks! Would have taken me a long time to find that missing character

@MincDev
Copy link

MincDev commented Apr 21, 2022

This is awesome. Can you also make it do redirection to www? I had to add this manually, but would save me time if you had this as part of your generator :)

@julianpoemp
Copy link
Author

@MincDev nice idea! I'll add it asap 🙂

@julianpoemp
Copy link
Author

@MincDev I added an option for redirection to www :)

@MincDev
Copy link

MincDev commented Aug 8, 2022

@MincDev I added an option for redirection to www :)

Great stuff! Thanks @julianpoemp!

@Ronaldy-Alves
Copy link

Thanks!

@thmarx
Copy link

thmarx commented Dec 13, 2022

Hi, I want to run my Angular 8 app over Apache Tomcat server. But every time I reload then it returns 404 page not found. So, for that, I included the .htaccess file in the folder where my index.html is. But still, it doesn't work because maybe the mod_rewrite is not enabled. My request url is https://ip:port/sso/callback. On tomcat ../webapps/sso, where sso is the app folder which contains all the build files including index.html and .htaccess files. I have set base-href as /sso/ . Please help

tomcat doesn't know htaccess files and doesn't know angular routes. you have to define an error page for 404.

404
index.html

that should work. i used it for an vue app setup.

@ajilijihad
Copy link

As far I can understand your "api" folder is next to your index.html of your Angular app? (so "inside" your app folder)

The generator has an option called "Do you want to exclude subdirectories?". Toggle this to "yes". Type in "api" into the textbox and click on the plus icon. This line is going to be added to the .htaccess code:

thank you so much

@GreenFlag31
Copy link

Thank you, it has been useful ! No documentation to create an .htaccess on Hostinger.

@alexandrudabija
Copy link

alexandrudabija commented Apr 27, 2023

@julianpoemp ,
Hello, without the .htaccess file my site works,
https://examples.md/
.When I add configurations to it, it no longer works

![OnSettings]

![offSettings]

@julianpoemp
Copy link
Author

julianpoemp commented Apr 27, 2023

@alexandrudabija Hello, I think setting headers under mod_rewrite doesn't work, you need to set header related code under mod_headers.c. For example:

# Generated with ngx-htaccess-generator v1.2.4
# Check for updates: https://julianpoemp.github.io/ngx-htaccess-generator/

<IfModule mod_headers.c>
  # Set allow Access-Control-Allow-Origin header
  Header set Access-Control-Allow-Origin "*"
</IfModule>

<IfModule mod_rewrite.c>
  RewriteEngine On
  
  # Redirection of requests to index.html
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
  RewriteRule ^.*$ - [NC,L]
  # Redirect all non-file routes to index.html
  RewriteRule ^(?!.*\.).*$ index.html [NC,L]
</IfModule>

Your problem is for sure related to Origin headers. And make sure each command is a one-liner (no line breaks).

One side-note: I'd recommend you to not post screenshots and domain names of real projects. If you have to post information make sure to censor it before posting :)

@alexandrudabija
Copy link

alexandrudabija commented Apr 28, 2023

@julianpoemp , Thank you, my problem was in the build, when I did ng build --configuration --base-href "https://example.md/"
it was giving me an error in the .haccess configuration, I did it as follows:
ng build --base-href /

and I haven't had any problems with the course.
my setup:
**
RewriteEngine On

RewriteRule ^(?!..).$ index.html [NC,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP_HOST} ^example.md$ [OR]
RewriteCond %{HTTP_HOST} ^www.example.md$
RewriteRule ^/?$ "https://www.example.md/" [R=301,L]

**

and it worked, thanks for the advice!

@vitaly-t
Copy link

vitaly-t commented Apr 28, 2023

My battle with the /api redirects, which now includes a proper solution. It was only later on that I found this generator project.

@AbirTarchoun1
Copy link

hello , i use hash URL on my angular app ( sever .net ) , but when i add new data , update new data ! but I m obliged to reload the page to see it , i tried different way to refresh but no one work for me ? can any one have a solution for this , thank you .

@NavneetVaid
Copy link

Is NGINX supported ?

@julianpoemp
Copy link
Author

@NavneetVaid nginx is not supported. If you are facing the reloading issue, use HashLocationStrategy: https://v17.angular.io/api/common/HashLocationStrategy

@NavneetVaid
Copy link

I dont want to use hashLocationStrategy, i want to have my url working without a #

@julianpoemp
Copy link
Author

@NavneetVaid you need to change your nginx config:
https://stackoverflow.com/a/47929996/6303600

If you only have access to your app's index.html you can try option 2 from this stackoverflow post:
https://stackoverflow.com/a/53993744/6303600

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