Skip to content

Apache routing for dynamic WeWeb pages (advanced)

This page is an advanced guide for users who:

  • Are self‑hosting a WeWeb app behind Apache
  • Want page that have dynamic path parameters such as /product/{{product_id}}/details to avoid 404s

What this guide covers

  • How a typical Vue.js / WeWeb build is structured
  • How to write .htaccess rules so Apache serves a specific template file (for example, /product/:param/details/index.html) when a user visits /product/5/details
  • How this can help search engines and social networks access those URLs without 404s

Understanding the build structure

When you export your WeWeb / Vue.js app and run npm run build, your dist folder might look like:

txt
dist/
├── index.html                          # Homepage (root)
├── assets/                             # JavaScript, CSS, fonts
├── data/                               # JSON data files
├── products/
│   └── index.html                      # Products listing page
└── product/
    └── :param/
        └── details/
            └── index.html              # Product details page template

Key idea:

  • :param is a literal folder name produced by the build.
  • /product/:param/details/index.html is a template file used for all product details pages.

You might have many real URLs:

  • /product/1/details
  • /product/5/details
  • /product/99/details

But there is only one template file on disk:

  • /product/:param/details/index.html

The problem without custom routing

When a user directly visits /product/5/details:

  • Apache looks for /product/5/details/index.html
  • That file does not exist
  • Result: 404 Not Found

Even if your Vue app would handle /product/5/details correctly once loaded, the first request never reaches it because Apache returns a 404.

The Apache .htaccess configuration

Place the following in a .htaccess file in your web server’s document root (where your built index.html lives):

apache
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /

  # Don't rewrite direct index.html requests
  RewriteRule ^index\.html$ - [L]

  # Map dynamic product detail URLs to the static :param template
  # Example: /product/5/details -> /product/:param/details/index.html
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^product/([^/]+)/details/?$ /product/:param/details/index.html [L]

  # Map dynamic profile URLs to the static :param template
  # Example: /profile/5 -> /profile/:param/index.html
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^profile/([^/]+)/?$ /profile/:param/index.html [L]

  # Fallback: serve root index.html for any other non-existent paths
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

How it works

  1. Enable rewriting

    apache
    <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteBase /

    Checks that mod_rewrite is enabled and turns on URL rewriting.

  2. Preserve direct index.html requests

    apache
    RewriteRule ^index\.html$ - [L]

    If someone directly requests /index.html, Apache serves it as is.

  3. Handle parameterized URLs for products

    apache
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^product/([^/]+)/details/?$ /product/:param/details/index.html [L]
    • Only runs when there is no physical file (! -f) and no directory (! -d).
    • Matches URLs like /product/5/details or /product/123/details/.
    • Rewrites them to /product/:param/details/index.html, which is the template file from the build.
  4. Handle parameterized URLs for profiles

    apache
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^profile/([^/]+)/?$ /profile/:param/index.html [L]
    • Matches URLs like /profile/5 or /profile/5/.
    • Rewrites them to /profile/:param/index.html.
  5. Fallback rule

    apache
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]

    Any other non‑existing path falls back to /index.html, which lets Vue Router handle normal SPA routes.

Real‑world example

Product detail page with parameter

Request (local testing):
http://localhost:8080/product/5/details

What Apache does:

  1. Checks: Does /product/5/details exist as a file? → No
  2. Checks: Does /product/5/details exist as a directory? → No
  3. Matches rule ^product/([^/]+)/details/?$ → Yes (captures 5)
  4. Serves /product/:param/details/index.html

Example HTML served (simplified):

html
<!DOCTYPE html>
<html>
  <head>
    <title>Detailed page for one product</title>
    <meta name="description" content="Description for product detailed page" />
    <meta property="og:title" content="Detailed page for one product" />
  </head>
  <body>
    <div id="app"></div>
    <script src="/assets/main-Bdry9Nph.js"></script>
  </body>
</html>

The exact <title> and <meta> tags depend on how you configured page metadata inside WeWeb.
Use Dynamic page metadata to control those values.

Static directory page

Request: http://localhost:8080/products

  • Apache sees that /products is a real directory.
  • It serves /products/index.html directly.
  • No rewrite rule is triggered.

Static asset

Request: http://localhost:8080/assets/main.js

  • Apache sees assets/main.js is a real file.
  • It serves the file directly.
  • No rewriting occurs.

Impact on SEO and social sharing

Routing alone does not create SEO‑friendly content. It simply ensures:

  • Search engines and social crawlers reach your dynamic URLs without hitting 404s.
  • The HTML they see on first load comes from the right template file.

Quick setup checklist

  1. Enable mod_rewrite

    Make sure mod_rewrite is loaded in your Apache config, for example:

    bash
    grep "rewrite_module" /etc/apache2/httpd.conf
  2. Allow .htaccess overrides

    In your Apache virtual host configuration, ensure .htaccess is allowed to define rewrite rules:

    apache
    <Directory "/Library/WebServer/Documents">
        AllowOverride All
    </Directory>
  3. Build and deploy

    bash
    npm run build
    ./deploy-app.sh   # or your own deployment script
  4. Restart Apache

    bash
    sudo apachectl restart
  5. Verify one dynamic URL

    bash
    curl http://localhost:8080/product/5/details | grep "<title>"

    You should see the <title> coming from the correct template HTML file.

Troubleshooting

404 errors on parameterized URLs?

  • Check that mod_rewrite is enabled.
  • Verify that .htaccess is in the correct document root.
  • Ensure AllowOverride All (or at least AllowOverride FileInfo) is set for that directory.

Changes not taking effect?

bash
sudo apachectl configtest
sudo apachectl restart