Files
pgsql-jellyfin/docs/INSTALLER_GUIDE.md
wjones c51c14efde Docs: overhaul README, centralize docs, update .gitignore
- Rewrote README.md to highlight PostgreSQL features, installer, and migration, with quick start and full docs index
- Moved all markdown documentation files to docs/ for better organization; updated links accordingly
- Added .gitignore rules to exclude all PublishProfiles folders; removed tracked publish profile XMLs
- Preserved original README as README.original.md; added README_GENERATION.md and DOCUMENTATION_ORGANIZATION.md
- Cleaned root directory, improved navigation, and clarified platform-specific instructions
2026-02-26 15:50:19 -05:00

15 KiB

Creating an Installer for Jellyfin

Solution: E:\Projects\pgsql-jellyfin
Target: Windows Installer for PostgreSQL-enabled Jellyfin
Status: Guide for implementation


Overview

You can create professional installers for your Jellyfin solution using several methods. Here are your options ranked by recommendation:


Why WiX?

  • Industry standard for .NET applications
  • Creates proper MSI installers
  • Full Windows Installer features (services, registry, shortcuts)
  • Supports upgrades and uninstalls
  • Free and open source
  • Integrates with Visual Studio

Prerequisites

# Install WiX Toolset
winget install --id WiX.Toolset

# Or download from:
# https://wixtoolset.org/

Implementation Steps

Step 1: Create WiX Project

Add to your solution:

<!-- Jellyfin.Installer.csproj -->
<Project Sdk="WixToolset.Sdk/5.0.0">
  <PropertyGroup>
    <OutputType>Package</OutputType>
    <Platform>x64</Platform>
    <TargetFramework>net11.0</TargetFramework>
    <OutputName>JellyfinSetup-PostgreSQL-$(Version)</OutputName>
  </PropertyGroup>

  <ItemGroup>
    <!-- Reference the main Jellyfin.Server project -->
    <ProjectReference Include="..\Jellyfin.Server\Jellyfin.Server.csproj">
      <Private>true</Private>
      <DoNotHarvest>true</DoNotHarvest>
      <IncludeOutputGroupInVSIXContainer>true</IncludeOutputGroupInVSIXContainer>
    </ProjectReference>
  </ItemGroup>
</Project>

Step 2: Create Installer Definition (Product.wxs)

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
  <Package 
    Name="Jellyfin Server (PostgreSQL Edition)" 
    Manufacturer="Your Name"
    Version="11.0.0.0"
    UpgradeCode="PUT-YOUR-GUID-HERE">
    
    <MajorUpgrade 
      DowngradeErrorMessage="A newer version is already installed." />
    
    <Media Id="1" Cabinet="jellyfin.cab" EmbedCab="yes" />

    <!-- Installation Directory -->
    <StandardDirectory Id="ProgramFiles64Folder">
      <Directory Id="INSTALLFOLDER" Name="Jellyfin">
        <Directory Id="BinFolder" Name="bin" />
        <Directory Id="DataFolder" Name="data" />
      </Directory>
    </StandardDirectory>

    <!-- Program Data Directory -->
    <StandardDirectory Id="CommonAppDataFolder">
      <Directory Id="ProgramDataFolder" Name="jellyfin" />
    </StandardDirectory>

    <!-- Components -->
    <ComponentGroup Id="ProductComponents" Directory="BinFolder">
      <!-- Harvest all files from lib\Release\net11.0 -->
      <Component Id="JellyfinExe">
        <File Source="$(var.SolutionDir)lib\Release\net11.0\jellyfin.dll" />
        <File Source="$(var.SolutionDir)lib\Release\net11.0\jellyfin.exe" />
        <!-- Add more files... -->
      </Component>
    </ComponentGroup>

    <!-- Service Component -->
    <Component Id="JellyfinService" Directory="BinFolder">
      <ServiceInstall
        Id="JellyfinServiceInstaller"
        Type="ownProcess"
        Name="JellyfinPostgreSQL"
        DisplayName="Jellyfin Server (PostgreSQL)"
        Description="Jellyfin media server with PostgreSQL support"
        Start="auto"
        Account="LocalSystem"
        ErrorControl="normal"
        Arguments='--service'
        />
      <ServiceControl
        Id="JellyfinServiceControl"
        Start="install"
        Stop="both"
        Remove="uninstall"
        Name="JellyfinPostgreSQL"
        Wait="yes" />
    </Component>

    <!-- Start Menu Shortcuts -->
    <StandardDirectory Id="ProgramMenuFolder">
      <Directory Id="ApplicationProgramsFolder" Name="Jellyfin">
        <Component Id="ApplicationShortcuts">
          <Shortcut 
            Id="JellyfinShortcut"
            Name="Jellyfin Server (PostgreSQL)"
            Description="Start Jellyfin media server"
            Target="[BinFolder]jellyfin.exe"
            WorkingDirectory="BinFolder" />
          <RemoveFolder Id="CleanUpShortCut" On="uninstall" />
        </Component>
      </Directory>
    </StandardDirectory>

    <!-- Features -->
    <Feature Id="ProductFeature" Title="Jellyfin Server" Level="1">
      <ComponentGroupRef Id="ProductComponents" />
      <ComponentRef Id="JellyfinService" />
      <ComponentRef Id="ApplicationShortcuts" />
    </Feature>

    <!-- UI -->
    <WixVariable Id="WixUILicenseRtf" Value="License.rtf" />
    <UIRef Id="WixUI_InstallDir" />
    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
  </Package>
