Skip to content

Conversation

Yukaii
Copy link
Member

@Yukaii Yukaii commented Sep 18, 2025

Problem

When configuring CMD_URL_PATH to serve CodiMD under a subdirectory path (e.g., CMD_URL_PATH=codimd), static assets like CSS, JavaScript files, favicons, and other resources return 404 errors, making the application unusable.

Example Issue

With the following Docker configuration:

environment:
    - CMD_URL_PATH=codimd
    - CMD_DOMAIN=localhost
    - CMD_URL_ADDPORT=true

URLs like these would return 404:

  • http://localhost:3000/codimd/build/font.68d91a5a4c1afd7f82a9.css → 404
  • http://localhost:3000/codimd/build/cover.65bca5da2232a62861ce.css → 404
  • All other static assets → 404

Root Cause

  1. Static assets mounted at root level: Express static middleware was mounted at / instead of respecting the urlPath configuration
  2. Application routes mounted at root level: Main application routes ignored the urlPath prefix
  3. Redirect loop issue: The trailing slash redirect middleware created infinite loops between /codimd and /codimd/
  4. Socket.IO path mismatch: WebSocket connections weren't configured for the URL path

Solution

1. Fixed Static Asset and Route Mounting (app.js)

Added conditional mounting based on config.urlPath:

// Handle URL path configuration
if (config.urlPath) {
    // Redirect from root to URL path
    app.get('/', function (req, res) {
        res.redirect(301, `/${config.urlPath}/`)
    })

    // Mount static files and routes under URL path
    const urlPathPrefix = `/${config.urlPath}`
    app.use(urlPathPrefix + '/', express.static(...))
    app.use(urlPathPrefix + '/docs', express.static(...))
    app.use(urlPathPrefix + '/uploads', express.static(...))
    app.use(urlPathPrefix, require('./lib/routes').router)
} else {
    // Standard mounting when no URL path is configured
    // ...
}

2. Fixed Redirect Loop (lib/middleware/redirectWithoutTrailingSlashes.js)

Updated the middleware to avoid redirect loops by allowing the URL path itself to pass through:

// Don't redirect if this is the URL path itself (e.g., /codimd/)
if (config.urlPath && req.path === `/${config.urlPath}/`) {
    next()
    return
}

3. Socket.IO Configuration

Updated Socket.IO to use the correct path when URL path is configured:

var io = require('socket.io')(server, config.urlPath ? {
    path: `/${config.urlPath}/socket.io`
} : {})

Testing

Local Configuration Used

{
    "domain": "",
    "urlAddPort": false,
    "urlPath": "codimd"
}

Results

  • ✅ Static assets now load correctly at /codimd/build/...
  • ✅ Application accessible at /codimd/
  • ✅ API endpoints work at /codimd/api/...
  • ✅ WebSocket connections work correctly
  • ✅ No more redirect loops

Reverse Proxy Compatibility

The fix also works correctly with reverse proxies. Here's a working Caddy configuration:

# Caddyfile for CodiMD with URL path configuration
{
    # Disable automatic HTTPS for local testing
    auto_https off
}

:8080 {
    # Handle the subdirectory path - DON'T strip prefix since CodiMD expects full path
    handle /codimd* {
        reverse_proxy localhost:3000
    }

    # Redirect root to subdirectory
    redir / /codimd/ 301

    # Enable logging for debugging
    log {
        output stdout
        level INFO
    }
}

Key Points for Reverse Proxy Setup:

  1. Don't strip the URL path prefix - CodiMD expects to receive the full path including /codimd
  2. Pass through the complete path to the backend
  3. Optional root redirect for better UX

Breaking Changes

None. This is a backward-compatible fix that only affects behavior when CMD_URL_PATH is configured.

Files Modified

  • app.js - Added URL path-aware mounting logic
  • lib/middleware/redirectWithoutTrailingSlashes.js - Fixed redirect loop

Fixes issue with 404 errors when using CMD_URL_PATH configuration for serving CodiMD under subdirectory paths.

@Yukaii Yukaii linked an issue Sep 18, 2025 that may be closed by this pull request
@Yukaii Yukaii force-pushed the bugfix/1936-404-errors-when-using-cmd_url_path-in-new-260 branch from a89a785 to c19b948 Compare September 18, 2025 05:39
@Yukaii Yukaii added this to the 2.6.1 milestone Sep 18, 2025
- Added support for a configurable URL path in the application, allowing static files and routes to be served under a specified path.
- Implemented redirection from the root to the configured URL path.
- Updated socket.io initialization to respect the URL path configuration.
- Enhanced middleware to prevent redirection for the URL path itself.

This change improves flexibility in routing and enhances the application's structure.

Signed-off-by: Yukai Huang <yukaihuangtw@gmail.com>
@Yukaii Yukaii force-pushed the bugfix/1936-404-errors-when-using-cmd_url_path-in-new-260 branch from c19b948 to 4e24b74 Compare September 30, 2025 07:46
@Yukaii Yukaii added enhancement Wants to improvide an existing feature bug Something isn't working labels Sep 30, 2025
@Yukaii
Copy link
Member Author

Yukaii commented Sep 30, 2025

Code Simplification Applied ✨

I've simplified the implementation by eliminating code duplication:

Before (duplicated if/else blocks):

  • ❌ 33 lines with duplicated static asset mounting
  • ❌ Separate code paths for with/without URL path
  • ❌ Harder to maintain

After (unified approach):

  • ✅ 18 lines total (saved ~15 lines)
  • ✅ Single code path using empty string prefix
  • ✅ Cleaner and more maintainable

Key Insight

When urlPath is not configured, we use an empty string prefix (''), so:

  • '' + '/' = '/' → same as mounting at root
  • '' + '/docs' = '/docs' → same as before

This works for both cases without duplication!

Analysis document: I also created URL_PATH_ANALYSIS.md analyzing whether any logic could be offloaded to reverse proxy configuration. Conclusion: Current approach is optimal - reverse proxy path stripping would break templates, OAuth, Socket.IO, and standalone deployments.

@Yukaii Yukaii removed this from the 2.6.1 milestone Sep 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement Wants to improvide an existing feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

404 errors when using CMD_URL_PATH in new 2.6.0
1 participant