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.
This commit is contained in:
@@ -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.
|
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
|
### 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:
|
Make sure that your server can reach the TMDB API by running the following command:
|
||||||
|
|||||||
4
pnpm-lock.yaml
generated
4
pnpm-lock.yaml
generated
@@ -15811,7 +15811,7 @@ snapshots:
|
|||||||
debug: 4.3.5
|
debug: 4.3.5
|
||||||
enhanced-resolve: 5.17.0
|
enhanced-resolve: 5.17.0
|
||||||
eslint: 8.35.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)
|
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
|
fast-glob: 3.3.2
|
||||||
get-tsconfig: 4.7.5
|
get-tsconfig: 4.7.5
|
||||||
@@ -15833,7 +15833,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- 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:
|
dependencies:
|
||||||
debug: 3.2.7(supports-color@8.1.1)
|
debug: 3.2.7(supports-color@8.1.1)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { getAppVersion } from '@server/utils/appVersion';
|
|||||||
import createCustomProxyAgent from '@server/utils/customProxyAgent';
|
import createCustomProxyAgent from '@server/utils/customProxyAgent';
|
||||||
import restartFlag from '@server/utils/restartFlag';
|
import restartFlag from '@server/utils/restartFlag';
|
||||||
import { getClientIp } from '@supercharge/request-ip';
|
import { getClientIp } from '@supercharge/request-ip';
|
||||||
|
import axios from 'axios';
|
||||||
import { TypeormStore } from 'connect-typeorm/out';
|
import { TypeormStore } from 'connect-typeorm/out';
|
||||||
import cookieParser from 'cookie-parser';
|
import cookieParser from 'cookie-parser';
|
||||||
import type { NextFunction, Request, Response } from 'express';
|
import type { NextFunction, Request, Response } from 'express';
|
||||||
@@ -35,6 +36,8 @@ import express from 'express';
|
|||||||
import * as OpenApiValidator from 'express-openapi-validator';
|
import * as OpenApiValidator from 'express-openapi-validator';
|
||||||
import type { Store } from 'express-session';
|
import type { Store } from 'express-session';
|
||||||
import session from 'express-session';
|
import session from 'express-session';
|
||||||
|
import http from 'http';
|
||||||
|
import https from 'https';
|
||||||
import next from 'next';
|
import next from 'next';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import swaggerUi from 'swagger-ui-express';
|
import swaggerUi from 'swagger-ui-express';
|
||||||
@@ -73,6 +76,11 @@ app
|
|||||||
const settings = await getSettings().load();
|
const settings = await getSettings().load();
|
||||||
restartFlag.initializeSettings(settings);
|
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
|
// Register HTTP proxy
|
||||||
if (settings.network.proxy.enabled) {
|
if (settings.network.proxy.enabled) {
|
||||||
await createCustomProxyAgent(settings.network.proxy);
|
await createCustomProxyAgent(settings.network.proxy);
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ export interface MainSettings {
|
|||||||
|
|
||||||
export interface NetworkSettings {
|
export interface NetworkSettings {
|
||||||
csrfProtection: boolean;
|
csrfProtection: boolean;
|
||||||
|
forceIpv4First: boolean;
|
||||||
trustProxy: boolean;
|
trustProxy: boolean;
|
||||||
proxy: ProxySettings;
|
proxy: ProxySettings;
|
||||||
}
|
}
|
||||||
@@ -544,6 +545,7 @@ class Settings {
|
|||||||
},
|
},
|
||||||
network: {
|
network: {
|
||||||
csrfProtection: false,
|
csrfProtection: false,
|
||||||
|
forceIpv4First: false,
|
||||||
trustProxy: false,
|
trustProxy: false,
|
||||||
proxy: {
|
proxy: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ const messages = defineMessages('components.Settings.SettingsNetwork', {
|
|||||||
networkDisclaimer:
|
networkDisclaimer:
|
||||||
'Network parameters from your container/system should be used instead of these settings. See the {docs} for more information.',
|
'Network parameters from your container/system should be used instead of these settings. See the {docs} for more information.',
|
||||||
docs: 'documentation',
|
docs: 'documentation',
|
||||||
|
forceIpv4First: 'Force IPv4 Resolution First',
|
||||||
|
forceIpv4FirstTip:
|
||||||
|
'Force Jellyseerr to resolve IPv4 addresses first instead of IPv6',
|
||||||
});
|
});
|
||||||
|
|
||||||
const SettingsNetwork = () => {
|
const SettingsNetwork = () => {
|
||||||
@@ -86,6 +89,7 @@ const SettingsNetwork = () => {
|
|||||||
<Formik
|
<Formik
|
||||||
initialValues={{
|
initialValues={{
|
||||||
csrfProtection: data?.csrfProtection,
|
csrfProtection: data?.csrfProtection,
|
||||||
|
forceIpv4First: data?.forceIpv4First,
|
||||||
trustProxy: data?.trustProxy,
|
trustProxy: data?.trustProxy,
|
||||||
proxyEnabled: data?.proxy?.enabled,
|
proxyEnabled: data?.proxy?.enabled,
|
||||||
proxyHostname: data?.proxy?.hostname,
|
proxyHostname: data?.proxy?.hostname,
|
||||||
@@ -102,6 +106,7 @@ const SettingsNetwork = () => {
|
|||||||
try {
|
try {
|
||||||
await axios.post('/api/v1/settings/network', {
|
await axios.post('/api/v1/settings/network', {
|
||||||
csrfProtection: values.csrfProtection,
|
csrfProtection: values.csrfProtection,
|
||||||
|
forceIpv4First: values.forceIpv4First,
|
||||||
trustProxy: values.trustProxy,
|
trustProxy: values.trustProxy,
|
||||||
proxy: {
|
proxy: {
|
||||||
enabled: values.proxyEnabled,
|
enabled: values.proxyEnabled,
|
||||||
@@ -193,6 +198,29 @@ const SettingsNetwork = () => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="form-row">
|
||||||
|
<label htmlFor="forceIpv4First" className="checkbox-label">
|
||||||
|
<span className="mr-2">
|
||||||
|
{intl.formatMessage(messages.forceIpv4First)}
|
||||||
|
</span>
|
||||||
|
<SettingsBadge badgeType="advanced" className="mr-2" />
|
||||||
|
<SettingsBadge badgeType="restartRequired" />
|
||||||
|
<SettingsBadge badgeType="experimental" />
|
||||||
|
<span className="label-tip">
|
||||||
|
{intl.formatMessage(messages.forceIpv4FirstTip)}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<div className="form-input-area">
|
||||||
|
<Field
|
||||||
|
type="checkbox"
|
||||||
|
id="forceIpv4First"
|
||||||
|
name="forceIpv4First"
|
||||||
|
onChange={() => {
|
||||||
|
setFieldValue('forceIpv4First', !values.forceIpv4First);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<label htmlFor="proxyEnabled" className="checkbox-label">
|
<label htmlFor="proxyEnabled" className="checkbox-label">
|
||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
|
|||||||
@@ -978,10 +978,13 @@
|
|||||||
"components.Settings.SettingsMain.validationUrl": "You must provide a valid URL",
|
"components.Settings.SettingsMain.validationUrl": "You must provide a valid URL",
|
||||||
"components.Settings.SettingsMain.validationUrlTrailingSlash": "URL must not end in a trailing slash",
|
"components.Settings.SettingsMain.validationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||||
"components.Settings.SettingsMain.youtubeUrl": "YouTube URL",
|
"components.Settings.SettingsMain.youtubeUrl": "YouTube URL",
|
||||||
|
"components.Settings.SettingsMain.youtubeUrlTip": "Base URL for YouTube videos if a self-hosted YouTube instance is used.",
|
||||||
"components.Settings.SettingsNetwork.csrfProtection": "Enable CSRF Protection",
|
"components.Settings.SettingsNetwork.csrfProtection": "Enable CSRF Protection",
|
||||||
"components.Settings.SettingsNetwork.csrfProtectionHoverTip": "Do NOT enable this setting unless you understand what you are doing!",
|
"components.Settings.SettingsNetwork.csrfProtectionHoverTip": "Do NOT enable this setting unless you understand what you are doing!",
|
||||||
"components.Settings.SettingsNetwork.csrfProtectionTip": "Set external API access to read-only (requires HTTPS)",
|
"components.Settings.SettingsNetwork.csrfProtectionTip": "Set external API access to read-only (requires HTTPS)",
|
||||||
"components.Settings.SettingsNetwork.docs": "documentation",
|
"components.Settings.SettingsNetwork.docs": "documentation",
|
||||||
|
"components.Settings.SettingsNetwork.forceIpv4First": "Force IPv4 Resolution First",
|
||||||
|
"components.Settings.SettingsNetwork.forceIpv4FirstTip": "Force Jellyseerr to resolve IPv4 addresses first instead of IPv6",
|
||||||
"components.Settings.SettingsNetwork.network": "Network",
|
"components.Settings.SettingsNetwork.network": "Network",
|
||||||
"components.Settings.SettingsNetwork.networkDisclaimer": "Network parameters from your container/system should be used instead of these settings. See the {docs} for more information.",
|
"components.Settings.SettingsNetwork.networkDisclaimer": "Network parameters from your container/system should be used instead of these settings. See the {docs} for more information.",
|
||||||
"components.Settings.SettingsNetwork.networksettings": "Network Settings",
|
"components.Settings.SettingsNetwork.networksettings": "Network Settings",
|
||||||
@@ -1213,7 +1216,7 @@
|
|||||||
"components.Setup.librarieserror": "Validation failed. Please toggle the libraries again to continue.",
|
"components.Setup.librarieserror": "Validation failed. Please toggle the libraries again to continue.",
|
||||||
"components.Setup.servertype": "Choose Server Type",
|
"components.Setup.servertype": "Choose Server Type",
|
||||||
"components.Setup.setup": "Setup",
|
"components.Setup.setup": "Setup",
|
||||||
"components.Setup.signin": "Sign in to your account",
|
"components.Setup.signin": "Sign In",
|
||||||
"components.Setup.signinMessage": "Get started by signing in",
|
"components.Setup.signinMessage": "Get started by signing in",
|
||||||
"components.Setup.signinWithEmby": "Enter your Emby details",
|
"components.Setup.signinWithEmby": "Enter your Emby details",
|
||||||
"components.Setup.signinWithJellyfin": "Enter your Jellyfin details",
|
"components.Setup.signinWithJellyfin": "Enter your Jellyfin details",
|
||||||
|
|||||||
Reference in New Issue
Block a user