gotson / komga

Media server for comics/mangas/BDs/magazines/eBooks with API, OPDS and Kobo Sync support
https://komga.org
MIT License
4.01k stars 236 forks source link

Cannot Open Any Books [No mapping for GET /book/XXXXXXXXXX/read-epub] #1716

Closed franciscomfcmaia closed 2 weeks ago

franciscomfcmaia commented 3 weeks ago

Steps to reproduce

When attempting to open any book in Komga, the screen remains blank [with a simple warning sign in the middle], and the Chrome web traffic logs show a 404 error when trying to load the next or previous book.

image
  1. Deploy Komga using Docker with the following configuration:
    • Version: 1.14.0
    • Media stored on an NFS server.
    • Configuration specified via Helm chart (see below).
    • Using Traefik as reverse proxy.
    • No path modification, servers hosted on https://read.${SECRET_DOMAIN}
  2. Open the Komga UI and attempt to open any book in the library.
  3. Check Chrome web traffic logs when the book fails to load.

Expected behavior

The book should display correctly without any 404 errors, and navigating to the next or previous book should function properly.

Actual behavior

Error response from the logs:

{
    "timestamp": "2024-09-29T11:53:25.418+00:00",
    "status": 404,
    "error": "Not Found",
    "message": "404 NOT_FOUND",
    "path": "/api/v1/books/0HDYCWF45AHWN/next"
}

Logs

 ____  __.
