[Bug]: Server cannot pull author information #2918

Closed
opened 2026-02-20 10:24:40 -05:00 by deekerman · 8 comments
Owner

Originally created by @lordofwizard on GitHub (Jul 26, 2025).

What happened?

Running docker compose version of the audiobookshelf

when clicked on "Quick Match" for author the information is not pulled.

Here are the logs.

here is the docker compose file that i am currently using. with v2.26.3 (latest tag at the time of submitting the bug)

###################################################################################################

#
#    _             _ _       ____              _     ____  _          _  __
#   / \  _   _  __| (_) ___ | __ )  ___   ___ | | __/ ___|| |__   ___| |/ _|
#  / _ \| | | |/ _` | |/ _ \|  _ \ / _ \ / _ \| |/ /\___ \| '_ \ / _ \ | |_
# / ___ \ |_| | (_| | | (_) | |_) | (_) | (_) |   <  ___) | | | |  __/ |  _|
#/_/   \_\__,_|\__,_|_|\___/|____/ \___/ \___/|_|\_\|____/|_| |_|\___|_|_|
#

  audiobookshelf:
    image: ghcr.io/advplyr/audiobookshelf:latest
    ports:
      - 6903:80
    volumes:
      - ${PWD}/audiobookshelf/audiobooks:/audiobooks
      - ${PWD}/audiobookshelf/podcasts:/podcasts
      - ${PWD}/audiobookshelf/config:/config
      - ${PWD}/audiobookshelf/metadata:/metadata
    environment:
      - TZ=Asia/Kolkata

What did you expect to happen?

I want it such that it automatilly pulls the author information and show's the author's picture as well as relational metadata

Steps to reproduce the issue

  1. Setup Docker container
  2. Add Audiobook
  3. From author tab, click on a author and click "Quick match"

Audiobookshelf version

v2.26.3

How are you running audiobookshelf?

Docker

What OS is your Audiobookshelf server hosted from?

Linux

If the issue is being seen in the UI, what browsers are you seeing the problem on?

Chrome

Logs

2025-07-26 15:26:21.049

INFO

=== Starting Server ===

2025-07-26 15:26:21.050

INFO

[Server] Init v2.26.3

2025-07-26 15:26:21.050

INFO

[Server] Node.js Version: v20.19.4

2025-07-26 15:26:21.050

INFO

[Server] Platform: linux

2025-07-26 15:26:21.051

INFO

[Server] Arch: arm64

2025-07-26 15:26:21.061

INFO

[Database] Initializing db at "/config/absdatabase.sqlite"

2025-07-26 15:26:21.098

INFO

[Database] Loading extension /usr/local/lib/nusqlite3/libnusqlite3.so

2025-07-26 15:26:21.099

INFO

[Database] Successfully loaded extension /usr/local/lib/nusqlite3/libnusqlite3.so

2025-07-26 15:26:21.099

INFO

[Database] Db supports unaccent and unicode foldings

2025-07-26 15:26:21.100

INFO

[Database] Db connection was successful

2025-07-26 15:26:21.161

INFO

[MigrationManager] Migrating database up to version 2.26.3

2025-07-26 15:26:21.162

INFO

[MigrationManager] Migrations to run: v2.26.0-create-auth-tables.js

2025-07-26 15:26:21.167

INFO

Created a backup of the original database.

2025-07-26 15:26:21.173

INFO

{ event: 'migrating', name: 'v2.26.0-create-auth-tables.js' }

2025-07-26 15:26:21.173

INFO

[2.26.0 migration] UPGRADE BEGIN: 2.26.0-create-auth-tables

2025-07-26 15:26:21.175

INFO

[2.26.0 migration] creating table "sessions"

2025-07-26 15:26:21.186

INFO

[2.26.0 migration] created table "sessions"

2025-07-26 15:26:21.187

INFO

[2.26.0 migration] creating table "apiKeys"

2025-07-26 15:26:21.195

INFO

[2.26.0 migration] created table "apiKeys"

2025-07-26 15:26:21.195

INFO

[2.26.0 migration] UPGRADE END: 2.26.0-create-auth-tables

2025-07-26 15:26:21.211

INFO

{ event: 'migrated', name: 'v2.26.0-create-auth-tables.js', durationSeconds: 0.04 }

2025-07-26 15:26:21.213

INFO

[MigrationManager] Migrations successfully applied to the original database.

2025-07-26 15:26:21.356

INFO

[Database] Db initialized with models: SequelizeMeta, user, session, apiKey, library, libraryFolder, book, podcast, podcastEpisode, libraryItem, mediaProgress, series, bookSeries, author, bookAuthor, collection, collectionBook, playlist, playlistMediaItem, device, playbackSession, feed, feedEpisode, setting, customMetadataProvider, mediaItemShare

2025-07-26 15:26:21.393

INFO

[Database] Server upgrade detected from 2.25.1 to 2.26.3

2025-07-26 15:26:21.402

INFO

[Database] running ANALYZE

2025-07-26 15:26:21.410

INFO

[Database] ANALYZE completed

2025-07-26 15:26:21.412

INFO

[LogManager] Init current daily log filename: 2025-07-26.txt

2025-07-26 15:26:21.425

INFO

[BackupManager] 0 Backups Found

2025-07-26 15:26:21.425

INFO

[BackupManager] Auto Backups are disabled

2025-07-26 15:26:21.445

INFO

[Watcher] Initializing watcher for "Audiobooks".

2025-07-26 15:26:21.463

INFO

Listening on port :80

2025-07-26 15:26:21.503

INFO

[Watcher] "Audiobooks" Ready

2025-07-26 15:26:22.759

INFO

[SocketAuthority] Socket Connected to /audiobookshelf/socket.io 80H6rs84IE36jKBpAAAB

2025-07-26 15:26:51.972

INFO

[SocketAuthority] Socket Connected to /audiobookshelf/socket.io _vmth6BMqQ9zz5Q2AAAD

2025-07-26 15:27:21.502

INFO

=== Starting Server ===

2025-07-26 15:27:21.503

INFO

[Server] Init v2.26.3

2025-07-26 15:27:21.503

INFO

[Server] Node.js Version: v20.19.4

2025-07-26 15:27:21.503

INFO

[Server] Platform: linux

2025-07-26 15:27:21.504

INFO

[Server] Arch: arm64

2025-07-26 15:27:21.515

INFO

[Database] Initializing db at "/config/absdatabase.sqlite"

2025-07-26 15:27:21.548

INFO

[Database] Loading extension /usr/local/lib/nusqlite3/libnusqlite3.so

2025-07-26 15:27:21.549

INFO

[Database] Successfully loaded extension /usr/local/lib/nusqlite3/libnusqlite3.so

2025-07-26 15:27:21.549

INFO

[Database] Db supports unaccent and unicode foldings

2025-07-26 15:27:21.550

INFO

[Database] Db connection was successful

2025-07-26 15:27:21.556

INFO

[MigrationManager] Database is already up to date.

2025-07-26 15:27:21.698

INFO

[Database] Db initialized with models: user, session, apiKey, library, libraryFolder, book, podcast, podcastEpisode, libraryItem, mediaProgress, series, bookSeries, author, bookAuthor, collection, collectionBook, playlist, playlistMediaItem, device, playbackSession, feed, feedEpisode, setting, customMetadataProvider, mediaItemShare

2025-07-26 15:27:21.740

INFO

[Database] running ANALYZE

2025-07-26 15:27:21.750

INFO

[Database] ANALYZE completed

2025-07-26 15:27:21.751

INFO

[LogManager] Init current daily log filename: 2025-07-26.txt

2025-07-26 15:27:21.759

INFO

[BackupManager] 0 Backups Found

2025-07-26 15:27:21.760

INFO

[BackupManager] Auto Backups are disabled

2025-07-26 15:27:21.776

