Skip to content

Static File Serving

Navigator can serve static files directly from the filesystem, bypassing Rails for better performance. This includes assets, images, documents, and any other static content.

Basic Configuration

server:
  listen: 3000
  static:
    public_dir: "./public"
    allowed_extensions: [css, js, png, jpg, gif, ico]
    try_files: [index.html, .html, .htm]
    cache_control:
      overrides:
        - path: /assets/
          max_age: 24h

Public Directory

Navigator serves static files from a configured public directory:

server:
  static:
    public_dir: "./public"  # Directory containing static files

All static files are served from this single directory. Navigator maps URL paths directly to files within this directory.

Public Directory Configuration

Field Type Default Description
public_dir string "./public" Directory path for static files

Examples: - URL /assets/app.css → File public/assets/app.css - URL /images/logo.png → File public/images/logo.png - URL /favicon.ico → File public/favicon.ico

File Extensions

Optionally restrict which file extensions Navigator will serve:

server:
  static:
    allowed_extensions: [
      # Web assets
      css, js, map,

      # Images
      png, jpg, jpeg, gif, ico, svg, webp,

      # Fonts
      woff, woff2, ttf, eot, otf,

      # Documents
      pdf, txt, xml, json,

      # Audio/Video
      mp3, mp4, webm, ogg
    ]

When allowed_extensions is specified, only files with these extensions will be served. If omitted, all file types are allowed.

Try Files Behavior

Enable nginx-style try_files for better static site support:

server:
  static:
    try_files: [".html", "index.html", ".htm"]

How Try Files Works

When try_files is configured, Navigator attempts to find files with different extensions:

  1. Request comes in: /about
  2. Navigator tries in order:
  3. /about (exact file)
  4. /about.html
  5. /about/index.html
  6. /about.htm
  7. If no file found, falls back to the Rails application

Try Files Configuration

Field Type Default Description
try_files array [] File suffixes to try (empty = disabled)

Examples: - try_files: [".html"] - Try .html extension - try_files: ["index.html", ".html"] - Try index.html first, then .html - try_files: [] - Disabled (exact path match only)

Cache Control

Set appropriate cache headers for different paths:

server:
  static:
    cache_control:
      overrides:
        # Long cache for fingerprinted assets
        - path: /assets/
          max_age: 8760h  # 1 year (365 days)

        # Medium cache for images
        - path: /images/
          max_age: 24h    # 1 day

        # Short cache for dynamic content
        - path: /docs/
          max_age: 5m     # 5 minutes

        # No cache for development
        - path: /dev/
          max_age: 0s     # Always revalidate

Cache Duration Guidelines

Content Type Duration Format Use Case
Immutable assets 1 year 8760h Fingerprinted files
Semi-static 1 week 168h Images, fonts
Dynamic 1 hour 1h Generated content
Real-time 5 minutes 5m API docs
Development No cache 0s Local development

MIME Types

Navigator automatically detects MIME types based on file extensions:

Extension MIME Type Description
.html, .htm text/html HTML documents
.css text/css Stylesheets
.js application/javascript JavaScript
.json application/json JSON data
.xml application/xml XML documents
.png image/png PNG images
.jpg, .jpeg image/jpeg JPEG images
.gif image/gif GIF images
.svg image/svg+xml SVG images
.ico image/x-icon Icons
.pdf application/pdf PDF documents
.woff font/woff Web fonts
.woff2 font/woff2 Web fonts v2

Performance Optimization

1. Serve Assets Directly

# Instead of letting Rails serve assets
server:
  static:
    public_dir: "./public"
    allowed_extensions: [css, js, png, jpg, gif]
    cache_control:
      overrides:
        - path: /assets/
          max_age: 8760h  # 1 year

applications:
  global_env:
    RAILS_SERVE_STATIC_FILES: "false"  # Let Navigator handle it

2. Optimize Directory Structure

# Good: Organized by type
public/
├── assets/          # Compiled assets
├── images/          # Static images
├── fonts/           # Web fonts
└── docs/            # Documentation

# Avoid: Mixed content
public/
├── style.css        # Mixed with HTML
├── app.js
├── logo.png
└── about.html

3. Use Compression