|    |/ _|____   _____    _________
|      < /  _ \ /     \  / ___\__  \
|    |  (  <_> )  Y Y  \/ /_/  > __ \_
|____|__ \____/|__|_|  /\___  (____  /
        \/           \//_____/     \/

Version: 1.14.0

2024-09-29T13:05:44.902+01:00  INFO 1 --- [           main] org.gotson.komga.ApplicationKt           : Starting ApplicationKt v1.14.0 using Java 21.0.4 with PID 1 (/app/BOOT-INF/classes started by ? in /app)
2024-09-29T13:05:44.907+01:00 DEBUG 1 --- [           main] org.gotson.komga.ApplicationKt           : Running with Spring Boot v3.2.2, Spring v6.1.3
2024-09-29T13:05:44.908+01:00  INFO 1 --- [           main] org.gotson.komga.ApplicationKt           : The following 1 profile is active: "docker"
[DELETED]
2024-09-29T13:05:52.750+01:00  INFO 1 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Will secure Or [Mvc [pattern='/api/**'], Mvc [pattern='/opds/**'], Mvc [pattern='/sse/**'], Mvc [pattern='/oauth2/authorization/**'], Mvc [pattern='/login/oauth2/code/**'], EndpointRequestMatcher includes=[*], excludes=[], includeLinks=true] with [org.springframework.security.web.session.DisableEncodeUrlFilter@27b89e0a, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@42bb0492, org.springframework.security.web.context.SecurityContextHolderFilter@1100363d, org.springframework.security.web.header.HeaderWriterFilter@786125a6, org.springframework.web.filter.CorsFilter@6eed5b68, org.springframework.security.web.authentication.logout.LogoutFilter@20fdf45a, org.springframework.security.web.session.ConcurrentSessionFilter@656c356c, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@6b8773c7, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@788be73c, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@65018381, org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter@3d70dab8, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@4377b35b, org.springframework.security.web.session.SessionManagementFilter@642ebd4c, org.springframework.security.web.access.ExceptionTranslationFilter@46700301, org.springframework.security.web.access.intercept.AuthorizationFilter@7c6f91d2]
2024-09-29T13:05:52.772+01:00  INFO 1 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Will secure Or [Mvc [pattern='/kobo/**']] with [org.springframework.security.web.session.DisableEncodeUrlFilter@3796ca50, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@55154761, org.springframework.security.web.context.SecurityContextHolderFilter@39384ba6, org.springframework.security.web.header.HeaderWriterFilter@1b52f723, org.springframework.web.filter.CorsFilter@304e83a, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@e7529ac, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@6770a229, org.gotson.komga.infrastructure.security.apikey.ApiKeyAuthenticationFilter@5e9db5e7, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5fd8302e, org.springframework.security.web.access.ExceptionTranslationFilter@25198ead, org.springframework.security.web.access.intercept.AuthorizationFilter@1009a9b4]
2024-09-29T13:05:53.198+01:00  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 25600 (http) with context path ''
[DELETED]
2024-09-29T13:06:02.593+01:00  INFO 1 --- [io-25600-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-09-29T13:06:02.594+01:00  INFO 1 --- [io-25600-exec-2] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2024-09-29T13:06:02.596+01:00  INFO 1 --- [io-25600-exec-2] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms
2024-09-29T13:06:02.652+01:00  WARN 1 --- [io-25600-exec-2] o.s.web.servlet.PageNotFound             : No mapping for GET /book/0HDYCWF4HAN6Y/read-epub
2024-09-29T13:06:03.329+01:00 DEBUG 1 --- [         task-6] o.g.k.i.security.LoginListener           : AuthenticationActivity(userId=0HDXR6V18ZAE1, email=admin@maia.ac, apiKeyId=null, apiKeyComment=null, ip=[REDACTED_IP], userAgent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/[REDACTED_IP] Safari/537.36, success=true, error=null, dateTime=2024-09-29T13:06:03.322730328, source=RememberMe)
2024-09-29T13:06:03.785+01:00 DEBUG 1 --- [         task-6] o.g.k.i.s.session.SessionListener        : SessionCreatedEvent: 325ddb6a-febb-497e-bebf-af284f16181c
2024-09-29T13:06:05.202+01:00 DEBUG 1 --- [io-25600-exec-8] o.g.komga.domain.service.BookAnalyzer    : Get file OEBPS/9781368016193_epub_cvi_r1.xhtml for book: BookWithMedia(book=Book(name=The Lying Woods - Ashley Elston, url=file:/data/Ashley%20Elston/The%20Lying%20Woods%20(67)/The%20Lying%20Woods%20-%20Ashley%20Elston.epub, fileLastModified=2024-09-29T12:22:28.068, fileSize=1179801, fileHash=6f27c021db1dd6298b15bfb19a51c632, number=1, id=0HDYCWF4HAN6Y, seriesId=0HDYCWF4DARHS, libraryId=0HDXRE4RCZCQ6, deletedDate=null, oneshot=false, createdDate=2024-09-29T12:46:27, lastModifiedDate=2024-09-29T12:46:55.030), media=Media(status=READY, mediaType=application/epub+zip, comment=null, bookId='0HDYCWF4HAN6Y', createdDate=2024-09-29T12:46:27, lastModifiedDate=2024-09-29T12:46:49.875))
2024-09-29T13:06:13.210+01:00 DEBUG 1 --- [   scheduling-1] o.g.komga.interfaces.sse.SseController   : Publish SSE: 'TaskQueueStatus':TaskQueueSseDto(count=0, countByType={})

komga_cleaned.log

Komga version

1.14.0

Operating system

Talos OS (K8S, Docker)

Installation method

jar

Other details

My Deployment:

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: komga
  namespace: media
spec:
  interval: 15m
  chart:
    spec:
      chart: app-template
      version: 1.5.1
      sourceRef:
        kind: HelmRepository
        name: bjw-s
        namespace: flux-system
  install:
    createNamespace: true
    remediation:
      retries: 5
  upgrade:
    remediation:
      retries: 5
  values:
    image:
      repository: gotson/komga
      tag: latest
    env:
      TZ: "${TIMEZONE}"
      CACHE_DIR: /cache
      LOGGING_LEVEL_ORG_GOTSON_KOMGA: "DEBUG"
      KOMGA_CORS_ALLOWED_ORIGINS: &cors "https://read.${SECRET_DOMAIN}"
      SERVER_PORT: &port 25600
    service:
      main:
        ports:
          http:
            port: *port
    ingress:
      main:
        enabled: true
        ingressClassName: traefik
        annotations:
          kubernetes.io/tls-acme: "true"
          cert-manager.io/cluster-issuer: letsencrypt-production
          traefik.ingress.kubernetes.io/router.entrypoints: "websecure"
          traefik.ingress.kubernetes.io/router.middlewares: >-
            networking-traefik-secure-headers@kubernetescrd,
            networking-rfc1918@kubernetescrd,
            media-komga-middleware@kubernetescrd
        hosts:
          - host: &host "read.${SECRET_DOMAIN}"
            paths:
              - path: /
                pathType: Prefix
        tls:
          - secretName: &tls "tls-komga"
            hosts:
              - *host
    persistence:
      data:
        enabled: true
        volumeSpec:
          nfs:
            server: "${NFS_SERVER_IP_COLD_2}"
            path: "${NFS_SERVER_IP_COLD_2_MEDIA_VAULT}/books"
        mountPath: /data
        readOnly: false

My Reverse Proxy Config:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: komga-secure-middleware
  namespace: media
spec:
  headers:
    # Custom request headers for Komga
    customRequestHeaders:
      X-Forwarded-Proto: https

    # Allow GET and POST methods for cross-origin requests
    accessControlAllowMethods:
      - GET
      - POST

    # Allow cross-origin requests from specific domains
    accessControlAllowOriginList:
      - https://*.${SECRET_DOMAIN}
      - https://${SECRET_DOMAIN}

    # Cache preflight responses for 100 seconds
    accessControlMaxAge: 100

    # Enforce strict Content Security Policy (CSP)
    contentSecurityPolicy: |
      default-src 'none'; form-action 'none'; frame-ancestors 'none'; base-uri 'none'

    # Add 'Vary: Origin' header to responses
    addVaryHeader: true

    # Enable protection against XSS attacks
    browserXssFilter: true

    # Prevent MIME-type sniffing
    contentTypeNosniff: true

    # Enable HTTP Strict Transport Security (HSTS) for 2 years
    forceSTSHeader: true
    stsIncludeSubdomains: true
    stsPreload: true
    stsSeconds: 63072000

    # Prevent the page from being framed (clickjacking protection)
    frameDeny: true

    # Set the referrer policy to 'same-origin'
    referrerPolicy: 'same-origin'

    # Ensure all traffic is redirected to HTTPS
    sslRedirect: true

Acknowledgements

gotson commented 3 weeks ago

can you get the logs from the Javascript console of the browser, and the XHR network requests made by the browser?

franciscomfcmaia commented 3 weeks ago

Hi @gotson,

I think the javascript console might be hiding the reason for this error.....but the 404 is really strange....

Screenshot 2024-09-30 at 11 23 02 Screenshot 2024-09-30 at 11 21 39
franciscomfcmaia commented 3 weeks ago

Okay @gotson,

I had a look at the X-Frame-Options on my traefik side. I made the following addition for anyone in this situation:

---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: komga-middleware
  namespace: media
spec:
  headers:
    customRequestHeaders:
      X-Forwarded-Proto: https
    customFrameOptionsValue: "ALLOW-FROM https://read.${SECRET_DOMAIN}"  # This can still be kept if you want to allow this specific origin
    contentSecurityPolicy: "frame-ancestors 'self' https://read.${SECRET_DOMAIN};"  # Allow framing from self and specified URL

Books are now opening!!! 👍🏼

However, I still see the 404 error but the webpage works fine. Maybe an old call still on the webui code?

Screenshot 2024-09-30 at 16 26 28
gotson commented 2 weeks ago

but the 404 is really strange

this is expected behaviour if the series has only 1 book