Compare commits

...

2 Commits

Author SHA1 Message Date
fallenbagel
1955db5c35 docs: add documentation for unix socket postgres connection 2025-01-12 12:13:07 +08:00
fallenbagel
ee803b601c refactor: adds socket_path for unix socket support for postgres 2025-01-12 12:12:23 +08:00
6 changed files with 223 additions and 136 deletions

View File

@@ -9,6 +9,8 @@ Jellyseerr supports SQLite and PostgreSQL. The database connection can be config
## SQLite Options ## SQLite Options
If you want to use SQLite, you can simply set the `DB_TYPE` environment variable to `sqlite`. This is the default configuration so even if you don't set any other options, SQLite will be used.
```dotenv ```dotenv
DB_TYPE="sqlite" # Which DB engine to use, either "sqlite" or "postgres". The default is "sqlite". DB_TYPE="sqlite" # Which DB engine to use, either "sqlite" or "postgres". The default is "sqlite".
CONFIG_DIRECTORY="config" # (optional) The path to the config directory where the db file is stored. The default is "config". CONFIG_DIRECTORY="config" # (optional) The path to the config directory where the db file is stored. The default is "config".
@@ -17,17 +19,35 @@ DB_LOG_QUERIES="false" # (optional) Whether to log the DB queries for debugging.
## PostgreSQL Options ## PostgreSQL Options
### TCP Connection
If your PostgreSQL server is configured to accept TCP connections, you can specify the host and port using the `DB_HOST` and `DB_PORT` environment variables. This is useful for remote connections where the server uses a network host and port.
```dotenv ```dotenv
DB_TYPE="postgres" # Which DB engine to use, either "sqlite" or "postgres". The default is "sqlite". To use postgres, this needs to be set to "postgres" DB_TYPE="postgres" # Which DB engine to use, either "sqlite" or "postgres". The default is "sqlite".
DB_HOST="localhost" # (optional) The host (url) of the database. The default is "localhost". DB_HOST="localhost" # (optional) The host (URL) of the database. The default is "localhost".
DB_PORT="5432" # (optional) The port to connect to. The default is "5432". DB_PORT="5432" # (optional) The port to connect to. The default is "5432".
DB_USER= # (required) Username used to connect to the database DB_USER= # (required) Username used to connect to the database.
DB_PASS= # (required) Password of the user used to connect to the database DB_PASS= # (required) Password of the user used to connect to the database.
DB_NAME="jellyseerr" # (optional) The name of the database to connect to. The default is "jellyseerr".
DB_LOG_QUERIES="false" # (optional) Whether to log the DB queries for debugging. The default is "false".
```
### Unix Socket Connection
If your PostgreSQL server is configured to accept Unix socket connections, you can specify the path to the socket directory using the `DB_SOCKET_PATH` environment variable. This is useful for local connections where the server uses a Unix socket.
```dotenv
DB_TYPE="postgres" # Which DB engine to use, either "sqlite" or "postgres". The default is "sqlite".
DB_SOCKET_PATH="/var/run/postgresql" # (required) The path to the PostgreSQL Unix socket directory.
DB_USER= # (required) Username used to connect to the database.
DB_PASS= # (optional) Password of the user used to connect to the database, depending on the server's authentication configuration.
DB_NAME="jellyseerr" # (optional) The name of the database to connect to. The default is "jellyseerr". DB_NAME="jellyseerr" # (optional) The name of the database to connect to. The default is "jellyseerr".
DB_LOG_QUERIES="false" # (optional) Whether to log the DB queries for debugging. The default is "false". DB_LOG_QUERIES="false" # (optional) Whether to log the DB queries for debugging. The default is "false".
``` ```
### SSL configuration ### SSL configuration
The following options can be used to further configure ssl. Certificates can be provided as a string or a file path, with the string version taking precedence. The following options can be used to further configure ssl. Certificates can be provided as a string or a file path, with the string version taking precedence.
```dotenv ```dotenv
@@ -40,6 +60,7 @@ DB_SSL_KEY_FILE= # (optinal) Path to the private key for the connection in PEM f
DB_SSL_CERT= # (optional) Certificate chain in pem format for the private key, provided as a string. The default is "". DB_SSL_CERT= # (optional) Certificate chain in pem format for the private key, provided as a string. The default is "".
DB_SSL_CERT_FILE= # (optional) Path to certificate chain in pem format for the private key. The default is "". DB_SSL_CERT_FILE= # (optional) Path to certificate chain in pem format for the private key. The default is "".
``` ```
---
### Migrating from SQLite to PostgreSQL ### Migrating from SQLite to PostgreSQL
@@ -48,7 +69,7 @@ DB_SSL_CERT_FILE= # (optional) Path to certificate chain in pem format for the p
3. Stop Jellyseerr 3. Stop Jellyseerr
4. Run the following command to export the data from the SQLite database and import it into the PostgreSQL database: 4. Run the following command to export the data from the SQLite database and import it into the PostgreSQL database:
:::info :::info
Edit the postgres connection string to match your setup Edit the postgres connection string to match your setup.
If you don't have or don't want to use docker, you can build the working pgloader version [in this PR](https://github.com/dimitri/pgloader/pull/1531) from source and use the same options as below. If you don't have or don't want to use docker, you can build the working pgloader version [in this PR](https://github.com/dimitri/pgloader/pull/1531) from source and use the same options as below.
::: :::

View File

@@ -6,6 +6,8 @@ sidebar_position: 2
# Build from Source (Advanced) # Build from Source (Advanced)
:::warning :::warning
This method is not recommended for most users. It is intended for advanced users who are familiar with managing their own server infrastructure. This method is not recommended for most users. It is intended for advanced users who are familiar with managing their own server infrastructure.
Refer to [Configuring Databases](/extending-jellyseerr/database-config#postgresql-options) for details on how to configure your database.
::: :::
import Tabs from '@theme/Tabs'; import Tabs from '@theme/Tabs';

View File

@@ -7,6 +7,8 @@ sidebar_position: 1
:::info :::info
This is the recommended method for most users. This is the recommended method for most users.
Details on how to install Docker can be found on the [official Docker website](https://docs.docker.com/get-docker/). Details on how to install Docker can be found on the [official Docker website](https://docs.docker.com/get-docker/).
Refer to [Configuring Databases](/extending-jellyseerr/database-config#postgresql-options) for details on how to configure your database.
::: :::
## Unix (Linux, macOS) ## Unix (Linux, macOS)

View File

@@ -6,6 +6,8 @@ sidebar_position: 3
import { JellyseerrVersion, NixpkgVersion } from '@site/src/components/JellyseerrVersion'; import { JellyseerrVersion, NixpkgVersion } from '@site/src/components/JellyseerrVersion';
import Admonition from '@theme/Admonition'; import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# Nix Package Manager (Advanced) # Nix Package Manager (Advanced)
:::info :::info
@@ -13,22 +15,55 @@ This method is not recommended for most users. It is intended for advanced users
::: :::
export const VersionMismatchWarning = () => { export const VersionMismatchWarning = () => {
const jellyseerrVersion = JellyseerrVersion(); let jellyseerrVersion = null;
const nixpkgVersion = NixpkgVersion(); let nixpkgVersions = null;
try {
jellyseerrVersion = JellyseerrVersion();
nixpkgVersions = NixpkgVersion();
} catch (err) {
return (
<Admonition type="error">
Failed to load version information. Error: {err.message || JSON.stringify(err)}
</Admonition>
);
}
const isUpToDate = jellyseerrVersion === nixpkgVersion; if (!nixpkgVersions || nixpkgVersions.error) {
return (
<Admonition type="error">
Failed to fetch Nixpkg versions: {nixpkgVersions?.error || 'Unknown error'}
</Admonition>
);
}
const isUnstableUpToDate = jellyseerrVersion === nixpkgVersions.unstable;
const isStableUpToDate = jellyseerrVersion === nixpkgVersions.stable;
return ( return (
<> <>
{!isUpToDate ? ( {!isStableUpToDate ? (
<Admonition type="warning"> <Admonition type="warning">
The <a href="https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/servers/jellyseerr/default.nix#L14">upstream Jellyseerr Nix Package (v{nixpkgVersion})</a> is not <b>up-to-date</b>. If you want to use <b>Jellyseerr v{jellyseerrVersion}</b>, you will need to <a href="#overriding-the-package-derivation">override the package derivation</a>. The{' '}
</Admonition> <a href="https://github.com/NixOS/nixpkgs/blob/nixos-24.11/pkgs/servers/jellyseerr/default.nix#L14">
) : ( upstream Jellyseerr Nix Package (v{nixpkgVersions.stable})
<Admonition type="success"> </a>{' '}
The <a href="https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/servers/jellyseerr/default.nix#L14">upstream Jellyseerr Nix Package (v{nixpkgVersion})</a> is <b>up-to-date</b> with <b>Jellyseerr v{jellyseerrVersion}</b>. is not <b>up-to-date</b>. If you want to use <b>Jellyseerr v{jellyseerrVersion}</b>,{' '}
</Admonition> {isUnstableUpToDate ? (
)} <>
consider using the{' '}
<a href="https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/je/jellyseerr/package.nix">
unstable package
</a>{' '}
instead.
</>
) : (
<>
you will need to{' '}
<a href="#overriding-the-package-derivation">override the package derivation</a>.
</>
)}
</Admonition>
) : null}
</> </>
); );
}; };
@@ -48,6 +83,8 @@ To get up and running with jellyseerr using Nix, you can add the following to yo
If you want more advanced configuration options, you can use the following: If you want more advanced configuration options, you can use the following:
<Tabs groupId="nixpkg-methods" queryString>
<TabItem value="default" label="Default Configurations">
```nix ```nix
{ config, pkgs, ... }: { config, pkgs, ... }:
@@ -56,53 +93,20 @@ If you want more advanced configuration options, you can use the following:
enable = true; enable = true;
port = 5055; port = 5055;
openFirewall = true; openFirewall = true;
package = pkgs.jellyseerr; # Use the unstable package if stable is not up-to-date
}; };
} }
``` ```
</TabItem>
After adding the configuration to your `configuration.nix`, you can run the following command to install jellyseerr: <TabItem value="custom" label="Database Configurations">
In order to use postgres, you will need to add override the default module of jellyseerr with the following as the current default module is not compatible with postgres:
```bash ```nix
nixos-rebuild switch
```
After rebuild is complete jellyseerr should be running, verify that it is with the following command.
```bash
systemctl status jellyseerr
```
:::info
You can now access Jellyseerr by visiting `http://localhost:5055` in your web browser.
:::
import CodeBlock from '@theme/CodeBlock';
## Overriding the package derivation
export const VersionMatch = () => {
const jellyseerrVersion = JellyseerrVersion();
const nixpkgVersion = NixpkgVersion();
const code = `{ config, pkgs, ... }:
{ {
nixpkgs.config.packageOverrides = pkgs: { config,
jellyseerr = pkgs.jellyseerr.overrideAttrs (oldAttrs: rec { pkgs,
version = "${jellyseerrVersion}"; lib,
...
src = pkgs.fetchFromGitHub { }:
rev = "v\${version}";
sha256 = pkgs.lib.fakeSha256;
};
offlineCache = pkgs.fetchYarnDeps {
sha256 = pkgs.lib.fakeSha256;
};
});
};
}`;
const module = `{ config, pkgs, lib, ... }:
with lib; with lib;
let let
cfg = config.services.jellyseerr; cfg = config.services.jellyseerr;
@@ -113,28 +117,65 @@ in
disabledModules = [ "services/misc/jellyseerr.nix" ]; disabledModules = [ "services/misc/jellyseerr.nix" ];
options.services.jellyseerr = { options.services.jellyseerr = {
enable = mkEnableOption (mdDoc ''Jellyseerr, a requests manager for Jellyfin''); enable = mkEnableOption ''Jellyseerr, a requests manager for Jellyfin'';
openFirewall = mkOption { openFirewall = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc ''Open port in the firewall for the Jellyseerr web interface.''; description = ''Open port in the firewall for the Jellyseerr web interface.'';
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 5055; default = 5055;
description = mdDoc ''The port which the Jellyseerr web UI should listen to.''; description = ''The port which the Jellyseerr web UI should listen to.'';
}; };
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = pkgs.jellyseerr; default = pkgs.jellyseerr;
defaultText = literalExpression "pkgs.jellyseerr"; defaultText = literalExpression "pkgs.jellyseerr";
description = lib.mdDoc '' description = ''
Jellyseerr package to use. Jellyseerr package to use.
''; '';
};
databaseConfig = mkOption {
type = types.attrsOf types.str;
default = {
type = "sqlite";
configDirectory = "config";
logQueries = "false";
}; };
description = ''
Database configuration. For "sqlite", only "type", "configDirectory", and "logQueries" are relevant.
For "postgres", include host, port, user, pass, name, and optionally socket.
Example:
{
type = "postgres";
socket = "/run/postgresql";
user = "jellyseerr";
name = "jellyseerr";
logQueries = "false";
}
or
{
type = "postgres";
host = "localhost";
port = "5432";
user = "dbuser";
pass = "password";
name = "jellyseerr";
logQueries = "false";
}
or
{
type = "sqlite";
configDirectory = "config";
logQueries = "false";
}
'';
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@@ -142,14 +183,29 @@ in
description = "Jellyseerr, a requests manager for Jellyfin"; description = "Jellyseerr, a requests manager for Jellyfin";
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
environment.PORT = toString cfg.port; environment =
let
dbConfig = cfg.databaseConfig;
in
{
PORT = toString cfg.port;
DB_TYPE = toString dbConfig.type;
CONFIG_DIRECTORY = toString dbConfig.configDirectory or "";
DB_LOG_QUERIES = toString dbConfig.logQueries;
DB_HOST = if dbConfig.type == "postgres" && !(hasAttr "socket" dbConfig) then toString dbConfig.host or "" else "";
DB_PORT = if dbConfig.type == "postgres" && !(hasAttr "socket" dbConfig) then toString dbConfig.port or "" else "";
DB_SOCKET_PATH = if dbConfig.type == "postgres" && hasAttr "socket" dbConfig then toString dbConfig.socket or "" else "";
DB_USER = if dbConfig.type == "postgres" then toString dbConfig.user or "" else "";
DB_PASS = if dbConfig.type == "postgres" then toString dbConfig.pass or "" else "";
DB_NAME = if dbConfig.type == "postgres" then toString dbConfig.name or "" else "";
};
serviceConfig = { serviceConfig = {
Type = "exec"; Type = "exec";
StateDirectory = "jellyseerr"; StateDirectory = "jellyseerr";
WorkingDirectory = "\${cfg.package}/libexec/jellyseerr/deps/jellyseerr"; WorkingDirectory = "${cfg.package}/libexec/jellyseerr";
DynamicUser = true; DynamicUser = true;
ExecStart = "\${cfg.package}/bin/jellyseerr"; ExecStart = "${cfg.package}/bin/jellyseerr";
BindPaths = [ "/var/lib/jellyseerr/:\${cfg.package}/libexec/jellyseerr/deps/jellyseerr/config/" ]; BindPaths = [ "/var/lib/jellyseerr/:${cfg.package}/libexec/jellyseerr/config/" ];
Restart = "on-failure"; Restart = "on-failure";
ProtectHome = true; ProtectHome = true;
ProtectSystem = "strict"; ProtectSystem = "strict";
@@ -169,57 +225,47 @@ in
}; };
}; };
networking.firewall = mkIf cfg.openFirewall { networking.firewall = mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; };
allowedTCPPorts = [ cfg.port ];
};
}; };
}`; }
```
const configuration = `{ config, pkgs, ... }: Then, import the module into your `configuration.nix`:
```nix
{ config, pkgs, ... }:
{ {
imports = [ ./jellyseerr-module.nix ] imports = [ ./modules/jellyseerr.nix ];
services.jellyseerr = { services.jellyseerr = {
enable = true; enable = true;
port = 5055; port = 5055;
openFirewall = true; openFirewall = true;
package = (pkgs.callPackage (import ../../../pkgs/jellyseerr) { }); package = pkgs.unstable.jellyseerr; # use the unstable package if stable is not up-to-date
databaseConfig = {
type = "postgres";
host = "localhost"; # or socket: "/run/postgresql"
port = "5432"; # if using socket, this is not needed
user = "jellyseerr";
pass = "jellyseerr";
name = "jellyseerr";
logQueries = "false";
}; };
}`; }
}
```
</TabItem>
</Tabs>
const isUpToDate = jellyseerrVersion === nixpkgVersion; After adding the configuration to your `configuration.nix`, you can run the following command to install jellyseerr:
return ( ```bash
<> nixos-rebuild switch
{isUpToDate ? ( ```
<> After rebuild is complete jellyseerr should be running, verify that it is with the following command.
<p>The latest version of Jellyseerr <strong>({jellyseerrVersion})</strong> and the Jellyseerr nixpkg package version <strong>({nixpkgVersion})</strong> is <strong>up-to-date</strong>.</p> ```bash
<p>There is no need to override the package derivation.</p> systemctl status jellyseerr
</> ```
) : (
<>
<p>The latest version of Jellyseerr <strong>({jellyseerrVersion})</strong> and the Jellyseerr nixpkg version <strong>(v{nixpkgVersion})</strong> is <strong>out-of-date</strong>.
If you want to use <b>Jellyseerr v{jellyseerrVersion}</b>, you will need to override the package derivation.</p>
<p>In order to override the package derivation:</p>
<ol>
<li style={{ marginBottom: '1rem' }}>Grab the <a href="https://raw.githubusercontent.com/NixOS/nixpkgs/nixos-unstable/pkgs/servers/jellyseerr/default.nix">latest nixpkg derivation for Jellyseerr</a></li>
<li style={{ marginBottom: '1rem' }}>Grab the latest <a href="https://raw.githubusercontent.com/Fallenbagel/jellyseerr/main/package.json">package.json</a> for Jellyseerr</li>
<li style={{ marginBottom: '1rem' }}>Add it to the same directory as the nixpkg derivation</li>
<li style={{ marginBottom: '1rem' }}>Update the `src` and `offlineCache` attributes in the nixpkg derivation:</li>
<CodeBlock className="language-nix" style={{ marginBottom: '1rem' }}>{code}</CodeBlock>
<Admonition type="tip" style={{ marginBottom: '1rem' }}>You can replace the <b>sha256</b> with the actual hash that <b>nixos-rebuild</b> outputs when you run the command.</Admonition>
<li style={{ marginBottom: '1rem' }}>Grab this module and import it in your `configuration.nix`</li>
<CodeBlock className="language-nix" style={{ marginBottom: '1rem' }}>{module}</CodeBlock>
<Admonition type="tip" style={{ marginBottom: '1rem' }}>We are using a custom module because the upstream module does not have a package option.</Admonition>
<li style={{ marginBottom: '1rem' }}>Call the new package in your `configuration.nix`</li>
<CodeBlock className="language-nix" style={{ marginBottom: '1rem' }}>{configuration}</CodeBlock>
</ol>
</>
)}
</>
);
}; :::info
You can now access Jellyseerr by visiting `http://localhost:5055` in your web browser.
<VersionMatch /> :::

View File

@@ -26,25 +26,37 @@ export const JellyseerrVersion = () => {
}; };
export const NixpkgVersion = () => { export const NixpkgVersion = () => {
const [version, setVersion] = useState(null); const [versions, setVersions] = useState(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(null); const [error, setError] = useState(null);
useEffect(() => { useEffect(() => {
const fetchVersion = async () => { const fetchVersion = async () => {
try { try {
const url = const unstableUrl =
'https://raw.githubusercontent.com/NixOS/nixpkgs/nixos-unstable/pkgs/servers/jellyseerr/default.nix'; 'https://raw.githubusercontent.com/NixOS/nixpkgs/refs/heads/nixos-unstable/pkgs/by-name/je/jellyseerr/package.nix';
const response = await fetch(url); const stableUrl =
const data = await response.text(); 'https://raw.githubusercontent.com/NixOS/nixpkgs/refs/heads/nixos-24.11/pkgs/servers/jellyseerr/default.nix';
const [unstableResponse, stableResponse] = await Promise.all([
fetch(unstableUrl),
fetch(stableUrl),
]);
const unstableData = await unstableResponse.text();
const stableData = await stableResponse.text();
const versionRegex = /version\s*=\s*"([^"]+)"/; const versionRegex = /version\s*=\s*"([^"]+)"/;
const match = data.match(versionRegex);
if (match && match[1]) { const unstableMatch = unstableData.match(versionRegex);
setVersion(match[1]); const stableMatch = stableData.match(versionRegex);
} else {
setError('0.0.0'); const unstableVersion =
} unstableMatch && unstableMatch[1] ? unstableMatch[1] : '0.0.0';
const stableVersion =
stableMatch && stableMatch[1] ? stableMatch[1] : '0.0.0';
setVersions({ unstable: unstableVersion, stable: stableVersion });
setLoading(false); setLoading(false);
} catch (err) { } catch (err) {
setError(err.message); setError(err.message);
@@ -63,5 +75,5 @@ export const NixpkgVersion = () => {
return { error }; return { error };
} }
return version; return versions;
}; };

View File

@@ -68,8 +68,10 @@ const prodConfig: DataSourceOptions = {
const postgresDevConfig: DataSourceOptions = { const postgresDevConfig: DataSourceOptions = {
type: 'postgres', type: 'postgres',
host: process.env.DB_HOST, host: process.env.DB_SOCKET_PATH || process.env.DB_HOST,
port: parseInt(process.env.DB_PORT ?? '5432'), port: process.env.DB_SOCKET_PATH
? undefined
: parseInt(process.env.DB_PORT ?? '5432'),
username: process.env.DB_USER, username: process.env.DB_USER,
password: process.env.DB_PASS, password: process.env.DB_PASS,
database: process.env.DB_NAME ?? 'jellyseerr', database: process.env.DB_NAME ?? 'jellyseerr',
@@ -84,8 +86,10 @@ const postgresDevConfig: DataSourceOptions = {
const postgresProdConfig: DataSourceOptions = { const postgresProdConfig: DataSourceOptions = {
type: 'postgres', type: 'postgres',
host: process.env.DB_HOST, host: process.env.DB_SOCKET_PATH || process.env.DB_HOST,
port: parseInt(process.env.DB_PORT ?? '5432'), port: process.env.DB_SOCKET_PATH
? undefined
: parseInt(process.env.DB_PORT ?? '5432'),
username: process.env.DB_USER, username: process.env.DB_USER,
password: process.env.DB_PASS, password: process.env.DB_PASS,
database: process.env.DB_NAME ?? 'jellyseerr', database: process.env.DB_NAME ?? 'jellyseerr',