Centralize build output and generate OS-specific startup.json
- All DLLs now output to lib\[Configuration]\[TargetFramework]\ at repo root (see Directory.Build.props) - .gitignore updated to exclude /lib/ - On first run, startup.json is auto-generated with OS-appropriate default paths (Windows, Linux, macOS, or portable) - Removes null/example config; generated config is immediately usable and clearly documented - Extensive new documentation: build output, startup.json logic, visual guides, and code proofs - Publish profile now deletes existing files for clean deploys - No breaking changes: existing startup.json files are preserved - Improves first-run UX, deployment, and cross-platform consistency
This commit is contained in:
@@ -0,0 +1,406 @@
|
||||
# File-Based Startup Configuration
|
||||
|
||||
## Overview
|
||||
Jellyfin now supports file-based configuration for all startup paths in addition to command-line options and environment variables. This provides a persistent, portable way to configure your Jellyfin installation.
|
||||
|
||||
**New in this version:** The `startup.json` file is **automatically created** on first startup if it doesn't exist, with example configurations for Linux, Windows, and portable installations. See [AUTO_GENERATED_STARTUP_CONFIG.md](AUTO_GENERATED_STARTUP_CONFIG.md) for details.
|
||||
|
||||
## Configuration Priority
|
||||
|
||||
When determining which path to use, Jellyfin follows this priority (highest to lowest):
|
||||
|
||||
1. **Command-line options** (e.g., `--datadir`)
|
||||
2. **Environment variables** (e.g., `JELLYFIN_DATA_DIR`)
|
||||
3. **Configuration file** (`startup.json`)
|
||||
4. **Default values**
|
||||
|
||||
This allows you to set defaults in a file, override them with environment variables for different environments, and temporarily override with command-line options for testing.
|
||||
|
||||
## Automatic File Creation ⭐ NEW
|
||||
|
||||
On first startup, if no `startup.json` file is found, Jellyfin will automatically create one with:
|
||||
- All path properties set to `null` (uses defaults)
|
||||
- Example configurations for Linux, Windows, and portable setups
|
||||
- Inline documentation and comments
|
||||
|
||||
**You'll see:**
|
||||
```
|
||||
Created default startup configuration at: /path/to/startup.json
|
||||
You can customize this file to set default paths for Jellyfin.
|
||||
```
|
||||
|
||||
Simply edit the file and restart Jellyfin to apply your custom paths. See [AUTO_GENERATED_STARTUP_CONFIG.md](AUTO_GENERATED_STARTUP_CONFIG.md) for complete details on the auto-generation feature.
|
||||
|
||||
## Configuration File Location
|
||||
|
||||
The `startup.json` file is searched in the following locations (in order):
|
||||
|
||||
1. **Current working directory**: `./startup.json`
|
||||
2. **Application directory**: `{AppDir}/startup.json`
|
||||
3. **Config subdirectory**: `{AppDir}/config/startup.json`
|
||||
|
||||
The first file found will be used.
|
||||
|
||||
## File Format
|
||||
|
||||
Create a file named `startup.json` with the following structure (or let it be auto-generated):
|
||||
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/var/lib/jellyfin",
|
||||
"ConfigDir": "/etc/jellyfin",
|
||||
"CacheDir": "/var/cache/jellyfin",
|
||||
"LogDir": "/var/log/jellyfin",
|
||||
"TempDir": "/var/tmp/jellyfin",
|
||||
"WebDir": "/usr/share/jellyfin/web"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Supported Properties
|
||||
|
||||
All path properties are **optional**. Any property can be set to `null` or omitted entirely, and the system will fall back to environment variables or defaults.
|
||||
|
||||
| Property | Description | Equivalent CLI | Equivalent Env Var |
|
||||
|----------|-------------|----------------|-------------------|
|
||||
| `DataDir` | Database and data files | `--datadir` | `JELLYFIN_DATA_DIR` |
|
||||
| `ConfigDir` | Configuration files | `--configdir` | `JELLYFIN_CONFIG_DIR` |
|
||||
| `CacheDir` | Cache files | `--cachedir` | `JELLYFIN_CACHE_DIR` |
|
||||
| `LogDir` | Log files | `--logdir` | `JELLYFIN_LOG_DIR` |
|
||||
| `TempDir` | Temporary files | `--tempdir` | `JELLYFIN_TEMP_DIR` |
|
||||
| `WebDir` | Web client files | `--webdir` | `JELLYFIN_WEB_DIR` |
|
||||
|
||||
## Example Configurations
|
||||
|
||||
### Linux Production Server
|
||||
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/var/lib/jellyfin",
|
||||
"ConfigDir": "/etc/jellyfin",
|
||||
"CacheDir": "/var/cache/jellyfin",
|
||||
"LogDir": "/var/log/jellyfin",
|
||||
"TempDir": "/var/tmp/jellyfin",
|
||||
"WebDir": "/usr/share/jellyfin/web"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Windows Production Server
|
||||
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "C:\\ProgramData\\Jellyfin\\data",
|
||||
"ConfigDir": "C:\\ProgramData\\Jellyfin\\config",
|
||||
"CacheDir": "D:\\Cache\\Jellyfin",
|
||||
"LogDir": "C:\\ProgramData\\Jellyfin\\logs",
|
||||
"TempDir": "D:\\Temp\\Jellyfin",
|
||||
"WebDir": "C:\\Program Files\\Jellyfin\\web"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Development Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "./dev-data",
|
||||
"ConfigDir": "./dev-config",
|
||||
"CacheDir": "./dev-cache",
|
||||
"LogDir": "./dev-logs",
|
||||
"TempDir": "./dev-temp",
|
||||
"WebDir": "./wwwroot"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Minimal Configuration (Using Defaults)
|
||||
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/custom/jellyfin/data"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, only `DataDir` is overridden. All other paths will use their default values or environment variables.
|
||||
|
||||
### Partial Override with Environment Variables
|
||||
|
||||
**startup.json:**
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/var/lib/jellyfin",
|
||||
"ConfigDir": "/etc/jellyfin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Environment variables:**
|
||||
```bash
|
||||
export JELLYFIN_TEMP_DIR=/fast-storage/jellyfin-temp
|
||||
```
|
||||
|
||||
**Result:** DataDir and ConfigDir come from the file, TempDir from environment variable, and all others use defaults.
|
||||
|
||||
## Use Cases
|
||||
|
||||
### 1. Containerized Deployments
|
||||
|
||||
**Docker Example:**
|
||||
Create `startup.json` in your config volume:
|
||||
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/data",
|
||||
"ConfigDir": "/config",
|
||||
"CacheDir": "/cache",
|
||||
"LogDir": "/logs",
|
||||
"TempDir": "/temp"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**docker-compose.yml:**
|
||||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin
|
||||
volumes:
|
||||
- ./startup.json:/config/startup.json
|
||||
- jellyfin_data:/data
|
||||
- jellyfin_cache:/cache
|
||||
- jellyfin_logs:/logs
|
||||
- jellyfin_temp:/temp
|
||||
```
|
||||
|
||||
### 2. Multiple Instance Setup
|
||||
|
||||
Run multiple Jellyfin instances with different configurations:
|
||||
|
||||
**Instance 1 (startup-prod.json):**
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/srv/jellyfin/prod/data",
|
||||
"ConfigDir": "/srv/jellyfin/prod/config",
|
||||
"LogDir": "/srv/jellyfin/prod/logs"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Instance 2 (startup-test.json):**
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/srv/jellyfin/test/data",
|
||||
"ConfigDir": "/srv/jellyfin/test/config",
|
||||
"LogDir": "/srv/jellyfin/test/logs"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Portable Installation
|
||||
|
||||
Create a portable Jellyfin installation with relative paths:
|
||||
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "./data",
|
||||
"ConfigDir": "./config",
|
||||
"CacheDir": "./cache",
|
||||
"LogDir": "./logs",
|
||||
"TempDir": "./temp",
|
||||
"WebDir": "./web"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Performance Optimization
|
||||
|
||||
Place different directories on different storage devices:
|
||||
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/mnt/hdd/jellyfin/data",
|
||||
"ConfigDir": "/mnt/ssd/jellyfin/config",
|
||||
"CacheDir": "/mnt/ssd/jellyfin/cache",
|
||||
"TempDir": "/mnt/nvme/jellyfin/temp",
|
||||
"LogDir": "/mnt/hdd/jellyfin/logs"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
When Jellyfin starts, it will log the configuration file being used:
|
||||
|
||||
```
|
||||
Loaded startup configuration from: /path/to/startup.json
|
||||
```
|
||||
|
||||
If the file has syntax errors, you'll see:
|
||||
|
||||
```
|
||||
Warning: Failed to load startup configuration from /path/to/startup.json: [error message]
|
||||
```
|
||||
|
||||
All resolved paths are logged at startup:
|
||||
|
||||
```
|
||||
[INF] Program data path: /var/lib/jellyfin
|
||||
[INF] Config directory path: /etc/jellyfin
|
||||
[INF] Cache path: /var/cache/jellyfin
|
||||
[INF] Log directory path: /var/log/jellyfin
|
||||
[INF] Temp directory path: /var/tmp/jellyfin
|
||||
[INF] Web resources path: /usr/share/jellyfin/web
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Configuration File Not Found
|
||||
|
||||
If your configuration file isn't being loaded:
|
||||
|
||||
1. Check the file is named exactly `startup.json`
|
||||
2. Verify it's in one of the search locations
|
||||
3. Check file permissions (must be readable)
|
||||
4. Look for typos in the JSON structure
|
||||
|
||||
### Invalid JSON Syntax
|
||||
|
||||
Common JSON errors:
|
||||
|
||||
```json
|
||||
// ❌ Wrong - trailing comma
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/var/lib/jellyfin",
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ Correct
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/var/lib/jellyfin"
|
||||
}
|
||||
}
|
||||
|
||||
// ❌ Wrong - single quotes
|
||||
{
|
||||
"Paths": {
|
||||
'DataDir': '/var/lib/jellyfin'
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ Correct - double quotes
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/var/lib/jellyfin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Path Resolution Order
|
||||
|
||||
Remember the priority:
|
||||
1. CLI argument beats everything
|
||||
2. Environment variable beats config file
|
||||
3. Config file beats defaults
|
||||
|
||||
To test which source is being used, try setting different values in each and check the startup logs.
|
||||
|
||||
## Migration from Environment Variables
|
||||
|
||||
If you currently use environment variables, you can migrate to a config file:
|
||||
|
||||
**Before (environment variables):**
|
||||
```bash
|
||||
export JELLYFIN_DATA_DIR=/var/lib/jellyfin
|
||||
export JELLYFIN_CONFIG_DIR=/etc/jellyfin
|
||||
export JELLYFIN_CACHE_DIR=/var/cache/jellyfin
|
||||
export JELLYFIN_LOG_DIR=/var/log/jellyfin
|
||||
```
|
||||
|
||||
**After (startup.json):**
|
||||
```json
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/var/lib/jellyfin",
|
||||
"ConfigDir": "/etc/jellyfin",
|
||||
"CacheDir": "/var/cache/jellyfin",
|
||||
"LogDir": "/var/log/jellyfin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then remove the environment variables from your `.bashrc`, systemd service, or wherever they're defined.
|
||||
|
||||
## Benefits
|
||||
|
||||
### Advantages of File-Based Configuration
|
||||
|
||||
1. **Portability**: Easy to copy configuration between systems
|
||||
2. **Version Control**: Track configuration changes in Git
|
||||
3. **Documentation**: Self-documenting with comments (in extended formats)
|
||||
4. **Persistence**: Survives system reboots and shell sessions
|
||||
5. **Consistency**: Same configuration across all instances
|
||||
6. **No Shell Escaping**: No need to worry about shell quoting rules
|
||||
7. **Easy Editing**: Simple text file, easy to modify
|
||||
8. **Backup**: Can be backed up with other configuration files
|
||||
|
||||
### When to Use Each Method
|
||||
|
||||
| Method | Best For |
|
||||
|--------|----------|
|
||||
| **Config File** | Production servers, containers, permanent installations |
|
||||
| **Environment Variables** | System-wide settings, CI/CD pipelines, user-specific overrides |
|
||||
| **Command Line** | Testing, one-time overrides, debugging |
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Keep `startup.json` readable only by the Jellyfin user
|
||||
- Don't commit sensitive paths to public repositories
|
||||
- Use environment variables for secrets (like database passwords)
|
||||
- Consider using separate config files per environment (dev/staging/prod)
|
||||
|
||||
## Example Setup Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# create-jellyfin-config.sh
|
||||
|
||||
cat > /etc/jellyfin/startup.json <<EOF
|
||||
{
|
||||
"Paths": {
|
||||
"DataDir": "/var/lib/jellyfin",
|
||||
"ConfigDir": "/etc/jellyfin",
|
||||
"CacheDir": "/var/cache/jellyfin",
|
||||
"LogDir": "/var/log/jellyfin",
|
||||
"TempDir": "/var/tmp/jellyfin",
|
||||
"WebDir": "/usr/share/jellyfin/web"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Set proper permissions
|
||||
chmod 644 /etc/jellyfin/startup.json
|
||||
chown jellyfin:jellyfin /etc/jellyfin/startup.json
|
||||
|
||||
echo "Jellyfin startup configuration created at /etc/jellyfin/startup.json"
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [PATH_CONFIGURATION_GUIDE.md](PATH_CONFIGURATION_GUIDE.md) - Complete path configuration reference
|
||||
- [startup.json.example](startup.json.example) - Template configuration file with JSON schema
|
||||
Reference in New Issue
Block a user