# How to Configure ipsw Using YAML Config Files and Environment Variables

> Learn how to configure ipsw using YAML files and environment variables. Discover the precedence order for settings and control the ipsw CLI effectively.

- Repository: [blacktop/ipsw](https://github.com/blacktop/ipsw)
- Tags: how-to-guide
- Published: 2026-02-26

---

**The `ipsw` CLI uses the Viper configuration library to merge settings from YAML files and environment variables, with command-line flags taking highest precedence, environment variables (prefixed with `IPSW_`) second, and `~/.config/ipsw/config.yaml` last.**

The `blacktop/ipsw` repository provides a comprehensive tool for analyzing iOS firmware and IPSW files. Understanding how to configure `ipsw` using YAML config files and environment variables enables you to automate complex workflows and maintain consistent settings across development, staging, and production environments without repeating command-line flags.

## Configuration Architecture and Precedence

`ipsw` implements a layered configuration system through the **Viper** library, which aggregates values from three distinct sources. The system resolves conflicts using strict precedence rules:

1. **Command-line flags** (handled by Cobra) override all other values.
2. **Environment variables** prefixed with `IPSW_` take precedence over file-based settings.
3. **YAML configuration files** provide default values when higher-precedence sources are absent.

### How Viper Merges Configuration Sources

In [`cmd/ipsw/cmd/root.go`](https://github.com/blacktop/ipsw/blob/main/cmd/ipsw/cmd/root.go), the `initConfig()` function initializes Viper with `viper.AutomaticEnv()` and configures a key replacer that substitutes underscores for dots and hyphens. This allows environment variables like `IPSW_DAEMON_HOST` to override YAML keys such as `daemon.host`. The system also integrates the `caarlos0/env` package, which parses environment variables into the configuration struct using tags defined in [`internal/config/config.go`](https://github.com/blacktop/ipsw/blob/main/internal/config/config.go).

## YAML Configuration Files

### Default Location and File Structure

By default, `ipsw` searches for a file named [`config.yaml`](https://github.com/blacktop/ipsw/blob/main/config.yaml) or [`config.yml`](https://github.com/blacktop/ipsw/blob/main/config.yml) in the `~/.config/ipsw/` directory. You can specify an alternative path using the `--config` flag, which sets the configuration file location before Viper attempts to load the data. The root command in [`cmd/ipsw/cmd/root.go`](https://github.com/blacktop/ipsw/blob/main/cmd/ipsw/cmd/root.go) expands tilde-relative paths (e.g., `~/ipsw/config.yaml`) into absolute paths during the initialization phase.

### Daemon and Database Sections

The YAML structure consists of two top-level sections that map directly to the `Config` struct in [`internal/config/config.go`](https://github.com/blacktop/ipsw/blob/main/internal/config/config.go):

**Daemon Section** controls the API server settings:
- `host`: Bind address for the HTTP server
- `port`: TCP port number
- `socket`: Unix socket path (overrides host/port if specified)
- `debug`: Enable debug logging
- `logfile`: Path to daemon log file
- `pem_db`: Path to PEM certificate database
- `sigs_dir`: Directory for signature files

**Database Section** manages storage connections:
- `driver`: Database driver (`sqlite3` or `postgres`)
- `path`: File path for SQLite databases
- `host`, `port`, `user`, `password`: Connection details for PostgreSQL
- `sslmode`: SSL configuration for Postgres
- `batchsize`: Insert batch size for database operations

## Environment Variables

### Variable Naming Conventions

`ipsw` recognizes environment variables prefixed with `IPSW_` (or `IPS...` for specific CLI contexts). The `caarlos0/env` package defined in [`internal/config/config.go`](https://github.com/blacktop/ipsw/blob/main/internal/config/config.go) maps these variables to struct fields using `env` tags. Viper's key replacer additionally allows dot-notation variables to use underscores, meaning `IPSW_DAEMON_HOST` and `IPSW.DAEMON.HOST` both resolve to the `daemon.host` configuration key.

### Common Configuration Examples

You can override any YAML setting or configure `ipsw` without a config file using environment variables:

- `IPSW_DAEMON_HOST` → Sets the API server bind address
- `IPSW_DAEMON_PORT` → Configures the TCP listening port
- `IPSW_DATABASE_DRIVER` → Selects `sqlite3` or `postgres`
- `IPSW_DATABASE_PATH` → Specifies the SQLite database file location
- `IPSW_DATABASE_BATCHSIZE` → Tunes database insertion performance

## Configuration Loading Process

### initConfig and Viper Integration

When `ipsw` starts, the `initConfig()` function in [`cmd/ipsw/cmd/root.go`](https://github.com/blacktop/ipsw/blob/main/cmd/ipsw/cmd/root.go) executes before any subcommands run. This function determines the configuration file location (defaulting to `~/.config/ipsw/config.yaml`), invokes `viper.AutomaticEnv()` to enable environment variable parsing, and configures the key replacer that substitutes underscores for dots and hyphens. The daemon process (`ipswd`) follows an identical initialization pattern in [`cmd/ipswd/cmd/root.go`](https://github.com/blacktop/ipsw/blob/main/cmd/ipswd/cmd/root.go).

### Path Expansion and Validation

After Viper loads the raw configuration, [`internal/config/config.go`](https://github.com/blacktop/ipsw/blob/main/internal/config/config.go) processes the data through several specialized functions:

- `expandConfigPaths()`: Resolves tildes (`~`), relative paths (`./`, `../`), and environment variables within path strings to absolute paths
- `LoadConfig()`: Unmarshals the combined Viper data into the typed `Config` struct using the `env` tags for environment variable mapping
- `verify()`: Applies default values for daemon ports and database batch sizes, then validates mutually exclusive settings (such as Unix sockets versus TCP endpoints)

## Practical Configuration Examples

### Complete YAML Configuration

Create `~/.config/ipsw/config.yaml` with the following structure to configure both the daemon and database:

```yaml
daemon:
  host: "localhost"
  port: 3993
  socket: ""          # leave empty to use host/port; set path to override with Unix socket

  debug: true
  logfile: "~/ipsw.log"
  pem_db: "/var/lib/ipsw/pem.db"
  sigs_dir: "~/ipsw/sigs"

database:
  driver: "sqlite3"
  path: "~/ipsw/ipsw.db"
  batchsize: 2000

```

### Environment Variable Setup

Override YAML settings or configure `ipsw` without a config file using environment variables:

```bash
export IPSW_DAEMON_HOST=127.0.0.1
export IPSW_DAEMON_PORT=4000
export IPSW_DATABASE_DRIVER=postgres
export IPSW_DATABASE_HOST=db.example.com
export IPSW_DATABASE_PORT=5432
export IPSW_DATABASE_USER=ipsw
export IPSW_DATABASE_PASSWORD=superSecret
export IPSW_DATABASE_SSLMODE=require

```

These variables are parsed automatically at startup; no additional flags are required.

### Mixing Configuration Methods

You can combine YAML files with environment variables to create flexible deployment strategies. Store non-sensitive defaults in `~/.config/ipsw/config.yaml` while injecting secrets and environment-specific overrides via variables:

```bash

# Base configuration in YAML contains daemon settings

# Override only the database password via environment

export IPSW_DATABASE_PASSWORD=$(cat /run/secrets/db_pass)
ipsw daemon start

```

When mixing methods, remember the precedence order: environment variables override YAML values, and command-line flags override both.

## Summary

- **Viper-based layering**: `ipsw` uses the Viper library to merge command-line flags, environment variables, and YAML configuration files with strict precedence.
- **Default YAML location**: The tool searches for [`config.yaml`](https://github.com/blacktop/ipsw/blob/main/config.yaml) in `~/.config/ipsw/` unless overridden with the `--config` flag.
- **Environment prefix**: Variables prefixed with `IPSW_` map to configuration fields via tags in [`internal/config/config.go`](https://github.com/blacktop/ipsw/blob/main/internal/config/config.go), with automatic key replacement for dots and hyphens.
- **Path expansion**: The `expandConfigPaths()` function in [`internal/config/config.go`](https://github.com/blacktop/ipsw/blob/main/internal/config/config.go) resolves tildes and relative paths to absolute paths during loading.
- **Validation**: The `verify()` function applies defaults for daemon ports and database settings while validating mutually exclusive options like Unix sockets versus TCP endpoints.

## Frequently Asked Questions

### What is the default location for the ipsw configuration file?

By default, `ipsw` looks for a file named [`config.yaml`](https://github.com/blacktop/ipsw/blob/main/config.yaml) or [`config.yml`](https://github.com/blacktop/ipsw/blob/main/config.yml) in the `~/.config/ipsw/` directory. This path is established in [`cmd/ipsw/cmd/root.go`](https://github.com/blacktop/ipsw/blob/main/cmd/ipsw/cmd/root.go) during the `initConfig()` function execution. You can specify an alternative file using the `--config` command-line flag, which sets the configuration path before Viper attempts to load the data.

### Can I use both YAML and environment variables together?

Yes, `ipsw` is designed to merge both sources seamlessly using the Viper configuration library. When both are present, environment variables take precedence over YAML file values. For example, if `daemon.port` is set to `3993` in your YAML file but you export `IPSW_DAEMON_PORT=4000`, the daemon will listen on port 4000. This layering allows you to commit safe defaults to version control while injecting secrets or environment-specific overrides via variables.

### How do I override a specific YAML setting using an environment variable?

To override any YAML configuration value, convert the YAML key path to an environment variable by replacing dots and hyphens with underscores and prefixing with `IPSW_`. For example, to override the `database.path` setting in YAML, set the `IPSW_DATABASE_PATH` environment variable. The `caarlos0/env` package defined in [`internal/config/config.go`](https://github.com/blacktop/ipsw/blob/main/internal/config/config.go) parses these variables using struct tags, while Viper's key replacer handles the dot-to-underscore translation automatically.

### Where are the configuration struct and validation logic defined?

The core configuration structure, environment variable tags, and validation logic reside in [`internal/config/config.go`](https://github.com/blacktop/ipsw/blob/main/internal/config/config.go). This file defines the `Config` struct with `daemon` and `database` sub-structs, specifies environment variable mappings via `env` tags, and implements the `LoadConfig()`, `expandConfigPaths()`, and `verify()` functions. The Viper initialization and `initConfig()` function that orchestrates the loading process are located in [`cmd/ipsw/cmd/root.go`](https://github.com/blacktop/ipsw/blob/main/cmd/ipsw/cmd/root.go) for the CLI and [`cmd/ipswd/cmd/root.go`](https://github.com/blacktop/ipsw/blob/main/cmd/ipswd/cmd/root.go) for the daemon.