INFO

[Watcher] Initializing watcher for "Audiobooks".

2025-07-26 15:27:21.786

INFO

Listening on port :80

2025-07-26 15:27:21.814

INFO

[Watcher] "Audiobooks" Ready

2025-07-26 15:27:26.747

INFO

[SocketAuthority] Socket Connected to /audiobookshelf/socket.io _33D85RnbdV8HKSKAAAB

2025-07-26 15:27:29.936

INFO

[SocketAuthority] Socket Connected to /audiobookshelf/socket.io bWcFcrBBtjVo9mk9AAAD

2025-07-26 15:27:50.686

INFO

[LocalAuth] User "root" logged in from ip 2409:40c2:600b:9f67:6c5e:6115:5c05:8776

2025-07-26 15:27:52.279

INFO

[LocalAuth] User "root" logged in from ip 2409:40c2:600b:9f67:6c5e:6115:5c05:8776

2025-07-26 15:27:54.775

INFO

[SocketAuthority] Socket Connected to /audiobookshelf/socket.io dg8MpzSfg2N-pWC8AAAF

2025-07-26 15:28:01.188

INFO

[Audnexus] Searching for author "https://api.audnex.us/authors?name=Frank+Herbert&region=us"

2025-07-26 15:28:01.225

ERROR

[Audnexus] Author ASIN request failed for Frank Herbert [AxiosError: Request failed with status code 404] { code: 'ERR_BAD_REQUEST', config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [Function: httpAdapter], transformRequest: [ [Function: transformRequest] ], transformResponse: [ [Function: transformResponse] ], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: [Function] }, validateStatus: [Function: validateStatus], headers: { Accept: 'application/json, text/plain, */*', 'User-Agent': 'axios/0.27.2' }, method: 'get', url: 'https://api.audnex.us/authors?name=Frank+Herbert&region=us', data: undefined }, request: <ref *1> ClientRequest { _events: [Object: null prototype] { abort: [Function (anonymous)], aborted: [Function (anonymous)], connect: [Function (anonymous)], error: [Function (anonymous)], socket: [Function (anonymous)], timeout: [Function (anonymous)], finish: [Function: requestOnFinish] }, _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: true, _last: true, chunkedEncoding: false, shouldKeepAlive: true, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: false, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, strictContentLength: false, _contentLength: 0, _hasBody: true, _trailer: '', finished: true, _headerSent: true, _closed: true, socket: TLSSocket { _tlsOptions: [Object], _secureEstablished: true, _securePending: false, _newSessionPending: false, _controlReleased: true, secureConnecting: false, _SNICallback: null, servername: 'api.audnex.us', alpnProtocol: false, authorized: false, authorizationError: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', encrypted: true, _events: [Object: null prototype], _eventsCount: 9, connecting: false, _hadError: false, _parent: null, _host: 'api.audnex.us', _closeAfterHandlingError: false, _readableState: [ReadableState], _writableState: [WritableState], allowHalfOpen: false, _maxListeners: undefined, _sockname: null, _pendingData: null, _pendingEncoding: '', server: undefined, _server: null, ssl: [TLSWrap], _requestCert: true, _rejectUnauthorized: false, timeout: 5000, parser: null, _httpMessage: null, [Symbol(alpncallback)]: null, [Symbol(res)]: [TLSWrap], [Symbol(verified)]: true, [Symbol(pendingSession)]: null, [Symbol(async_id_symbol)]: -1, [Symbol(kHandle)]: [TLSWrap], [Symbol(lastWriteQueueSize)]: 0, [Symbol(timeout)]: Timeout { _idleTimeout: 5000, _idlePrev: [TimersList], _idleNext: [TimersList], _idleStart: 40634, _onTimeout: [Function: bound ], _timerArgs: undefined, _repeat: null, _destroyed: false, [Symbol(refed)]: false, [Symbol(kHasPrimitive)]: false, [Symbol(asyncId)]: 2892, [Symbol(triggerId)]: 2890 }, [Symbol(kBuffer)]: null, [Symbol(kBufferCb)]: null, [Symbol(kBufferGen)]: null, [Symbol(shapeMode)]: true, [Symbol(kCapture)]: false, [Symbol(kSetNoDelay)]: false, [Symbol(kSetKeepAlive)]: true, [Symbol(kSetKeepAliveInitialDelay)]: 1, [Symbol(kBytesRead)]: 0, [Symbol(kBytesWritten)]: 0, [Symbol(connect-options)]: [Object] }, _header: 'GET /authors?name=Frank+Herbert&region=us HTTP/1.1\r\n' + 'Accept: application/json, text/plain, */*\r\n' + 'User-Agent: axios/0.27.2\r\n' + 'Host: api.audnex.us\r\n' + 'Connection: keep-alive\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: nop], agent: Agent { _events: [Object: null prototype], _eventsCount: 2, _maxListeners: undefined, defaultPort: 443, protocol: 'https:', options: [Object: null prototype], requests: [Object: null prototype] {}, sockets: [Object: null prototype] {}, freeSockets: [Object: null prototype], keepAliveMsecs: 1000, keepAlive: true, maxSockets: Infinity, maxFreeSockets: 256, scheduling: 'lifo', maxTotalSockets: Infinity, totalSocketCount: 1, maxCachedSessions: 100, _sessionCache: [Object], [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false }, socketPath: undefined, method: 'GET', maxHeaderSize: undefined, insecureHTTPParser: undefined, joinDuplicateHeaders: undefined, path: '/authors?name=Frank+Herbert&region=us', _ended: true, res: IncomingMessage { _events: [Object], _readableState: [ReadableState], _maxListeners: undefined, socket: null, httpVersionMajor: 1, httpVersionMinor: 1, httpVersion: '1.1', complete: true, rawHeaders: [Array], rawTrailers: [], joinDuplicateHeaders: undefined, aborted: false, upgrade: false, url: '', method: null, statusCode: 404, statusMessage: 'Not Found', client: [TLSSocket], _consuming: false, _dumped: false, req: [Circular *1], _eventsCount: 4, responseUrl: 'https://api.audnex.us/authors?name=Frank+Herbert&region=us', redirects: [], [Symbol(shapeMode)]: true, [Symbol(kCapture)]: false, [Symbol(kHeaders)]: [Object], [Symbol(kHeadersCount)]: 16, [Symbol(kTrailers)]: null, [Symbol(kTrailersCount)]: 0 }, aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'api.audnex.us', protocol: 'https:', _redirectable: Writable { _events: [Object], _writableState: [WritableState], _maxListeners: undefined, _options: [Object], _ended: true, _ending: true, _redirectCount: 0, _redirects: [], _requestBodyLength: 0, _requestBodyBuffers: [], _eventsCount: 3, _onNativeResponse: [Function (anonymous)], _currentRequest: [Circular *1], _currentUrl: 'https://api.audnex.us/authors?name=Frank+Herbert&region=us', [Symbol(shapeMode)]: true, [Symbol(kCapture)]: false }, [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false, [Symbol(kBytesWritten)]: 0, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype] { accept: [Array], 'user-agent': [Array], host: [Array] }, [Symbol(errored)]: null, [Symbol(kHighWaterMark)]: 16384, [Symbol(kRejectNonStandardBodyWrites)]: false, [Symbol(kUniqueHeaders)]: null }, response: { status: 404, statusText: 'Not Found', headers: { server: 'nginx/1.28.0', date: 'Sat, 26 Jul 2025 09:58:01 GMT', 'content-type': 'application/json', 'content-length': '128', connection: 'keep-alive', 'x-frame-options': 'SAMEORIGIN', 'permissions-policy': 'interest-cohort=()', 'x-content-type-options': 'nosniff' }, config: { transitional: [Object], adapter: [Function: httpAdapter], transformRequest: [Array], transformResponse: [Array], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: [Object], validateStatus: [Function: validateStatus], headers: [Object], method: 'get', url: 'https://api.audnex.us/authors?name=Frank+Herbert&region=us', data: undefined }, request: <ref *1> ClientRequest { _events: [Object: null prototype], _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: true, _last: true, chunkedEncoding: false, shouldKeepAlive: true, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: false, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, strictContentLength: false, _contentLength: 0, _hasBody: true, _trailer: '', finished: true, _headerSent: true, _closed: true, socket: [TLSSocket], _header: 'GET /authors?name=Frank+Herbert&region=us HTTP/1.1\r\n' + 'Accept: application/json, text/plain, */*\r\n' + 'User-Agent: axios/0.27.2\r\n' + 'Host: api.audnex.us\r\n' + 'Connection: keep-alive\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: nop], agent: [Agent], socketPath: undefined, method: 'GET', maxHeaderSize: undefined, insecureHTTPParser: undefined, joinDuplicateHeaders: undefined, path: '/authors?name=Frank+Herbert&region=us', _ended: true, res: [IncomingMessage], aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'api.audnex.us', protocol: 'https:', _redirectable: [Writable], [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false, [Symbol(kBytesWritten)]: 0, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype], [Symbol(errored)]: null, [Symbol(kHighWaterMark)]: 16384, [Symbol(kRejectNonStandardBodyWrites)]: false, [Symbol(kUniqueHeaders)]: null }, data: { error: [Object] } } }

