From 0357d172058ceda7d49a0c18c13009e0031e034d Mon Sep 17 00:00:00 2001 From: Gauthier Date: Tue, 17 Jun 2025 21:35:52 +0200 Subject: [PATCH] feat: add force ipv4 first setting (#1719) This PR adds a 'Force IPv4' setting in the network settings, like the one that existed before we migrated from Fetch API to Axios. --- docs/troubleshooting.mdx | 6 ++++ pnpm-lock.yaml | 4 +-- server/index.ts | 8 ++++++ server/lib/settings/index.ts | 2 ++ .../Settings/SettingsNetwork/index.tsx | 28 +++++++++++++++++++ src/i18n/locale/en.json | 5 +++- 6 files changed, 50 insertions(+), 3 deletions(-) diff --git a/docs/troubleshooting.mdx b/docs/troubleshooting.mdx index ec368da7e..a79b316b9 100644 --- a/docs/troubleshooting.mdx +++ b/docs/troubleshooting.mdx @@ -105,6 +105,12 @@ In some places (like China), the ISP blocks not only the DNS resolution but also You can configure Jellyseerr to use a proxy with the [HTTP(S) Proxy](/using-jellyseerr/settings/general#https-proxy) setting. +### Option 3: Force IPV4 resolution first + +Sometimes there are configuration issues with IPV6 that prevent the hostname resolution from working correctly. + +You can try to force the resolution to use IPV4 first by going to `Settings > Networking > Advanced Networking` and enabling `Force IPv4 Resolution First` setting and restarting Jellyseerr. + ### Option 4: Check that your server can reach TMDB API Make sure that your server can reach the TMDB API by running the following command: diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 812cfd385..8f32923f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15811,7 +15811,7 @@ snapshots: debug: 4.3.5 enhanced-resolve: 5.17.0 eslint: 8.35.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.35.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.35.0))(eslint@8.35.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.54.0(eslint@8.35.0)(typescript@4.9.5))(eslint@8.35.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 @@ -15833,7 +15833,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.35.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.35.0)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.35.0))(eslint@8.35.0): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: diff --git a/server/index.ts b/server/index.ts index abb98be60..f8819f520 100644 --- a/server/index.ts +++ b/server/index.ts @@ -28,6 +28,7 @@ import { getAppVersion } from '@server/utils/appVersion'; import createCustomProxyAgent from '@server/utils/customProxyAgent'; import restartFlag from '@server/utils/restartFlag'; import { getClientIp } from '@supercharge/request-ip'; +import axios from 'axios'; import { TypeormStore } from 'connect-typeorm/out'; import cookieParser from 'cookie-parser'; import type { NextFunction, Request, Response } from 'express'; @@ -35,6 +36,8 @@ import express from 'express'; import * as OpenApiValidator from 'express-openapi-validator'; import type { Store } from 'express-session'; import session from 'express-session'; +import http from 'http'; +import https from 'https'; import next from 'next'; import path from 'path'; import swaggerUi from 'swagger-ui-express'; @@ -73,6 +76,11 @@ app const settings = await getSettings().load(); restartFlag.initializeSettings(settings); + if (settings.network.forceIpv4First) { + axios.defaults.httpAgent = new http.Agent({ family: 4 }); + axios.defaults.httpsAgent = new https.Agent({ family: 4 }); + } + // Register HTTP proxy if (settings.network.proxy.enabled) { await createCustomProxyAgent(settings.network.proxy); diff --git a/server/lib/settings/index.ts b/server/lib/settings/index.ts index 490b926a7..e2274f97b 100644 --- a/server/lib/settings/index.ts +++ b/server/lib/settings/index.ts @@ -140,6 +140,7 @@ export interface MainSettings { export interface NetworkSettings { csrfProtection: boolean; + forceIpv4First: boolean; trustProxy: boolean; proxy: ProxySettings; } @@ -544,6 +545,7 @@ class Settings { }, network: { csrfProtection: false, + forceIpv4First: false, trustProxy: false, proxy: { enabled: false, diff --git a/src/components/Settings/SettingsNetwork/index.tsx b/src/components/Settings/SettingsNetwork/index.tsx index 57e6f5258..e02b7bfc6 100644 --- a/src/components/Settings/SettingsNetwork/index.tsx +++ b/src/components/Settings/SettingsNetwork/index.tsx @@ -42,6 +42,9 @@ const messages = defineMessages('components.Settings.SettingsNetwork', { networkDisclaimer: 'Network parameters from your container/system should be used instead of these settings. See the {docs} for more information.', docs: 'documentation', + forceIpv4First: 'Force IPv4 Resolution First', + forceIpv4FirstTip: + 'Force Jellyseerr to resolve IPv4 addresses first instead of IPv6', }); const SettingsNetwork = () => { @@ -86,6 +89,7 @@ const SettingsNetwork = () => { { try { await axios.post('/api/v1/settings/network', { csrfProtection: values.csrfProtection, + forceIpv4First: values.forceIpv4First, trustProxy: values.trustProxy, proxy: { enabled: values.proxyEnabled, @@ -193,6 +198,29 @@ const SettingsNetwork = () => { +
+ +
+ { + setFieldValue('forceIpv4First', !values.forceIpv4First); + }} + /> +
+