</Wix>

Step 3: Build the Installer

# Add WiX project to solution
dotnet new wix -n Jellyfin.Installer -o Jellyfin.Installer
dotnet sln add Jellyfin.Installer/Jellyfin.Installer.csproj

# Build installer
dotnet build Jellyfin.Installer --configuration Release

# Output: Jellyfin.Installer\bin\Release\JellyfinSetup-PostgreSQL-11.0.0.msi

Quick Option: Inno Setup (Easier but Less Features)

Why Inno Setup?

  • Very easy to use
  • Script-based (no XML)
  • Small installer size
  • Free
  • Less Windows Installer integration than WiX

Prerequisites

# Download from: https://jrsoftware.org/isinfo.php
winget install --id JRSoftware.InnoSetup

Implementation: Create Setup Script (jellyfin-setup.iss)

; Jellyfin PostgreSQL Edition Installer
[Setup]
AppName=Jellyfin Server (PostgreSQL Edition)
AppVersion=11.0.0
DefaultDirName={autopf}\Jellyfin
DefaultGroupName=Jellyfin
OutputDir=installer-output
OutputBaseFilename=JellyfinSetup-PostgreSQL-11.0.0
Compression=lzma2
SolidCompression=yes
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
PrivilegesRequired=admin
SetupIconFile=jellyfin.ico

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "desktopicon"; Description: "Create a &desktop icon"; GroupDescription: "Additional icons:"
Name: "service"; Description: "Install as Windows Service"; GroupDescription: "Service Options:"; Flags: unchecked

[Files]
; Copy all files from lib\Release\net11.0
Source: "lib\Release\net11.0\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; Copy startup configuration
Source: "Jellyfin.Server\Resources\Configuration\startup.windows.json"; DestDir: "{app}"; DestName: "startup.json"; Flags: onlyifdoesntexist

[Dirs]
; Create program data directories
Name: "{commonappdata}\jellyfin"; Permissions: users-modify
Name: "{commonappdata}\jellyfin\data"; Permissions: users-modify
Name: "{commonappdata}\jellyfin\log"; Permissions: users-modify
Name: "{commonappdata}\jellyfin\cache"; Permissions: users-modify

[Icons]
Name: "{group}\Jellyfin Server"; Filename: "{app}\jellyfin.exe"
Name: "{group}\Jellyfin Web Interface"; Filename: "http://localhost:8096"
Name: "{commondesktop}\Jellyfin Server"; Filename: "{app}\jellyfin.exe"; Tasks: desktopicon

[Run]
; Open web interface after install
Filename: "http://localhost:8096"; Description: "Open Jellyfin Web Interface"; Flags: postinstall shellexec skipifsilent

; Install as service (optional)
Filename: "sc.exe"; Parameters: "create JellyfinPostgreSQL binPath= ""{app}\jellyfin.exe --service"" start= auto"; Tasks: service; Flags: runhidden
Filename: "sc.exe"; Parameters: "description JellyfinPostgreSQL ""Jellyfin media server with PostgreSQL support"""; Tasks: service; Flags: runhidden
Filename: "sc.exe"; Parameters: "start JellyfinPostgreSQL"; Tasks: service; Flags: runhidden waituntilterminated