Additional Notes

No response

Originally created by @lordofwizard on GitHub (Jul 26, 2025). ### What happened? Running docker compose version of the audiobookshelf when clicked on "Quick Match" for author the information is not pulled. Here are the logs. here is the docker compose file that i am currently using. with v2.26.3 (latest tag at the time of submitting the bug) ```yaml ################################################################################################### # # _ _ _ ____ _ ____ _ _ __ # / \ _ _ __| (_) ___ | __ ) ___ ___ | | __/ ___|| |__ ___| |/ _| # / _ \| | | |/ _` | |/ _ \| _ \ / _ \ / _ \| |/ /\___ \| '_ \ / _ \ | |_ # / ___ \ |_| | (_| | | (_) | |_) | (_) | (_) | < ___) | | | | __/ | _| #/_/ \_\__,_|\__,_|_|\___/|____/ \___/ \___/|_|\_\|____/|_| |_|\___|_|_| # audiobookshelf: image: ghcr.io/advplyr/audiobookshelf:latest ports: - 6903:80 volumes: - ${PWD}/audiobookshelf/audiobooks:/audiobooks - ${PWD}/audiobookshelf/podcasts:/podcasts - ${PWD}/audiobookshelf/config:/config - ${PWD}/audiobookshelf/metadata:/metadata environment: - TZ=Asia/Kolkata ``` ### What did you expect to happen? I want it such that it automatilly pulls the author information and show's the author's picture as well as relational metadata ### Steps to reproduce the issue 1. Setup Docker container 2. Add Audiobook 3. From author tab, click on a author and click "Quick match" ### Audiobookshelf version v2.26.3 ### How are you running audiobookshelf? Docker ### What OS is your Audiobookshelf server hosted from? Linux ### If the issue is being seen in the UI, what browsers are you seeing the problem on? Chrome ### Logs ```shell 2025-07-26 15:26:21.049 INFO === Starting Server === 2025-07-26 15:26:21.050 INFO [Server] Init v2.26.3 2025-07-26 15:26:21.050 INFO [Server] Node.js Version: v20.19.4 2025-07-26 15:26:21.050 INFO [Server] Platform: linux 2025-07-26 15:26:21.051 INFO [Server] Arch: arm64 2025-07-26 15:26:21.061 INFO [Database] Initializing db at "/config/absdatabase.sqlite" 2025-07-26 15:26:21.098 INFO [Database] Loading extension /usr/local/lib/nusqlite3/libnusqlite3.so 2025-07-26 15:26:21.099 INFO [Database] Successfully loaded extension /usr/local/lib/nusqlite3/libnusqlite3.so 2025-07-26 15:26:21.099 INFO [Database] Db supports unaccent and unicode foldings 2025-07-26 15:26:21.100 INFO [Database] Db connection was successful 2025-07-26 15:26:21.161 INFO [MigrationManager] Migrating database up to version 2.26.3 2025-07-26 15:26:21.162 INFO [MigrationManager] Migrations to run: v2.26.0-create-auth-tables.js 2025-07-26 15:26:21.167 INFO Created a backup of the original database. 2025-07-26 15:26:21.173 INFO { event: 'migrating', name: 'v2.26.0-create-auth-tables.js' } 2025-07-26 15:26:21.173 INFO [2.26.0 migration] UPGRADE BEGIN: 2.26.0-create-auth-tables 2025-07-26 15:26:21.175 INFO [2.26.0 migration] creating table "sessions" 2025-07-26 15:26:21.186 INFO [2.26.0 migration] created table "sessions" 2025-07-26 15:26:21.187 INFO [2.26.0 migration] creating table "apiKeys" 2025-07-26 15:26:21.195 INFO [2.26.0 migration] created table "apiKeys" 2025-07-26 15:26:21.195 INFO [2.26.0 migration] UPGRADE END: 2.26.0-create-auth-tables 2025-07-26 15:26:21.211 INFO { event: 'migrated', name: 'v2.26.0-create-auth-tables.js', durationSeconds: 0.04 } 2025-07-26 15:26:21.213 INFO [MigrationManager] Migrations successfully applied to the original database. 2025-07-26 15:26:21.356 INFO [Database] Db initialized with models: SequelizeMeta, user, session, apiKey, library, libraryFolder, book, podcast, podcastEpisode, libraryItem, mediaProgress, series, bookSeries, author, bookAuthor, collection, collectionBook, playlist, playlistMediaItem, device, playbackSession, feed, feedEpisode, setting, customMetadataProvider, mediaItemShare 2025-07-26 15:26:21.393 INFO [Database] Server upgrade detected from 2.25.1 to 2.26.3 2025-07-26 15:26:21.402 INFO [Database] running ANALYZE 2025-07-26 15:26:21.410 INFO [Database] ANALYZE completed 2025-07-26 15:26:21.412 INFO [LogManager] Init current daily log filename: 2025-07-26.txt 2025-07-26 15:26:21.425 INFO [BackupManager] 0 Backups Found 2025-07-26 15:26:21.425 INFO [BackupManager] Auto Backups are disabled 2025-07-26 15:26:21.445 INFO [Watcher] Initializing watcher for "Audiobooks". 2025-07-26 15:26:21.463 INFO Listening on port :80 2025-07-26 15:26:21.503 INFO [Watcher] "Audiobooks" Ready 2025-07-26 15:26:22.759 INFO [SocketAuthority] Socket Connected to /audiobookshelf/socket.io 80H6rs84IE36jKBpAAAB 2025-07-26 15:26:51.972 INFO [SocketAuthority] Socket Connected to /audiobookshelf/socket.io _vmth6BMqQ9zz5Q2AAAD 2025-07-26 15:27:21.502 INFO === Starting Server === 2025-07-26 15:27:21.503 INFO [Server] Init v2.26.3 2025-07-26 15:27:21.503 INFO [Server] Node.js Version: v20.19.4 2025-07-26 15:27:21.503 INFO [Server] Platform: linux 2025-07-26 15:27:21.504 INFO [Server] Arch: arm64 2025-07-26 15:27:21.515 INFO [Database] Initializing db at "/config/absdatabase.sqlite" 2025-07-26 15:27:21.548 INFO [Database] Loading extension /usr/local/lib/nusqlite3/libnusqlite3.so 2025-07-26 15:27:21.549 INFO [Database] Successfully loaded extension /usr/local/lib/nusqlite3/libnusqlite3.so 2025-07-26 15:27:21.549 INFO [Database] Db supports unaccent and unicode foldings 2025-07-26 15:27:21.550 INFO [Database] Db connection was successful 2025-07-26 15:27:21.556 INFO [MigrationManager] Database is already up to date. 2025-07-26 15:27:21.698 INFO [Database] Db initialized with models: user, session, apiKey, library, libraryFolder, book, podcast, podcastEpisode, libraryItem, mediaProgress, series, bookSeries, author, bookAuthor, collection, collectionBook, playlist, playlistMediaItem, device, playbackSession, feed, feedEpisode, setting, customMetadataProvider, mediaItemShare 2025-07-26 15:27:21.740 INFO [Database] running ANALYZE 2025-07-26 15:27:21.750 INFO [Database] ANALYZE completed 2025-07-26 15:27:21.751 INFO [LogManager] Init current daily log filename: 2025-07-26.txt 2025-07-26 15:27:21.759 INFO [BackupManager] 0 Backups Found 2025-07-26 15:27:21.760 INFO [BackupManager] Auto Backups are disabled 2025-07-26 15:27:21.776 INFO [Watcher] Initializing watcher for "Audiobooks". 2025-07-26 15:27:21.786 INFO Listening on port :80 2025-07-26 15:27:21.814 INFO [Watcher] "Audiobooks" Ready 2025-07-26 15:27:26.747 INFO [SocketAuthority] Socket Connected to /audiobookshelf/socket.io _33D85RnbdV8HKSKAAAB 2025-07-26 15:27:29.936 INFO [SocketAuthority] Socket Connected to /audiobookshelf/socket.io bWcFcrBBtjVo9mk9AAAD 2025-07-26 15:27:50.686 INFO [LocalAuth] User "root" logged in from ip 2409:40c2:600b:9f67:6c5e:6115:5c05:8776 2025-07-26 15:27:52.279 INFO [LocalAuth] User "root" logged in from ip 2409:40c2:600b:9f67:6c5e:6115:5c05:8776 2025-07-26 15:27:54.775 INFO [SocketAuthority] Socket Connected to /audiobookshelf/socket.io dg8MpzSfg2N-pWC8AAAF 2025-07-26 15:28:01.188 INFO [Audnexus] Searching for author "https://api.audnex.us/authors?name=Frank+Herbert&region=us" 2025-07-26 15:28:01.225 ERROR [Audnexus] Author ASIN request failed for Frank Herbert [AxiosError: Request failed with status code 404] { code: 'ERR_BAD_REQUEST', config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [Function: httpAdapter], transformRequest: [ [Function: transformRequest] ], transformResponse: [ [Function: transformResponse] ], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: [Function] }, validateStatus: [Function: validateStatus], headers: { Accept: 'application/json, text/plain, */*', 'User-Agent': 'axios/0.27.2' }, method: 'get', url: 'https://api.audnex.us/authors?name=Frank+Herbert&region=us', data: undefined }, request: <ref *1> ClientRequest { _events: [Object: null prototype] { abort: [Function (anonymous)], aborted: [Function (anonymous)], connect: [Function (anonymous)], error: [Function (anonymous)], socket: [Function (anonymous)], timeout: [Function (anonymous)], finish: [Function: requestOnFinish] }, _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: true, _last: true, chunkedEncoding: false, shouldKeepAlive: true, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: false, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, strictContentLength: false, _contentLength: 0, _hasBody: true, _trailer: '', finished: true, _headerSent: true, _closed: true, socket: TLSSocket { _tlsOptions: [Object], _secureEstablished: true, _securePending: false, _newSessionPending: false, _controlReleased: true, secureConnecting: false, _SNICallback: null, servername: 'api.audnex.us', alpnProtocol: false, authorized: false, authorizationError: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE', encrypted: true, _events: [Object: null prototype], _eventsCount: 9, connecting: false, _hadError: false, _parent: null, _host: 'api.audnex.us', _closeAfterHandlingError: false, _readableState: [ReadableState], _writableState: [WritableState], allowHalfOpen: false, _maxListeners: undefined, _sockname: null, _pendingData: null, _pendingEncoding: '', server: undefined, _server: null, ssl: [TLSWrap], _requestCert: true, _rejectUnauthorized: false, timeout: 5000, parser: null, _httpMessage: null, [Symbol(alpncallback)]: null, [Symbol(res)]: [TLSWrap], [Symbol(verified)]: true, [Symbol(pendingSession)]: null, [Symbol(async_id_symbol)]: -1, [Symbol(kHandle)]: [TLSWrap], [Symbol(lastWriteQueueSize)]: 0, [Symbol(timeout)]: Timeout { _idleTimeout: 5000, _idlePrev: [TimersList], _idleNext: [TimersList], _idleStart: 40634, _onTimeout: [Function: bound ], _timerArgs: undefined, _repeat: null, _destroyed: false, [Symbol(refed)]: false, [Symbol(kHasPrimitive)]: false, [Symbol(asyncId)]: 2892, [Symbol(triggerId)]: 2890 }, [Symbol(kBuffer)]: null, [Symbol(kBufferCb)]: null, [Symbol(kBufferGen)]: null, [Symbol(shapeMode)]: true, [Symbol(kCapture)]: false, [Symbol(kSetNoDelay)]: false, [Symbol(kSetKeepAlive)]: true, [Symbol(kSetKeepAliveInitialDelay)]: 1, [Symbol(kBytesRead)]: 0, [Symbol(kBytesWritten)]: 0, [Symbol(connect-options)]: [Object] }, _header: 'GET /authors?name=Frank+Herbert&region=us HTTP/1.1\r\n' + 'Accept: application/json, text/plain, */*\r\n' + 'User-Agent: axios/0.27.2\r\n' + 'Host: api.audnex.us\r\n' + 'Connection: keep-alive\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: nop], agent: Agent { _events: [Object: null prototype], _eventsCount: 2, _maxListeners: undefined, defaultPort: 443, protocol: 'https:', options: [Object: null prototype], requests: [Object: null prototype] {}, sockets: [Object: null prototype] {}, freeSockets: [Object: null prototype], keepAliveMsecs: 1000, keepAlive: true, maxSockets: Infinity, maxFreeSockets: 256, scheduling: 'lifo', maxTotalSockets: Infinity, totalSocketCount: 1, maxCachedSessions: 100, _sessionCache: [Object], [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false }, socketPath: undefined, method: 'GET', maxHeaderSize: undefined, insecureHTTPParser: undefined, joinDuplicateHeaders: undefined, path: '/authors?name=Frank+Herbert&region=us', _ended: true, res: IncomingMessage { _events: [Object], _readableState: [ReadableState], _maxListeners: undefined, socket: null, httpVersionMajor: 1, httpVersionMinor: 1, httpVersion: '1.1', complete: true, rawHeaders: [Array], rawTrailers: [], joinDuplicateHeaders: undefined, aborted: false, upgrade: false, url: '', method: null, statusCode: 404, statusMessage: 'Not Found', client: [TLSSocket], _consuming: false, _dumped: false, req: [Circular *1], _eventsCount: 4, responseUrl: 'https://api.audnex.us/authors?name=Frank+Herbert&region=us', redirects: [], [Symbol(shapeMode)]: true, [Symbol(kCapture)]: false, [Symbol(kHeaders)]: [Object], [Symbol(kHeadersCount)]: 16, [Symbol(kTrailers)]: null, [Symbol(kTrailersCount)]: 0 }, aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'api.audnex.us', protocol: 'https:', _redirectable: Writable { _events: [Object], _writableState: [WritableState], _maxListeners: undefined, _options: [Object], _ended: true, _ending: true, _redirectCount: 0, _redirects: [], _requestBodyLength: 0, _requestBodyBuffers: [], _eventsCount: 3, _onNativeResponse: [Function (anonymous)], _currentRequest: [Circular *1], _currentUrl: 'https://api.audnex.us/authors?name=Frank+Herbert&region=us', [Symbol(shapeMode)]: true, [Symbol(kCapture)]: false }, [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false, [Symbol(kBytesWritten)]: 0, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype] { accept: [Array], 'user-agent': [Array], host: [Array] }, [Symbol(errored)]: null, [Symbol(kHighWaterMark)]: 16384, [Symbol(kRejectNonStandardBodyWrites)]: false, [Symbol(kUniqueHeaders)]: null }, response: { status: 404, statusText: 'Not Found', headers: { server: 'nginx/1.28.0', date: 'Sat, 26 Jul 2025 09:58:01 GMT', 'content-type': 'application/json', 'content-length': '128', connection: 'keep-alive', 'x-frame-options': 'SAMEORIGIN', 'permissions-policy': 'interest-cohort=()', 'x-content-type-options': 'nosniff' }, config: { transitional: [Object], adapter: [Function: httpAdapter], transformRequest: [Array], transformResponse: [Array], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: [Object], validateStatus: [Function: validateStatus], headers: [Object], method: 'get', url: 'https://api.audnex.us/authors?name=Frank+Herbert&region=us', data: undefined }, request: <ref *1> ClientRequest { _events: [Object: null prototype], _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: true, _last: true, chunkedEncoding: false, shouldKeepAlive: true, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: false, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, strictContentLength: false, _contentLength: 0, _hasBody: true, _trailer: '', finished: true, _headerSent: true, _closed: true, socket: [TLSSocket], _header: 'GET /authors?name=Frank+Herbert&region=us HTTP/1.1\r\n' + 'Accept: application/json, text/plain, */*\r\n' + 'User-Agent: axios/0.27.2\r\n' + 'Host: api.audnex.us\r\n' + 'Connection: keep-alive\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: nop], agent: [Agent], socketPath: undefined, method: 'GET', maxHeaderSize: undefined, insecureHTTPParser: undefined, joinDuplicateHeaders: undefined, path: '/authors?name=Frank+Herbert&region=us', _ended: true, res: [IncomingMessage], aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'api.audnex.us', protocol: 'https:', _redirectable: [Writable], [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false, [Symbol(kBytesWritten)]: 0, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype], [Symbol(errored)]: null, [Symbol(kHighWaterMark)]: 16384, [Symbol(kRejectNonStandardBodyWrites)]: false, [Symbol(kUniqueHeaders)]: null }, data: { error: [Object] } } } ``` ### Additional Notes _No response_
deekerman 2026-02-20 10:24:40 -05:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@AIMutant commented on GitHub (Jul 29, 2025):

