Deploying Router Apps

You celebrate having a working prototype by deploying QuizBuzz to your web server. You add an Apache virtual host configuration and visit the main page at https://quizbuzz.example.com. It works as you'd expect.

Then you try sending this direct URL to the state capitals quiz to a friend: https://quizbuzz.example.com/quiz/state-capitals. The friend reports that this URL leads to a 404 error.

The issue is that Apache receives the URL and tries to find a file in the site's directory named state-capitals. There isn't one; the path is purely virtual. What you want is for the main index page to load, and then for the React Router to load the appropriate component.

Apache's URL-rewriting facility is made for solving problems like this. You open your Apache virtual host configuration and add the rewrite rules listed below. The first rule lets paths that match real files really retrieve those files. You need this rule to make images, favicons, and external stylesheets work. The second rule passes any other path on to the index, where it will be examined by the router.

<VirtualHost *:443>
ServerName quizbuzz.example.com
ServerAdmin webmaster@localhost
DocumentRoot /home/your-username/quizbuzz

<Directory /home/your-username/quizbuzz>
Require all granted

RewriteEngine on

# Let requests whose paths point to real files through.
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

# Direct every other path to the main page.
RewriteRule ^ index.html [L]
</Directory>

# error log and certificate directives...
</VirtualHost>

The rewrite engine may need to enabled in the terminal with this command:

sudo a2enmod rewrite

The utility has an obscure name. a2 stands for Apache 2, en stands for enable, and mod stands for module.

The rewrite rules only kick in when the user tries to navigate to a particular page within your app from the outside. External navigation happens when the user clicks on a link in an email or on some other website. Any internal navigation, such as clicks on Link or NavLink components or programmatic edits to the history, will not trigger an outbound request to Apache. They will be handled internally by the app, usually causing a re-render. That's why starting at the main index page worked for you, but the link you sent to your friend didn't.