[UninstallRun]
; Stop and remove service if it exists
Filename: "sc.exe"; Parameters: "stop JellyfinPostgreSQL"; Flags: runhidden
Filename: "sc.exe"; Parameters: "delete JellyfinPostgreSQL"; Flags: runhidden

[Code]
// Custom code for install dialogs
function InitializeSetup(): Boolean;
begin
  Result := True;
  // Check for .NET 11 runtime
  if not RegKeyExists(HKLM, 'SOFTWARE\dotnet\Setup\InstalledVersions\x64\sharedhost') then
  begin
    MsgBox('.NET 11 Runtime is required. Please install it first.', mbError, MB_OK);
    Result := False;
  end;
end;

Build Inno Setup Installer

# Compile the script
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" jellyfin-setup.iss

# Output: installer-output\JellyfinSetup-PostgreSQL-11.0.0.exe

🚀 Modern Option: MSIX (Windows 10/11 Only)

Why MSIX?

  • Modern Windows app packaging
  • Automatic updates via Microsoft Store
  • Clean install/uninstall
  • Sandboxed security
  • Windows 10 1809+ only
  • Requires code signing certificate

Implementation: Add MSIX Project

<!-- Jellyfin.Package.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net11.0-windows10.0.19041.0</TargetFramework>
    <GenerateAppxPackageOnBuild>true</GenerateAppxPackageOnBuild>
    <AppxPackageSigningEnabled>true</AppxPackageSigningEnabled>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\Jellyfin.Server\Jellyfin.Server.csproj" />
  </ItemGroup>

  <ItemGroup>
    <Content Include="Images\StoreLogo.png" />
    <Content Include="Images\Square44x44Logo.png" />
    <Content Include="Images\Square150x150Logo.png" />
    <Content Include="Images\Wide310x150Logo.png" />
  </ItemGroup>
</Project>

📦 Simple Option: Self-Contained Publish + ZIP

Why Zip?

  • Simplest approach
  • No installer needed
  • Portable
  • No service install
  • No shortcuts
  • No uninstaller

Implementation

# Publish self-contained
dotnet publish Jellyfin.Server `
  --configuration Release `
  --runtime win-x64 `
  --self-contained true `
  --output "publish\jellyfin-pgsql-win-x64" `
  /p:PublishSingleFile=false `
  /p:IncludeNativeLibrariesForSelfExtract=true

# Create ZIP
Compress-Archive `
  -Path "publish\jellyfin-pgsql-win-x64\*" `
  -DestinationPath "jellyfin-pgsql-11.0.0-win-x64.zip"

Include README in ZIP

# Jellyfin Server (PostgreSQL Edition)

## Installation

1. Extract this ZIP to C:\Jellyfin (or any location)
2. Run `jellyfin.exe`
3. Open http://localhost:8096 in your browser
4. Follow setup wizard

## Install as Windows Service

Run as Administrator:
```cmd
sc create JellyfinPostgreSQL binPath= "C:\Jellyfin\jellyfin.exe --service" start= auto
sc description JellyfinPostgreSQL "Jellyfin media server with PostgreSQL"
sc start JellyfinPostgreSQL

Uninstall Service

sc stop JellyfinPostgreSQL
sc delete JellyfinPostgreSQL

Configuration

Edit startup.json to customize paths.


---

## 🎯 Recommended Approach for You

### For Production Distribution: **WiX Toolset**

**Why:**
- Professional MSI installer
- Windows Service support
- Proper upgrade handling
- Includes PostgreSQL setup guidance

**Next Steps:**

1. **Install WiX**
   ```powershell
   winget install --id WiX.Toolset
  1. Create Installer Project

    mkdir Jellyfin.Installer
    cd Jellyfin.Installer
    # Create Product.wxs file (see template above)
    
  2. Add to Solution

    dotnet sln add Jellyfin.Installer/Jellyfin.Installer.csproj
    
  3. Build

    dotnet build Jellyfin.Installer --configuration Release
    

For Quick Testing: Inno Setup

Why:

  • Fast to create
  • Easy to customize
  • Good for internal testing