This happens occasionally on some of my books also. Not everyone but often enough recently. Additionally I found that some of the authors get reset to empty or even to older non-synced data.

@AIMutant commented on GitHub (Jul 29, 2025): This happens occasionally on some of my books also. Not everyone but often enough recently. Additionally I found that some of the authors get reset to empty or even to older non-synced data.
Author
Owner

@advplyr commented on GitHub (Aug 14, 2025):

Is this resolved for you? If the request is returning a 404 from the server there isn't much we can do about that.

@advplyr commented on GitHub (Aug 14, 2025): Is this resolved for you? If the request is returning a 404 from the server there isn't much we can do about that.
Author
Owner

@lordofwizard commented on GitHub (Aug 15, 2025):

@advplyr no, even at the latest version i have the same issue persisting.

@lordofwizard commented on GitHub (Aug 15, 2025): @advplyr no, even at the latest version i have the same issue persisting.
Author
Owner

@Vito0912 commented on GitHub (Aug 15, 2025):

Please try fetching the URL from inside the container

@Vito0912 commented on GitHub (Aug 15, 2025): Please try fetching the URL from inside the container
Author
Owner

@lordofwizard commented on GitHub (Aug 16, 2025):

@Vito0912 I did that using curl, i am getting the response of the api back. (i installed curl package in the alpine container of audiobookshelf and ran the command) i am getting response back.