# Pre-compress static files
gzip -k -9 public/assets/*.css
gzip -k -9 public/assets/*.js
brotli -k -9 public/assets/*.css
brotli -k -9 public/assets/*.js

Navigator will serve pre-compressed files when available.

Common Patterns

Rails Application with Assets

server:
  listen: 3000
  static:
    public_dir: "./public"
    allowed_extensions: [css, js, png, jpg, gif, ico, woff, woff2]
    try_files: ["index.html", ".html"]
    cache_control:
      overrides:
        - path: /assets/
          max_age: 8760h  # 1 year
        - path: /packs/
          max_age: 8760h  # 1 year

applications:
  global_env:
    RAILS_SERVE_STATIC_FILES: "false"

Static Site with Rails API

server:
  static:
    public_dir: "./public/dist"
    try_files: ["index.html", "/index.html"]
    cache_control:
      overrides:
        - path: /
          max_age: 1h
        - path: /assets/
          max_age: 8760h  # 1 year

applications:
  tenants:
    # API only handles /api/ paths
    - name: api
      path: /api/

Multi-Tenant with Shared Assets

server:
  static:
    public_dir: "./public"
    cache_control:
      overrides:
        # Shared assets for all tenants
        - path: /shared/
          max_age: 24h

        # Tenant-specific assets
        - path: /tenant1/assets/
          max_age: 1h

        - path: /tenant2/assets/
          max_age: 1h

Development vs Production

server:
  static:
    public_dir: "./public"
    allowed_extensions: [css, js, png, jpg]
    cache_control:
      overrides:
        - path: /assets/
          max_age: 0s  # No cache for development
server:
  static:
    public_dir: "./public"
    allowed_extensions: [css, js, map, png, jpg, gif, ico, svg, woff, woff2, ttf, eot]
    cache_control:
      overrides:
        - path: /assets/
          max_age: 8760h  # 1 year
        - path: /packs/
          max_age: 8760h  # 1 year

Security Considerations

1. Prevent Directory Traversal

Navigator automatically prevents .. path traversal attacks, but ensure your directory structure is secure:

# Safe
server:
  static:
    public_dir: public/  # Contained directory

# Potentially unsafe
server:
  static:
    public_dir: /  # Root filesystem access (avoid!)

2. Serve Only Intended Files

# Use specific extensions
server:
  static:
    allowed_extensions: [css, js, png, jpg]  # Only these types

# Or omit to allow all files (use with caution)
server:
  static:
    # allowed_extensions not specified = all files allowed

3. Exclude Sensitive Directories

# Safe - only serve from public directory
server:
  static:
    public_dir: public/  # Only files in public/ are accessible

# Ensure sensitive files are outside public_dir:
# - config/ (contains secrets)
# - log/ (contains sensitive data)
# - db/ (database files)

Troubleshooting

Files Not Being Served

  1. Check file exists:

    ls -la public/assets/application.css
    

  2. Verify public directory:

    server:
      static:
        public_dir: public/  # Must contain the file
    

  3. Test directly:

    curl -I http://localhost:3000/assets/application.css
    # Look for "X-Served-By: Navigator" header
    

Wrong MIME Type

Navigator uses file extensions for MIME type detection. Ensure files have correct extensions:

# Correct
app.js         application/javascript
style.css      text/css
image.png      image/png

# Problematic  
app.js.txt     text/plain (wrong!)

Cache Issues

  1. Check cache headers:

    curl -I http://localhost:3000/assets/app.css
    # Look for Cache-Control header
    

  2. Force refresh:

    curl -H "Cache-Control: no-cache" http://localhost:3000/assets/app.css
    

  3. Clear browser cache or use incognito mode

Permission Errors

# Ensure Navigator can read files
chmod 644 public/assets/*
chmod 755 public/assets/

# Check ownership
ls -la public/assets/

Monitoring

Check Static File Serving

# Monitor static file requests
grep "static" /var/log/navigator.log

# Count static vs dynamic requests
grep -c "static" /var/log/navigator.log
grep -c "proxy" /var/log/navigator.log

Performance Testing

# Test static file performance
ab -n 1000 -c 10 http://localhost:3000/assets/application.css

# Compare with Rails serving
ab -n 1000 -c 10 http://localhost:3000/non-static-path

Migration from nginx

Migrate nginx static file configurations:

# nginx
location /assets/ {
    root /var/www/app/public;
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location ~* \.(css|js|png|jpg)$ {
    root /var/www/app/public;
    expires 1w;
}

Becomes:

# Navigator
server:
  static:
    public_dir: /var/www/app/public
    allowed_extensions: [css, js, png, jpg]
    cache_control:
      overrides:
        - path: /assets/
          max_age: 8760h  # 1 year

See Also