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.
- Boolean. Default:
cleanup- Boolean. Default:
true. - Cleans
cache_dirandbackup_dirafter a successful upgrade.
- Boolean. Default:
repository- GitHub repository. Default:
svenshi/oxidns.
- GitHub repository. Default:
asset- Release asset name.
autoselects the archive for the current platform and build bundle. - An explicit asset has the highest priority and skips
bundleinference.
- Release asset name.
bundle- Type:
auto | full | standard | minimal. - Default:
auto. - Selects the release build bundle when
asset: autois used.fulluses the legacy asset name;standard/minimaluse slim asset names with a bundle prefix.
- Type:
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.
- Path. Default:
skip_webui- Boolean. Default:
false. - When
true, only the binary is replaced and the WebUI directory upgrade is skipped.
- Boolean. Default:
no_restart- Boolean. Default:
false. - When
true, a successful upgrade does not trigger an automatic restart. - The default
falserestarts automatically after a successful upgrade: CLIapplyrestarts 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.
- Boolean. Default:
timeout,outbound,socks5,insecure_skip_verify- Same meaning as the CLI
upgradeflags. outboundreferences a profile fromnetwork.outbound.profiles. The legacysocks5field remains supported and overrides the profile proxy.
- Same meaning as the CLI
Behavior
- The executor always returns
ExecStep::Next. - The plugin only runs the
applyaction. It does not providecheckordownloadmodes. - By default it updates only when a newer version is available.
force: trueforces the update. - By default it cleans cache and backup files after a successful upgrade. Set
cleanup: falseto keep rollback files. - The upgrade downloads the archive and verifies SHA256 with the GitHub release asset
digestfield. asset: autoselects the archive frombundle;bundle: autofollows the current binary's build bundle, and custom builds must setbundleorassetexplicitly.- 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 intowebui_dir; setskip_webui: trueto skip it. If the archive has nowebui/(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
forceandforce=true|falseare supported. - Other settings use defaults. Use full
argsconfiguration to override the repository, directories, restart mode, or proxy. modeis 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
downloadsrun 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
outboundis set, downloads use the resolver and proxy defined by the referencednetwork.outbound.profilesentry. - When
socks5is set, all download connections are routed through that SOCKS5 proxy using the same format asupstream[].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: falseto disable that bootstrap behavior.
- Only
httpandhttpsare supported. - When
outboundis omitted,network.outbound.defaultis used. If bothoutboundandsocks5are set,socks5overrides the profile proxy while preserving the profile resolver. socks5acceptshost:portandusername:password@host:port; bracket IPv6 addresses such as"[::1]:1080"are supported too.startup_if_missingonly 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; ifconfig.yaml, dependency topology, or the plugin list changed too, usereload.
Recommended Pairing
- 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"
downloadwrites the subscription content to local files.reload_providerrefreshes only the affected provider snapshots without rebuilding unrelated plugins.startup_if_missing: trueis 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 fullreloadinstead.
Full Reload Still Fits Config Changes
- tag: config_refresh
type: sequence
args:
- exec: "$subscription_download"
- exec: "$reload_all"
- tag: reload_all
type: reload
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>/reloadfor 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, oradguard_ruleproviders afterdownload. - Reducing the blast radius and cost of a full application reload in background maintenance flows.
argsonly 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,reloadis still required. - Running this on a live request path may trigger file reads and recompilation, so it is usually a better fit for background
cronor maintenancesequenceflows.
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
downloadin acronjob so refreshed rule files take effect immediately. - Triggering a full configuration reload from a dedicated background
sequence.
- It must run inside a normal OxiDNS process with application control context attached.
- Execution fails when another reload is already
pendingorin_progress. - Using it in a live request
sequencetriggers 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
schedulejobs in thiscronplugin. - Notes:
- Only affects
schedule. - When omitted, OxiDNS uses the system local time zone and falls back to
UTCif unavailable. - Use IANA names such as
Asia/Shanghai,UTC, orAmerica/Los_Angeles.
- Only affects
args.jobs[].name
- Type:
string; Required: yes - Purpose: Job name used in logs and runtime metadata.
- Runtime impact:
- Must be unique within the same
cronplugin.
- Must be unique within the same
args.jobs[].schedule
- Type:
string; Required: exactly one ofscheduleorinterval - Purpose: Schedule a job with a standard 5-field cron expression.
- Notes:
- Only
minute hour day month day-of-weekis supported. - Second-level cron expressions are not supported.
- Next runs are computed in
args.timezoneor the system local time zone.
- Only
args.jobs[].interval
- Type:
string; Required: exactly one ofscheduleorinterval - Purpose: Schedule a job with a fixed interval.
- Supports:
5m1h1d
- Runtime impact:
- Minimum interval is
1m. - The first run happens after one full interval elapses.
- Minimum interval is
args.jobs[].executors
- Type:
array; Required: yes - Purpose: Ordered list of executors to run for the job.
- Supports:
$tagexplicit executor references- bare
tagreferences - 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
scheduleandintervalare mutually exclusive.- If a job is still running when the next trigger arrives, that trigger is skipped and not replayed later.
- Jobs run with an empty
DnsContext, so this plugin is best suited for side-effect executors or dedicated backgroundsequencechains. cronitself cannot be executed inside a normal requestsequence.
Typical Uses
- Periodic side-effect tasks.
- Scheduling a dedicated background
sequence. - Providing a common trigger surface for future executors such as
reload.
- A
cronjob cannot reference anothercronexecutor. - Executors that require a real DNS request usually do not make sense in an empty background context.