@lordofwizard commented on GitHub (Aug 16, 2025): @Vito0912 I did that using curl, i am getting the response of the api back. (i installed curl package in the alpine container of audiobookshelf and ran the command) i am getting response back.
Author
Owner

@Hannah-GBS commented on GitHub (Oct 14, 2025):

I just ran into this on the latest version. Did a Quick Match on 10 books, and 8 of them finished with a blank Author field. If I Match manually from the same source the Author field is filled in correctly.

@Hannah-GBS commented on GitHub (Oct 14, 2025): I just ran into this on the latest version. Did a Quick Match on 10 books, and 8 of them finished with a blank Author field. If I Match manually from the same source the Author field is filled in correctly.
Author
Owner

@lordofwizard commented on GitHub (Nov 8, 2025):

It's in a docker container but the issue I am having is a bit hard to put into words (i am beginner and english is not my native lang sorry)

  audiobookshelf:
    image: ghcr.io/advplyr/audiobookshelf:latest
    ports:
      - 6903:80
    volumes:
      - ${PWD}/audiobookshelf/podcasts:/podcasts
      - ${PWD}/audiobookshelf/config:/config
      - ${PWD}/audiobookshelf/metadata:/metadata
      - /home/ubuntu/Downloads/ablib:/audiobooks_extra
    environment:
      - TZ=Asia/Kolkata
      - ROUTER_BASE_PATH=/

and here's my nginx configuration

    server {
        listen 8080;
        server_name audiobooks.lordofwizard.com;
    
        # SSL Certificates (uncomment when using Cloudflare Origin certs)
        # ssl_certificate /etc/ssl/cloudflare/origin.crt;
        # ssl_certificate_key /etc/ssl/cloudflare/origin.key;
    
        # Optional: add HSTS (only enable after verifying HTTPS works)
        # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
        location / {
            proxy_pass http://127.0.0.1:6903;
    
            # --- WebSocket + Streaming Support ---
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
    
            # --- Header Forwarding ---
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
    
            # --- Timeouts (for long streams) ---
            proxy_connect_timeout 20s;
            proxy_read_timeout 3600s;
            proxy_send_timeout 3600s;
    
            # --- Buffers & Uploads ---
            proxy_buffers 16 16k;
            proxy_buffer_size 32k;
            client_max_body_size 1024M;
    
            # --- Handle Redirects properly ---
            proxy_redirect off;
    
            # --- Optional: error fallback (for better UX) ---
            error_page 502 503 504 /custom_50x.html;
        }
    
        # Optional static caching for cover art (improves loading)
        location /cover/ {
            proxy_pass http://127.0.0.1:6903/cover/;
            expires 30d;
            add_header Cache-Control "public, must-revalidate, proxy-revalidate";
        }
    }
Image
@lordofwizard commented on GitHub (Nov 8, 2025): It's in a docker container but the issue I am having is a bit hard to put into words (i am beginner and english is not my native lang sorry) ```yaml audiobookshelf: image: ghcr.io/advplyr/audiobookshelf:latest ports: - 6903:80 volumes: - ${PWD}/audiobookshelf/podcasts:/podcasts - ${PWD}/audiobookshelf/config:/config - ${PWD}/audiobookshelf/metadata:/metadata - /home/ubuntu/Downloads/ablib:/audiobooks_extra environment: - TZ=Asia/Kolkata - ROUTER_BASE_PATH=/ ``` and here's my nginx configuration ```nginx server { listen 8080; server_name audiobooks.lordofwizard.com; # SSL Certificates (uncomment when using Cloudflare Origin certs) # ssl_certificate /etc/ssl/cloudflare/origin.crt; # ssl_certificate_key /etc/ssl/cloudflare/origin.key; # Optional: add HSTS (only enable after verifying HTTPS works) # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; location / { proxy_pass http://127.0.0.1:6903; # --- WebSocket + Streaming Support --- proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # --- Header Forwarding --- proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # --- Timeouts (for long streams) --- proxy_connect_timeout 20s; proxy_read_timeout 3600s; proxy_send_timeout 3600s; # --- Buffers & Uploads --- proxy_buffers 16 16k; proxy_buffer_size 32k; client_max_body_size 1024M; # --- Handle Redirects properly --- proxy_redirect off; # --- Optional: error fallback (for better UX) --- error_page 502 503 504 /custom_50x.html; } # Optional static caching for cover art (improves loading) location /cover/ { proxy_pass http://127.0.0.1:6903/cover/; expires 30d; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; } } ``` <img width="1934" height="1346" alt="Image" src="https://github.com/user-attachments/assets/a4d0cc8f-10b2-433f-b1ee-95e17bb22307" />
Author
Owner

