Setting up Apache to Serve Angular and Act as a Reverse Proxy for Kestrel
· Alex Peters
Introduction
Today we'll figure out how to configure Apache to serve your Angular application and act as a reverse proxy server for Kestrel. This guide is intended for Linux (specifically Ubuntu), but with slight adjustments, it's applicable to Windows as well.
Setting up Apache VirtualHost
First, go to /etc/apache2/sites-available and create a new configuration file, say
example.conf.
Now open the file and add a new virtual host:
<VirtualHost *:80>
ServerName example.com
DocumentRoot "/var/www/frontend"
ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>
ServerNameis your domain name;DocumentRootis the folder where your Angular build is located;ErrorLogis where Apache logs errors related to your site;CustomLogis where Apache writes access logs for your site;
Granting Access to Angular Build Directory
Next, we’ll add a directory directive to allow access:
<Directory "/var/www/frontend">
Require all granted
</Directory>
Require all granted allows everyone to access the Angular frontend files publicly. Without
this, Apache
might block access by default.
Configuring the Reverse Proxy to Kestrel
Now, configure Apache to forward API calls to the Kestrel server:
ProxyPreserveHost On
ProxyPass /api/ http://localhost:5000/
ProxyPassReverse /api/ http://localhost:5000/
<Location /api>
Require all granted
</Location>
ProxyPreserveHost Onkeeps the original Host header from the incoming request;ProxyPassforwards requests from/api/to the Kestrel server running on localhost;ProxyPassReverserewrites any redirects coming back from Kestrel to point through Apache;<Location /api>makes the/apiendpoint publicly accessible;
Enabling URL Rewriting
Finally, we configure URL rewriting to handle Angular routing properly:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d [OR]
RewriteCond %{REQUEST_URI} ^/api/
RewriteRule ^ - [L]
RewriteRule ^ /index.html [L]
</IfModule>
RewriteEngine Onturns on the rewrite engine.RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]is a condition that checks if(DOCUMENT_ROOT + REQUEST_URI)points to an actual file on disk. The flag[OR]at the end of the line means this condition is combined with the next one using a logical OR;RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d [OR]is a condition that checks if(DOCUMENT_ROOT + REQUEST_URI)exists as a directory on disk;RewriteCond %{REQUEST_URI} ^/api/is a condition that checks whetherREQUEST_URImatches the regular expression^/api/RewriteRule ^ - [L]is a rule that will be invoked if one of the aforementioned conditions is met. This rule, in particular, does nothing. It performs no rewrite. The flag[L]stands for “last” and indicates that no subsequent rewrite rules will be processed;RewriteRule ^ /index.html [L]is a rule that will be invoked if none of the aforementioned conditions are met. The rule rewrites all routes to serveindex.html(for Angular SPA behavior);
If you find Apache config syntax a little convoluted, here is some pseudocode that makes it easier to understand:
if (File.Exists(Path.Combine(documentRoot, requestUri.TrimStart('/')))
|| Directory.Exists(Path.Combine(documentRoot, requestUri.TrimStart('/')))
|| requestUri.StartsWith("/api/", StringComparison.OrdinalIgnoreCase)) {}
else
{
requestUri = "/index.html";
}
Final Apache Configuration
Your final example.conf should look like this:
<VirtualHost *:80>
ServerName example.com
DocumentRoot "/var/www/frontend"
<Directory "/var/www/frontend">
Require all granted
</Directory>
ProxyPreserveHost On
ProxyPass /api/ http://localhost:5000/
ProxyPassReverse /api/ http://localhost:5000/
<Location /api>
Require all granted
</Location>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d [OR]
RewriteCond %{REQUEST_URI} ^/api/
RewriteRule ^ - [L]
RewriteRule ^ /index.html [L]
</IfModule>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Enabling the Site and Reloading Apache
Once you’re done with the configuration, run:
sudo a2ensite example.conf
sudo systemctl reload apache2
Now Apache will serve your Angular frontend and forward API requests correctly to your backend running on Kestrel.