Next Steps:

  1. Install Inno Setup

    winget install JRSoftware.InnoSetup
    
  2. Create Script

    • Use template above
    • Save as jellyfin-setup.iss
  3. Compile

    "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" jellyfin-setup.iss
    

Additional Installer Features to Consider

PostgreSQL Database Setup

Add to installer:

<!-- WiX: Check for PostgreSQL -->
<Property Id="POSTGRESQLINSTALLED">
  <RegistrySearch Id="PostgreSQLSearch" 
    Root="HKLM" 
    Key="SOFTWARE\PostgreSQL\Installations\postgresql-x64-16"
    Name="Version"
    Type="raw" />
</Property>

<Condition Message="PostgreSQL 12+ is required. Please install PostgreSQL first.">
  Installed OR POSTGRESQLINSTALLED
</Condition>

Firewall Rules

<!-- Add Windows Firewall exception -->
<Component Id="FirewallException">
  <fire:FirewallException Id="JellyfinFirewall"
    Name="Jellyfin Server"
    Port="8096"
    Protocol="tcp"
    Scope="any" />
</Component>

Database Migration Wizard

Include a post-install wizard for:

  • PostgreSQL connection setup
  • Database migration from SQLite
  • Initial configuration

Testing Your Installer

Test Checklist

  • Fresh Windows install
  • Upgrade from previous version
  • Silent install: msiexec /i JellyfinSetup.msi /quiet
  • Custom install directory
  • Service starts automatically
  • Firewall rules created
  • Shortcuts work
  • Uninstall removes everything
  • Data preserved on upgrade

Test Commands

# Install silently
msiexec /i JellyfinSetup-PostgreSQL-11.0.0.msi /quiet /l*v install.log

# Uninstall silently
msiexec /x JellyfinSetup-PostgreSQL-11.0.0.msi /quiet

# Upgrade
msiexec /i JellyfinSetup-PostgreSQL-11.0.1.msi /quiet

Distribution

Get a code signing certificate:

  • DigiCert
  • Sectigo
  • SignPath (free for open source)

Sign your installer:

signtool sign /f certificate.pfx /p password /t http://timestamp.digicert.com JellyfinSetup.msi

Release Strategy

  1. GitHub Releases

    # .github/workflows/release.yml
    - name: Build Installer
      run: dotnet build Jellyfin.Installer --configuration Release
    
    - name: Upload Release Asset
      uses: actions/upload-release-asset@v1
      with:
        asset_path: Jellyfin.Installer/bin/Release/JellyfinSetup.msi
        asset_name: jellyfin-pgsql-windows-${{ github.ref }}.msi
    
  2. Versioning

    • Use semantic versioning: 11.0.0
    • Include in filename: JellyfinSetup-PostgreSQL-11.0.0.msi
    • Update UpgradeCode for major versions only

Quick Start Script

I can create a PowerShell script to help you set up the installer project:

# setup-installer.ps1
param(
    [Parameter(Mandatory=$false)]
    [ValidateSet("WiX", "InnoSetup", "Both")]
    [string]$Type = "InnoSetup"
)

Write-Host "Setting up Jellyfin installer project..." -ForegroundColor Cyan

# Your current setup
$solutionRoot = "E:\Projects\pgsql-jellyfin"
$libFolder = "$solutionRoot\lib\Release\net11.0"

if ($Type -eq "InnoSetup" -or $Type -eq "Both") {
    # Create Inno Setup script
    # ... (see template above)
}

if ($Type -eq "WiX" -or $Type -eq "Both") {
    # Create WiX project
    # ... (see template above)
}

Write-Host "Installer setup complete!" -ForegroundColor Green

Summary

Recommended for You: Inno Setup (Quick start)

  • Easiest to implement immediately
  • Creates professional .exe installer
  • Includes service install option

Future: Migrate to WiX (Production)

  • Industry standard
  • Better upgrade handling
  • Full MSI features

Want me to create the installer project for you? Just let me know which approach you prefer!


Files Needed:

  • jellyfin.ico (icon file)
  • License.rtf (license text)
  • README.md (user instructions)
  • PostgreSQL setup guide

Estimated Time:

  • Inno Setup: 30 minutes
  • WiX Setup: 2-4 hours
  • MSIX: 1-2 hours

Let me know which installer type you'd like me to help you implement!