How to Configure ipsw Using YAML Config Files and Environment Variables

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, 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.

YAML Configuration Files

Default Location and File Structure

By default, ipsw searches for a file named config.yaml or 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 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:

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 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 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.

Path Expansion and Validation

After Viper loads the raw configuration, 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:

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:

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:


# 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 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, with automatic key replacement for dots and hyphens.
  • Path expansion: The expandConfigPaths() function in 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 or config.yml in the ~/.config/ipsw/ directory. This path is established in 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 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. 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 for the CLI and cmd/ipswd/cmd/root.go for the daemon.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →