Skip to main content

Maintenance and Scheduling

These executors handle downloads, upgrades, provider reloads, full reloads, and background scheduling. Restrict triggers and prepare rollback in production.

upgrade​

Purpose​

Runs the OxiDNS upgrade flow from the executor pipeline. It is suitable for maintenance tasks triggered by cron, sequence, or another executor.

Example Configuration​

- tag: upgrade_auto
type: upgrade
args:
repository: svenshi/oxidns
asset: auto
bundle: auto
github_token: ghp_xxx
cache_dir: ./upgrade/cache
backup_dir: ./upgrade/backups
webui_dir: ./webui
skip_webui: false
no_restart: false
force: false
cleanup: true
timeout: 30s
outbound: remote
socks5: 127.0.0.1:1080
insecure_skip_verify: false

Options​

  • force
    • Boolean. Default: false.
    • Continue downloading, verifying, and replacing even when the selected release is not newer than the current version.
  • cleanup
    • Boolean. Default: true.
    • Cleans cache_dir and backup_dir after a successful upgrade.
  • repository
    • GitHub repository. Default: svenshi/oxidns.
  • asset
    • Release asset name. auto selects the archive for the current platform and build bundle.
    • An explicit asset has the highest priority and skips bundle inference.
  • bundle
    • Type: auto | full | standard | minimal.
    • Default: auto.
    • Selects the release build bundle when asset: auto is used. full uses the legacy asset name; standard / minimal use slim asset names with a bundle prefix.
  • github_token
    • GitHub personal access token for API requests, used to raise the rate limit or access private repositories.
    • The value is sent as a Bearer token on GitHub API requests.
  • cache_dir / backup_dir
    • Download cache and pre-replacement backup directories.
  • webui_dir
    • Path. Default: ./webui.
    • Directory where the WebUI static assets are installed during an upgrade; keep it aligned with api.http.webui.root.
  • skip_webui
    • Boolean. Default: false.
    • When true, only the binary is replaced and the WebUI directory upgrade is skipped.
  • no_restart
    • Boolean. Default: false.
    • When true, a successful upgrade does not trigger an automatic restart.
    • The default false restarts automatically after a successful upgrade: CLI apply restarts the installed service through the system service manager, while the executor requests a graceful in-process restart through the application control channel so the new binary is loaded.
  • timeout, outbound, socks5, insecure_skip_verify
    • Same meaning as the CLI upgrade flags.
    • outbound references a profile from network.outbound.profiles. The legacy socks5 field remains supported and overrides the profile proxy.

Behavior​

  • The executor always returns ExecStep::Next.
  • The plugin only runs the apply action. It does not provide check or download modes.
  • By default it updates only when a newer version is available. force: true forces the update.
  • By default it cleans cache and backup files after a successful upgrade. Set cleanup: false to keep rollback files.
  • The upgrade downloads the archive and verifies SHA256 with the GitHub release asset digest field.
  • asset: auto selects the archive from bundle; bundle: auto follows the current binary's build bundle, and custom builds must set bundle or asset explicitly.
  • On Unix it unpacks .tar.gz, backs up the current binary, and replaces it. Windows currently does not support plugin upgrades.
  • By default, after replacing the binary it backs up and installs the archive's webui/ directory into webui_dir; set skip_webui: true to skip it. If the archive has no webui/ (older releases), the WebUI upgrade is skipped without affecting the binary upgrade result.

quick setup​

- exec: upgrade
- exec: upgrade force
- exec: upgrade force=false
- exec: upgrade bundle=standard
  • Empty arguments run apply with the default configuration.
  • Only force and force=true|false are supported.
  • Other settings use defaults. Use full args configuration to override the repository, directories, restart mode, or proxy.
  • mode is not supported; the plugin always applies upgrades.

download​

Purpose​

Downloads one or more http/https files into a local directory and overwrites the target files only after the new content is fully written.

Example Configuration​

- tag: rules_download
type: download
args:
timeout: 30s
outbound: remote
socks5: "127.0.0.1:1080"
downloads:
- url: "https://example.com/geosite.dat"
dir: "/etc/oxidns"
- url: "https://example.com/geoip.dat"
dir: "/etc/oxidns"
filename: "geoip.dat"

Quick Setup​

- exec: "download https://example.com/rules.txt /etc/oxidns"

Behavior​

  • downloads run sequentially in declaration order.
  • A failed item only emits a warning log and does not stop later items.
  • Missing target directories are created automatically.
  • Files are written to a temporary path first and then moved into place.
  • When outbound is set, downloads use the resolver and proxy defined by the referenced network.outbound.profiles entry.
  • When socks5 is set, all download connections are routed through that SOCKS5 proxy using the same format as upstream[].socks5.
  • By default, OxiDNS checks target files during startup and downloads any missing ones before other plugins initialize. A bootstrap failure aborts startup.
  • Set startup_if_missing: false to disable that bootstrap behavior.
Notes
  • Only http and https are supported.
  • When outbound is omitted, network.outbound.default is used. If both outbound and socks5 are set, socks5 overrides the profile proxy while preserving the profile resolver.
  • socks5 accepts host:port and username:password@host:port; bracket IPv6 addresses such as "[::1]:1080" are supported too.
  • startup_if_missing only fills missing files; it does not overwrite existing targets on every startup.
  • When used inside a normal sequence, the download time is paid directly by that request.
  • Overwriting a local file does not apply automatically. For file-backed providers that only need to pick up new data, prefer chaining reload_provider; if config.yaml, dependency topology, or the plugin list changed too, use reload.
- tag: rules_refresh
type: sequence
args:
- exec: "$rules_download"
- exec: "$reload_rules"

- tag: rules_download
type: download
args:
downloads:
- url: "https://example.com/geosite.dat"
dir: "/etc/oxidns"

- tag: provider_geosite
type: geosite
args:
file: "/etc/oxidns/geosite.dat"

- tag: reload_rules
type: reload_provider
args:
- "$provider_geosite"

Subscription Refresh Example​

This example fits the common flow of “remote subscription -> scheduled download -> targeted provider refresh”:

plugins:
# 1. Run the subscription refresh flow periodically
- tag: subscription_cron
type: cron
args:
timezone: "Asia/Shanghai"
jobs:
- name: refresh_rule_subscriptions
interval: 6h
executors:
- "$subscription_refresh"

# 2. Chain download and targeted provider reload with a sequence
- tag: subscription_refresh
type: sequence
args:
- exec: "$subscription_download"
- exec: "$reload_rule_providers"

# 3. Download remote subscription files
- tag: subscription_download
type: download
args:
timeout: 60s
startup_if_missing: true
downloads:
- url: "https://example.com/geosite.dat"
dir: "/etc/oxidns/rules"
filename: "geosite.dat"
- url: "https://example.com/geoip.dat"
dir: "/etc/oxidns/rules"
filename: "geoip.dat"

# 4. Reload only the affected providers after download completes
- tag: reload_rule_providers
type: reload_provider
args:
- "$provider_geosite"
- "$provider_geoip"

# 5. These providers re-read the local files after reload
- tag: provider_geosite
type: geosite
args:
file: "/etc/oxidns/rules/geosite.dat"

- tag: provider_geoip
type: geoip
args:
file: "/etc/oxidns/rules/geoip.dat"
Notes
  • download writes the subscription content to local files.
  • reload_provider refreshes only the affected provider snapshots without rebuilding unrelated plugins.
  • startup_if_missing: true is useful for first-time deployment when files may not exist yet.
  • If the subscription source requires a proxy, set a SOCKS5 proxy on subscription_download.args.socks5.
  • To avoid overwriting existing files at startup, keep the default behavior and only bootstrap missing files.
  • If the update also changes config.yaml, provider topology, or the plugin list, use a full reload instead.

Full Reload Still Fits Config Changes​

- tag: config_refresh
type: sequence
args:
- exec: "$subscription_download"
- exec: "$reload_all"

- tag: reload_all
type: reload

Manual downloads​

The WebUI download plugin detail view provides a Download all button above the live download list and a Download button for each item. Buttons show progress and are disabled during an active download. The result reports success and failure counts; a failed item does not stop subsequent downloads. Apply configuration changes before using the updated list.

The corresponding management API supports single-item and batch downloads. Manual downloads only update files; reload the relevant providers separately when rules need to be refreshed.

reload_provider​

Purpose​

Reloads one or more providers in place by tag, rebuilding their internal snapshots with the same startup configuration without triggering a full application reload.

Example Configuration​

- tag: reload_rule_providers
type: reload_provider
args:
- "$geosite_cn"
- "$geoip_cn"

Quick Setup​

- exec: "reload_provider $geosite_cn"

Behavior​

  • Providers are reloaded sequentially in the order declared in args.
  • The semantics are the same as calling POST /plugins/<provider_tag>/reload for each referenced provider.
  • Once every provider reload succeeds, the executor returns Next.
  • Only provider-local data is refreshed; tags, dependencies, and other plugin configuration are unchanged.

Typical Uses​

  • Refreshing only the affected domain_set, ip_set, geosite, geoip, or adguard_rule providers after download.
  • Reducing the blast radius and cost of a full application reload in background maintenance flows.
Notes
  • args only accepts provider references such as "$geoip_cn"; inline rules and file references are rejected.
  • If the update changes config.yaml, provider topology, the plugin list, or other non-provider structures, reload is still required.
  • Running this on a live request path may trigger file reads and recompilation, so it is usually a better fit for background cron or maintenance sequence flows.

reload​

Purpose​

Triggers the same application-level full reload as the management API POST /reload, reloading the active configuration and rebuilding all plugins.

Example Configuration​

- tag: reload_all
type: reload

Quick Setup​

- exec: "reload"

Behavior​

  • Execution submits a reload request to the application control layer.
  • The semantics are the same as the management API POST /reload.
  • Once the reload request is accepted, the executor returns Next.
  • This is a full application reload. Reloading selected plugin tags is not supported.

Typical Uses​

  • Pairing with download in a cron job so refreshed rule files take effect immediately.
  • Triggering a full configuration reload from a dedicated background sequence.
Notes
  • It must run inside a normal OxiDNS process with application control context attached.
  • Execution fails when another reload is already pending or in_progress.
  • Using it in a live request sequence triggers a full application reload and is usually not appropriate for latency-sensitive request paths.

cron​

Purpose​

Schedules a list of executors in the background. It does not participate in the live DNS request path and starts running only after plugin initialization.

Example Configuration​

- tag: cron_jobs
type: cron
args:
timezone: "Asia/Shanghai"
jobs:
- name: refresh_sets
interval: 5m
executors:
- "$seq_refresh"
- "debug_print cron refresh"

- name: nightly_cleanup
schedule: "15 3 * * *"
executors:
- "sleep 2s"
- "$seq_cleanup"

Configuration Details​

args.jobs​

  • Type: array; Required: yes
  • Purpose: Defines one or more background jobs.
  • Runtime impact:
    • The array cannot be empty.
    • Each job maintains its own trigger state and overlap protection.

args.timezone​

  • Type: string; Required: no
  • Default: system local time zone
  • Purpose: Overrides the time zone used by all schedule jobs in this cron plugin.
  • Notes:
    • Only affects schedule.
    • When omitted, OxiDNS uses the system local time zone and falls back to UTC if unavailable.
    • Use IANA names such as Asia/Shanghai, UTC, or America/Los_Angeles.

args.jobs[].name​

  • Type: string; Required: yes
  • Purpose: Job name used in logs and runtime metadata.
  • Runtime impact:
    • Must be unique within the same cron plugin.

args.jobs[].schedule​

  • Type: string; Required: exactly one of schedule or interval
  • Purpose: Schedule a job with a standard 5-field cron expression.
  • Notes:
    • Only minute hour day month day-of-week is supported.
    • Second-level cron expressions are not supported.
    • Next runs are computed in args.timezone or the system local time zone.
    • TaskCenter re-anchors deadlines to the system wall clock, so NTP or manual clock adjustments affect future runs.

args.jobs[].interval​

  • Type: string; Required: exactly one of schedule or interval
  • Purpose: Schedule a job with a fixed interval.
  • Supports:
    • 5m
    • 1h
    • 1d
  • Runtime impact:
    • Minimum interval is 1m.
    • The first run happens after one full interval elapses.
    • Fixed intervals use monotonic time and are not affected by wall-clock adjustments.

args.jobs[].executors​

  • Type: array; Required: yes
  • Purpose: Ordered list of executors to run for the job.
  • Supports:
    • $tag explicit executor references
    • bare tag references
    • quick-setup expressions such as debug_print cron refresh
  • Runtime impact:
    • The array cannot be empty.
    • Later executors still run even if an earlier executor returns Stop, produces a response, or fails.

Behavior​

  • schedule and interval are mutually exclusive.
  • If a job is still running when the next trigger arrives, that trigger is skipped and not replayed later.
  • The management API and WebUI can start an individual job manually with the same overlap protection as scheduled triggers. Manual runs do not change the existing interval or cron-expression schedule.
  • Scheduled and manual runs of one job share an increasing run ID. Runtime state retains only the current run and latest manual result, not history.
  • Executor errors are counted while later executors continue. A clean chain is completed, ordinary executor errors produce completed_with_errors, a panic produces failed, and destruction, reload, or shutdown cancellation produces cancelled.
  • Jobs run with an empty DnsContext, so this plugin is best suited for side-effect executors or dedicated background sequence chains.
  • cron itself cannot be executed inside a normal request sequence.

Typical Uses​

  • Periodic side-effect tasks.
  • Scheduling a dedicated background sequence.
  • Running or validating an individual maintenance job on demand from the WebUI.
  • Providing a common trigger surface for future executors such as reload.
Notes
  • A cron job cannot reference another cron executor.
  • Executors that require a real DNS request usually do not make sense in an empty background context.