@lordofwizard commented on GitHub (Nov 9, 2025):

I fixed it turns out it was a issue with my host.

I am keeping a (AI gen doc) on what I did to solve it.

Date: November 9, 2025
Server: Oracle Cloud Ubuntu Server
Issue: Docker containers unable to establish SSL/TLS connections


🔴 Problem Summary

All Docker containers on the Oracle Ubuntu server were failing to establish SSL/TLS connections to external services (e.g., https://www.google.com), while the host system could connect without issues.

Error Message

curl: (60) SSL: no alternative certificate subject name matches target hostname 'www.google.com'

🔍 Root Cause Analysis

The Core Issue

An iptables NAT rule was redirecting ALL port 443 (HTTPS) traffic to port 8080, where an nginx reverse proxy was running with Cloudflare Origin certificates.

bash

# The problematic rule:
REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 redir ports 8080

What Was Happening

┌─────────────────────────────────────────────────────────────┐
│                     TRAFFIC FLOW                             │
├─────────────────────────────────────────────────────────────┤
│                                                               │
│  1. Docker Container                                          │
│     └─> Tries to connect to www.google.com:443              │
│                                                               │
│  2. iptables NAT Rule (PREROUTING chain)                     │
│     └─> Intercepts ALL port 443 traffic                     │
│     └─> Redirects to localhost:8080                         │
│                                                               │
│  3. Nginx Reverse Proxy (port 8080)                          │
│     └─> Receives the connection                             │
│     └─> Presents Cloudflare Origin Certificate              │
│     └─> Certificate CN: "CloudFlare Origin Certificate"     │
│                                                               │
│  4. Docker Container                                          │
│     └─> Expects: CN=www.google.com                          │
│     └─> Receives: CN=CloudFlare Origin Certificate          │
│     └─> CERTIFICATE MISMATCH → CONNECTION FAILS ❌           │
│                                                               │
└─────────────────────────────────────────────────────────────┘

Why Host Connections Worked

The iptables PREROUTING chain primarily affects:

  • Incoming traffic to the server
  • Traffic from Docker containers (which routes through the kernel's network stack)

It does NOT typically affect:

  • Outgoing connections from the host itself (uses OUTPUT chain, not PREROUTING)

This is why curl https://www.google.com from the host worked, but the same command from Docker containers failed.


🧪 Diagnostic Process

1. Initial Symptoms

bash

# Container test - FAILED
docker run --rm curlimages/curl:latest https://www.google.com
# Error: SSL certificate mismatch

# Host test - SUCCESS
curl -v https://www.google.com
# Connected successfully

2. Certificate Analysis

Container saw:

subject: O="CloudFlare, Inc."; OU=CloudFlare Origin CA; CN=CloudFlare Origin Certificate
issuer: C=US; O="CloudFlare, Inc."; OU=CloudFlare Origin SSL Certificate Authority

Host saw:

subject: CN=www.google.com
issuer: C=US; O=Google Trust Services; CN=WR2

3. Network Mode Test

bash

# Using host network mode - SUCCESS
docker run --rm --network host curlimages/curl:latest https://www.google.com
# This bypassed Docker's network isolation and the iptables rule

This confirmed the issue was with Docker's network routing, not certificates or DNS.

4. DNS Resolution Check

bash

docker exec nexus-audiobookshelf-1 sh -c "nslookup www.google.com"
# Result: 142.251.220.68 (correct Google IP)

DNS was working correctly, so the issue was happening after DNS resolution.

5. The Smoking Gun - iptables

bash

sudo iptables -t nat -L -n -v | grep 443
# Output:
33806 1766K REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 redir ports 8080

This rule was intercepting ALL HTTPS traffic and redirecting it to the nginx reverse proxy.


Solution

The Fix

Remove the blanket port 443 redirect and replace it with a more specific rule that only affects incoming traffic:

bash

# 1. Remove the problematic rule
sudo iptables -t nat -D PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 8080

# 2. Add a specific rule for incoming traffic only
sudo iptables -t nat -A PREROUTING -i enp0s10 -p tcp --dport 443 -j REDIRECT --to-ports 8080

# 3. Save the rules permanently
sudo netfilter-persistent save
# or
sudo iptables-save > /etc/iptables/rules.v4

What Changed

Before:

  • ALL port 443 traffic (incoming AND from Docker) → nginx
  • Docker containers couldn't make outbound HTTPS connections

After:

  • Only incoming traffic on interface enp0s10 port 443 → nginx
  • Docker containers' outbound HTTPS traffic → goes directly to destination
  • Reverse proxy still works for incoming requests

🎯 Key Learnings

1. iptables Chain Ordering Matters

PREROUTING → applies to:
  - Incoming packets
  - Packets from Docker containers (routing through host kernel)

OUTPUT → applies to:
  - Packets generated by host processes

2. Docker Network Isolation

Docker containers don't directly connect to the internet. Their traffic:

  1. Goes through Docker's network bridge
  2. Routes through the host kernel's network stack
  3. Gets processed by iptables rules (PREROUTING chain)
  4. Then exits through the host's network interface

3. Certificate Validation

SSL/TLS certificate validation checks:

  • Subject Alternative Name (SAN) or Common Name (CN) matches the hostname
  • Certificate is signed by a trusted CA
  • Certificate is not expired

When nginx intercepted the connection, it presented its own certificate (Cloudflare Origin), which didn't match www.google.com.

4. Testing Methodologies

Best practices for diagnosing Docker network issues:

bash

# 1. Test from host
curl -v https://example.com

# 2. Test from container with default network
docker run --rm curlimages/curl:latest -v https://example.com

# 3. Test from container with host network
docker run --rm --network host curlimages/curl:latest -v https://example.com

# 4. Compare certificates
openssl s_client -connect example.com:443 -servername example.com

# 5. Check iptables NAT rules
sudo iptables -t nat -L -n -v

# 6. Check DNS resolution in container
docker exec <container> nslookup example.com

📋 Server Configuration Context

Network Setup

  • Provider: Oracle Cloud Infrastructure
  • OS: Ubuntu
  • Network Interface: enp0s10
  • Internal IP: 10.0.0.203/24
  • Gateway: 10.0.0.1

Docker Configuration

json

{
  "dns": ["8.8.8.8", "1.1.1.1", "10.0.0.1"],
  "mtu": 1400,
  "iptables": true,
  "ip-forward": true,
  "userland-proxy": false
}

Nginx Reverse Proxy

  • Port: 8080 (with SSL using Cloudflare Origin certificates)
  • Purpose: Reverse proxy for multiple services
  • Services: Audiobookshelf, qBittorrent, Sonarr, Radarr, Prowlarr, Vaultwarden, etc.

Firewall Rules

Oracle Cloud Security Lists:

  • Ingress: 22, 80, 443, 8080, 8443, 6903, 8384, 6969
  • Egress: All protocols, all ports

UFW:

  • Allows all listed ports
  • Allows traffic from Docker subnet (172.17.0.0/16)

🚨 Red Herrings Investigated

During troubleshooting, these were investigated but were NOT the cause:

1. Missing CA Certificates

  • Tested: Mounting /etc/ssl/certs into containers
  • Result: No change
  • Reason: Certificates were fine; the wrong certificate was being presented

2. MTU Issues

  • Tested: Reduced MTU from 1500 to 1400
  • Result: No change
  • Reason: Packets were reaching destination; SSL handshake was the problem

3. Docker DNS Configuration

  • Tested: Multiple DNS servers (8.8.8.8, 1.1.1.1, Cloudflare)
  • Result: DNS resolution was working
  • Reason: Issue occurred after DNS resolution

4. Tailscale Exit Nodes

  • Suspected: Tailscale routing traffic through Cloudflare
  • Tested: Checked exit node configuration
  • Result: No exit nodes configured
  • Reason: Tailscale was not intercepting traffic

5. iptables-nft vs iptables-legacy

  • Suspected: Version mismatch causing issues
  • Result: Not the cause
  • Reason: iptables was working; the rule itself was the problem

6. Oracle Cloud Network Inspection

  • Suspected: OCI intercepting SSL
  • Result: OCI security lists were configured correctly
  • Reason: Issue was local to the server

🔧 Prevention

To Avoid This Issue in the Future

  1. Be specific with iptables rules:

bash

   # Bad - affects all traffic
   iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 8080
   
   # Good - only affects incoming traffic on specific interface
   iptables -t nat -A PREROUTING -i enp0s10 -p tcp --dport 443 -j REDIRECT --to-ports 8080
  1. Document iptables rules:
    • Keep a record of all custom iptables rules
    • Include comments explaining their purpose
    • Use iptables-save to backup rules
  2. Test Docker connectivity after firewall changes:

bash

   docker run --rm curlimages/curl:latest https://www.google.com
  1. Use Docker network modes appropriately:
    • bridge (default): Isolated network with port mapping
    • host: Uses host network stack (bypasses iptables PREROUTING)
    • none: No networking

📚 Technical References

iptables Chains and Tables

nat table:
  PREROUTING  → Packets arriving on network interface
  OUTPUT      → Packets generated by local processes
  POSTROUTING → Packets about to leave network interface

PREROUTING processes:
  - External incoming traffic
  - Traffic from Docker containers (they route through kernel)

OUTPUT processes:
  - Traffic from host processes (curl, wget, etc.)

Docker Networking

Docker containers using bridge mode:

  1. Container → Docker bridge (docker0)
  2. Bridge → Host kernel (iptables PREROUTING)
  3. Host kernel → Network interface
  4. Network interface → Internet

SSL/TLS Certificate Validation

Client validates:
  1. Certificate CN/SAN matches hostname
  2. Certificate signed by trusted CA
  3. Certificate not expired
  4. Certificate not revoked (optional OCSP check)

🎓 Commands Reference

Diagnostic Commands

bash

# Test SSL from container
docker run --rm curlimages/curl:latest -v https://www.google.com

# Check certificate presented to container
docker run --rm curlimages/curl:latest -v https://www.google.com 2>&1 | grep "subject:"

# View all iptables NAT rules
sudo iptables -t nat -L -n -v

# Check DNS resolution in container
docker exec <container> nslookup www.google.com

# Test with host network mode
docker run --rm --network host curlimages/curl:latest https://www.google.com

Fix Commands

bash

# Remove blanket redirect
sudo iptables -t nat -D PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 8080

# Add specific redirect for incoming traffic
sudo iptables -t nat -A PREROUTING -i enp0s10 -p tcp --dport 443 -j REDIRECT --to-ports 8080

# Save rules
sudo netfilter-persistent save

📝 Conclusion

This issue demonstrates the complexity of network routing in containerized environments. A seemingly simple iptables rule intended to redirect incoming HTTPS traffic to a reverse proxy inadvertently broke all outbound HTTPS connections from Docker containers.

Key Takeaway: Always scope iptables rules to specific interfaces and directions to avoid unintended side effects on container networking.

Resolution Time: ~1 hour of troubleshooting
Impact: All Docker containers unable to make HTTPS requests
Severity: High (blocks critical functionality like package updates, API calls, downloads)
Status: Resolved

@lordofwizard commented on GitHub (Nov 9, 2025): # I fixed it turns out it was a issue with my host. I am keeping a (AI gen doc) on what I did to solve it. **Date:** November 9, 2025 **Server:** Oracle Cloud Ubuntu Server **Issue:** Docker containers unable to establish SSL/TLS connections --- ## 🔴 Problem Summary All Docker containers on the Oracle Ubuntu server were failing to establish SSL/TLS connections to external services (e.g., `https://www.google.com`), while the host system could connect without issues. ### Error Message ``` curl: (60) SSL: no alternative certificate subject name matches target hostname 'www.google.com' ``` --- ## 🔍 Root Cause Analysis ### The Core Issue An **iptables NAT rule** was redirecting ALL port 443 (HTTPS) traffic to port 8080, where an nginx reverse proxy was running with Cloudflare Origin certificates. bash ```bash # The problematic rule: REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 redir ports 8080 ``` ### What Was Happening ``` ┌─────────────────────────────────────────────────────────────┐ │ TRAFFIC FLOW │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 1. Docker Container │ │ └─> Tries to connect to www.google.com:443 │ │ │ │ 2. iptables NAT Rule (PREROUTING chain) │ │ └─> Intercepts ALL port 443 traffic │ │ └─> Redirects to localhost:8080 │ │ │ │ 3. Nginx Reverse Proxy (port 8080) │ │ └─> Receives the connection │ │ └─> Presents Cloudflare Origin Certificate │ │ └─> Certificate CN: "CloudFlare Origin Certificate" │ │ │ │ 4. Docker Container │ │ └─> Expects: CN=www.google.com │ │ └─> Receives: CN=CloudFlare Origin Certificate │ │ └─> CERTIFICATE MISMATCH → CONNECTION FAILS ❌ │ │ │ └─────────────────────────────────────────────────────────────┘ ``` ### Why Host Connections Worked The iptables PREROUTING chain primarily affects: - **Incoming traffic** to the server - **Traffic from Docker containers** (which routes through the kernel's network stack) It does NOT typically affect: - **Outgoing connections from the host** itself (uses OUTPUT chain, not PREROUTING) This is why `curl https://www.google.com` from the host worked, but the same command from Docker containers failed. --- ## 🧪 Diagnostic Process ### 1. Initial Symptoms bash ```bash # Container test - FAILED docker run --rm curlimages/curl:latest https://www.google.com # Error: SSL certificate mismatch # Host test - SUCCESS curl -v https://www.google.com # Connected successfully ``` ### 2. Certificate Analysis **Container saw:** ``` subject: O="CloudFlare, Inc."; OU=CloudFlare Origin CA; CN=CloudFlare Origin Certificate issuer: C=US; O="CloudFlare, Inc."; OU=CloudFlare Origin SSL Certificate Authority ``` **Host saw:** ``` subject: CN=www.google.com issuer: C=US; O=Google Trust Services; CN=WR2 ``` ### 3. Network Mode Test bash ```bash # Using host network mode - SUCCESS docker run --rm --network host curlimages/curl:latest https://www.google.com # This bypassed Docker's network isolation and the iptables rule ``` This confirmed the issue was with **Docker's network routing**, not certificates or DNS. ### 4. DNS Resolution Check bash ```bash docker exec nexus-audiobookshelf-1 sh -c "nslookup www.google.com" # Result: 142.251.220.68 (correct Google IP) ``` DNS was working correctly, so the issue was happening **after** DNS resolution. ### 5. The Smoking Gun - iptables bash ```bash sudo iptables -t nat -L -n -v | grep 443 # Output: 33806 1766K REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 redir ports 8080 ``` This rule was intercepting ALL HTTPS traffic and redirecting it to the nginx reverse proxy. --- ## ✅ Solution ### The Fix Remove the blanket port 443 redirect and replace it with a more specific rule that only affects **incoming** traffic: bash ```bash # 1. Remove the problematic rule sudo iptables -t nat -D PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 8080 # 2. Add a specific rule for incoming traffic only sudo iptables -t nat -A PREROUTING -i enp0s10 -p tcp --dport 443 -j REDIRECT --to-ports 8080 # 3. Save the rules permanently sudo netfilter-persistent save # or sudo iptables-save > /etc/iptables/rules.v4 ``` ### What Changed **Before:** - ❌ ALL port 443 traffic (incoming AND from Docker) → nginx - ❌ Docker containers couldn't make outbound HTTPS connections **After:** - ✅ Only incoming traffic on interface `enp0s10` port 443 → nginx - ✅ Docker containers' outbound HTTPS traffic → goes directly to destination - ✅ Reverse proxy still works for incoming requests --- ## 🎯 Key Learnings ### 1. iptables Chain Ordering Matters ``` PREROUTING → applies to: - Incoming packets - Packets from Docker containers (routing through host kernel) OUTPUT → applies to: - Packets generated by host processes ``` ### 2. Docker Network Isolation Docker containers don't directly connect to the internet. Their traffic: 1. Goes through Docker's network bridge 2. Routes through the host kernel's network stack 3. Gets processed by iptables rules (PREROUTING chain) 4. Then exits through the host's network interface ### 3. Certificate Validation SSL/TLS certificate validation checks: - **Subject Alternative Name (SAN)** or **Common Name (CN)** matches the hostname - Certificate is signed by a trusted CA - Certificate is not expired When nginx intercepted the connection, it presented its own certificate (Cloudflare Origin), which didn't match `www.google.com`. ### 4. Testing Methodologies **Best practices for diagnosing Docker network issues:** bash ```bash # 1. Test from host curl -v https://example.com # 2. Test from container with default network docker run --rm curlimages/curl:latest -v https://example.com # 3. Test from container with host network docker run --rm --network host curlimages/curl:latest -v https://example.com # 4. Compare certificates openssl s_client -connect example.com:443 -servername example.com # 5. Check iptables NAT rules sudo iptables -t nat -L -n -v # 6. Check DNS resolution in container docker exec <container> nslookup example.com ``` --- ## 📋 Server Configuration Context ### Network Setup - **Provider:** Oracle Cloud Infrastructure - **OS:** Ubuntu - **Network Interface:** enp0s10 - **Internal IP:** 10.0.0.203/24 - **Gateway:** 10.0.0.1 ### Docker Configuration json ```json { "dns": ["8.8.8.8", "1.1.1.1", "10.0.0.1"], "mtu": 1400, "iptables": true, "ip-forward": true, "userland-proxy": false } ``` ### Nginx Reverse Proxy - **Port:** 8080 (with SSL using Cloudflare Origin certificates) - **Purpose:** Reverse proxy for multiple services - **Services:** Audiobookshelf, qBittorrent, Sonarr, Radarr, Prowlarr, Vaultwarden, etc. ### Firewall Rules **Oracle Cloud Security Lists:** - Ingress: 22, 80, 443, 8080, 8443, 6903, 8384, 6969 - Egress: All protocols, all ports **UFW:** - Allows all listed ports - Allows traffic from Docker subnet (172.17.0.0/16) --- ## 🚨 Red Herrings Investigated During troubleshooting, these were investigated but were NOT the cause: ### 1. ❌ Missing CA Certificates - Tested: Mounting `/etc/ssl/certs` into containers - Result: No change - Reason: Certificates were fine; the wrong certificate was being presented ### 2. ❌ MTU Issues - Tested: Reduced MTU from 1500 to 1400 - Result: No change - Reason: Packets were reaching destination; SSL handshake was the problem ### 3. ❌ Docker DNS Configuration - Tested: Multiple DNS servers (8.8.8.8, 1.1.1.1, Cloudflare) - Result: DNS resolution was working - Reason: Issue occurred after DNS resolution ### 4. ❌ Tailscale Exit Nodes - Suspected: Tailscale routing traffic through Cloudflare - Tested: Checked exit node configuration - Result: No exit nodes configured - Reason: Tailscale was not intercepting traffic ### 5. ❌ iptables-nft vs iptables-legacy - Suspected: Version mismatch causing issues - Result: Not the cause - Reason: iptables was working; the rule itself was the problem ### 6. ❌ Oracle Cloud Network Inspection - Suspected: OCI intercepting SSL - Result: OCI security lists were configured correctly - Reason: Issue was local to the server --- ## 🔧 Prevention ### To Avoid This Issue in the Future 1. **Be specific with iptables rules:** bash ```bash # Bad - affects all traffic iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 8080 # Good - only affects incoming traffic on specific interface iptables -t nat -A PREROUTING -i enp0s10 -p tcp --dport 443 -j REDIRECT --to-ports 8080 ``` 2. **Document iptables rules:** - Keep a record of all custom iptables rules - Include comments explaining their purpose - Use `iptables-save` to backup rules 3. **Test Docker connectivity after firewall changes:** bash ```bash docker run --rm curlimages/curl:latest https://www.google.com ``` 4. **Use Docker network modes appropriately:** - `bridge` (default): Isolated network with port mapping - `host`: Uses host network stack (bypasses iptables PREROUTING) - `none`: No networking --- ## 📚 Technical References ### iptables Chains and Tables ``` nat table: PREROUTING → Packets arriving on network interface OUTPUT → Packets generated by local processes POSTROUTING → Packets about to leave network interface PREROUTING processes: - External incoming traffic - Traffic from Docker containers (they route through kernel) OUTPUT processes: - Traffic from host processes (curl, wget, etc.) ``` ### Docker Networking Docker containers using bridge mode: 1. Container → Docker bridge (docker0) 2. Bridge → Host kernel (iptables PREROUTING) 3. Host kernel → Network interface 4. Network interface → Internet ### SSL/TLS Certificate Validation ``` Client validates: 1. Certificate CN/SAN matches hostname 2. Certificate signed by trusted CA 3. Certificate not expired 4. Certificate not revoked (optional OCSP check) ``` --- ## 🎓 Commands Reference ### Diagnostic Commands bash ```bash # Test SSL from container docker run --rm curlimages/curl:latest -v https://www.google.com # Check certificate presented to container docker run --rm curlimages/curl:latest -v https://www.google.com 2>&1 | grep "subject:" # View all iptables NAT rules sudo iptables -t nat -L -n -v # Check DNS resolution in container docker exec <container> nslookup www.google.com # Test with host network mode docker run --rm --network host curlimages/curl:latest https://www.google.com ``` ### Fix Commands bash ```bash # Remove blanket redirect sudo iptables -t nat -D PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 8080 # Add specific redirect for incoming traffic sudo iptables -t nat -A PREROUTING -i enp0s10 -p tcp --dport 443 -j REDIRECT --to-ports 8080 # Save rules sudo netfilter-persistent save ``` --- ## 📝 Conclusion This issue demonstrates the complexity of network routing in containerized environments. A seemingly simple iptables rule intended to redirect incoming HTTPS traffic to a reverse proxy inadvertently broke all outbound HTTPS connections from Docker containers. **Key Takeaway:** Always scope iptables rules to specific interfaces and directions to avoid unintended side effects on container networking. **Resolution Time:** ~1 hour of troubleshooting **Impact:** All Docker containers unable to make HTTPS requests **Severity:** High (blocks critical functionality like package updates, API calls, downloads) **Status:** ✅ Resolved
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/audiobookshelf-advplyr#2918
No description provided.