swagger: '2.0' info: title: 'AdGuard Home' description: 'AdGuard Home REST API. Admin web interface is built on top of this REST API.' version: 0.93.0 schemes: - http basePath: /control produces: - application/json tags: - name: global description: 'AdGuard Home server general settings and controls' - name: tls description: 'AdGuard Home HTTPS/DOH/DOT settings' - name: log description: 'AdGuard Home query log' - name: stats description: 'AdGuard Home statistics' - name: i18n description: 'Application localization' - name: filtering description: 'Rule-based filtering' - name: safebrowsing description: 'Blocking malware/phishing sites' - name: parental description: 'Blocking adult and explicit materials' - name: safesearch description: 'Enforce family-friendly results in search engines' - name: dhcp description: 'Built-in DHCP server controls' - name: install description: 'First-time install configuration handlers' paths: # API TO-DO LIST # TODO: Use JSON where it is possible # TODO: Use lower_case for all objects' properties # TODO: Move to definitions what's missing from there # -------------------------------------------------- # General settings and controls # -------------------------------------------------- /status: get: tags: - global operationId: status summary: 'Get DNS server current status and general settings' produces: - application/json responses: 200: description: OK schema: $ref: "#/definitions/ServerStatus" /enable_protection: post: tags: - global operationId: enableProtection summary: "Enable protection (turns on dnsfilter module in coredns)" responses: 200: description: OK /disable_protection: post: tags: - global operationId: disableProtection summary: "Disable protection (turns off filtering, sb, parental, safesearch temporarily by disabling dnsfilter module in coredns)" responses: 200: description: OK /set_upstream_dns: post: tags: - global operationId: setUpstreamDNS summary: 'Set upstream DNS for coredns, empty value will reset it to default values' consumes: - text/plain parameters: - in: body name: upstream description: 'Upstream servers, separated by newline or space, port is optional after colon' schema: # TODO: use JSON type: string example: | 1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 192.168.1.104:53535 responses: 200: description: OK /test_upstream_dns: post: tags: - global operationId: testUpstreamDNS summary: 'Test upstream DNS' consumes: - text/plain parameters: - in: body name: upstream description: 'Upstream servers, separated by newline or space, port is optional after colon' schema: # TODO: use JSON type: string example: | 1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 192.168.1.104:53535 responses: 200: description: 'Status of testing each requested server, with "OK" meaning that server works, any other text means an error.' examples: application/json: 1.1.1.1: OK 1.0.0.1: OK 8.8.8.8: OK 8.8.4.4: OK "192.168.1.104:53535": "Couldn't communicate with DNS server" /set_bootstrap_dns: post: tags: - global operationId: setBootstrapDNS summary: 'Set bootstrap DNS for DNS-over-HTTPS and DNS-over-TLS upstreams, empty value will reset it to default values' consumes: - text/plain parameters: - in: body name: upstream description: 'Bootstrap servers, separated by newline or space, port is optional after colon' schema: # TODO: use JSON type: string example: | 1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 192.168.1.104:53535 responses: 200: description: OK /version.json: get: tags: - global operationId: getVersionJson summary: 'Gets information about the latest available version of AdGuard' produces: - 'application/json' responses: 200: description: 'Version info' schema: $ref: "#/definitions/VersionInfo" 500: description: 'Cannot write answer' 502: description: 'Cannot retrieve the version.json file contents' # -------------------------------------------------- # Query log methods # -------------------------------------------------- /querylog: get: tags: - log operationId: queryLog summary: 'Get DNS server query log' parameters: - in: query name: download type: boolean description: 'If any value is set, make the browser download the query instead of displaying it by setting Content-Disposition header' responses: 200: description: OK schema: $ref: '#/definitions/QueryLog' /querylog_enable: post: tags: - log operationId: querylogEnable summary: 'Enable querylog' responses: 200: description: OK /querylog_disable: post: tags: - log operationId: querylogDisable summary: 'Disable filtering' responses: 200: description: OK # -------------------------------------------------- # General statistics methods # -------------------------------------------------- /stats_top: get: tags: - stats operationId: statusTop summary: 'Get DNS server top client, domain and blocked statistics' responses: 200: description: OK schema: $ref: "#/definitions/StatsTop" /stats: get: tags: - stats operationId: stats summary: 'Get DNS server statistics' responses: 200: description: 'Returns general statistics for the last 24 hours' schema: $ref: "#/definitions/Stats" /stats_history: get: tags: - stats operationId: stats_history summary: 'Get historical DNS server statistics for the last 24 hours' parameters: - name: start_time in: query type: string description: 'Start time in ISO8601 (example: `2018-05-04T17:55:33+00:00`)' required: true - name: end_time in: query type: string description: 'End time in ISO8601 (example: `2018-05-04T17:55:33+00:00`)' required: true - name: time_unit in: query type: string description: 'Time unit (`minutes` or `hours`)' required: true enum: - minutes - hours responses: 501: description: 'Requested time window is outside of supported range. It will be supported later, but not now.' 200: description: 'Returns historical stats for the specified time interval.' schema: $ref: '#/definitions/StatsHistory' /stats_reset: post: tags: - stats operationId: statsReset summary: "Reset all statistics to zeroes" responses: 200: description: OK # -------------------------------------------------- # TLS server methods # -------------------------------------------------- /tls/status: get: tags: - tls operationId: tlsStatus summary: "Returns TLS configuration and its status" responses: 200: description: OK schema: $ref: "#/definitions/TlsConfig" /tls/configure: post: tags: - tls operationId: tlsConfigure summary: "Updates current TLS configuration" consumes: - application/json parameters: - in: "body" name: "body" description: "TLS configuration JSON" required: true schema: $ref: "#/definitions/TlsConfig" responses: 200: description: "TLS configuration and its status" schema: $ref: "#/definitions/TlsConfig" 400: description: "Invalid configuration or unavailable port" 500: description: "Error occurred while applying configuration" /tls/validate: post: tags: - tls operationId: tlsValidate summary: "Checks if the current TLS configuration is valid" consumes: - application/json parameters: - in: "body" name: "body" description: "TLS configuration JSON" required: true schema: $ref: "#/definitions/TlsConfig" responses: 200: description: "TLS configuration and its status" schema: $ref: "#/definitions/TlsConfig" 400: description: "Invalid configuration or unavailable port" # -------------------------------------------------- # DHCP server methods # -------------------------------------------------- /dhcp/status: get: tags: - dhcp operationId: dhcpStatus summary: "Gets the current DHCP settings and status" responses: 200: description: OK schema: $ref: "#/definitions/DhcpStatus" /dhcp/set_config: post: tags: - dhcp operationId: dhcpSetConfig summary: "Updates the current DHCP server configuration" consumes: - application/json parameters: - in: "body" name: "body" description: "DHCP configuration JSON" required: true schema: $ref: "#/definitions/DhcpConfig" responses: 200: description: OK /dhcp/find_active_dhcp: post: tags: - dhcp operationId: checkActiveDhcp summary: "Searches for an active DHCP server on the network" responses: 200: description: OK schema: $ref: "#/definitions/DhcpSearchResult" # -------------------------------------------------- # Filtering status methods # -------------------------------------------------- /filtering/status: get: tags: - filtering operationId: filteringStatus summary: 'Get status of rules-based filter' responses: 200: description: OK schema: $ref: "#/definitions/FilteringStatus" /filtering/enable: post: tags: - filtering operationId: filteringEnable summary: 'Enable filtering' responses: 200: description: OK /filtering/disable: post: tags: - filtering operationId: filteringDisable summary: 'Disable filtering' responses: 200: description: OK /filtering/add_url: put: tags: - filtering operationId: filteringAddURL summary: 'Add filter URL' consumes: - text/plain parameters: - in: body name: url description: 'URL containing filtering rules' required: true schema: type: string example: 'url=https://filters.adtidy.org/windows/filters/15.txt' responses: 200: description: OK /filtering/remove_url: delete: tags: - filtering operationId: filteringRemoveURL summary: 'Remove filter URL' consumes: - text/plain parameters: - in: body name: url description: 'Previously added URL containing filtering rules' required: true schema: type: string example: 'url=https://filters.adtidy.org/windows/filters/15.txt' responses: 200: description: OK /filtering/enable_url: post: tags: - filtering operationId: filteringEnableURL summary: 'Enable filter URL' consumes: - text/plain parameters: - in: body name: url description: 'Previously added URL containing filtering rules' required: true schema: type: string example: 'url=https://filters.adtidy.org/windows/filters/15.txt' responses: 200: description: OK /filtering/disable_url: post: tags: - filtering operationId: filteringDisableURL summary: 'Disable filter URL' consumes: - text/plain parameters: - in: body name: url description: 'Previously added URL containing filtering rules' required: true schema: type: string example: 'url=https://filters.adtidy.org/windows/filters/15.txt' responses: 200: description: OK /filtering/refresh: post: tags: - filtering operationId: filteringRefresh summary: | Reload filtering rules from URLs This might be needed if new URL was just added and you dont want to wait for automatic refresh to kick in. This API request is ratelimited, so you can call it freely as often as you like, it wont create unneccessary burden on servers that host the URL. This should work as intended, a `force` parameter is offered as last-resort attempt to make filter lists fresh. If you ever find yourself using `force` to make something work that otherwise wont, this is a bug and report it accordingly. parameters: - name: force in: query type: boolean description: 'If any value is set, ignore cache and force re-download of all filters' responses: 200: description: OK with how many filters were actually updated /filtering/set_rules: put: tags: - filtering operationId: filteringSetRules summary: 'Set user-defined filter rules' consumes: - text/plain parameters: - in: body name: rules description: 'All filtering rules, one line per rule' schema: # TODO: move to definitions type: string example: '@@||yandex.ru^|' responses: 200: description: OK # -------------------------------------------------- # Safebrowsing methods # -------------------------------------------------- /safebrowsing/enable: post: tags: - safebrowsing operationId: safebrowsingEnable summary: 'Enable safebrowsing' responses: 200: description: OK /safebrowsing/disable: post: tags: - safebrowsing operationId: safebrowsingDisable summary: 'Disable safebrowsing' responses: 200: description: OK /safebrowsing/status: get: tags: - safebrowsing operationId: safebrowsingStatus summary: 'Get safebrowsing status' responses: 200: description: OK examples: application/json: enabled: false # -------------------------------------------------- # Parental control methods # -------------------------------------------------- /parental/enable: post: tags: - parental operationId: parentalEnable summary: 'Enable parental filtering' consumes: - text/plain parameters: - in: body name: sensitivity description: | Age sensitivity for parental filtering, EARLY_CHILDHOOD is 3 YOUNG is 10 TEEN is 13 MATURE is 17 required: true schema: type: string enum: - EARLY_CHILDHOOD - YOUNG - TEEN - MATURE example: 'sensitivity=TEEN' responses: 200: description: OK /parental/disable: post: tags: - parental operationId: parentalDisable summary: 'Disable parental filtering' responses: 200: description: OK /parental/status: get: tags: - parental operationId: parentalStatus summary: 'Get parental filtering status' responses: 200: description: OK examples: application/json: enabled: true sensitivity: 13 # -------------------------------------------------- # Safe search methods # -------------------------------------------------- /safesearch/enable: post: tags: - safesearch operationId: safesearchEnable summary: 'Enable safesearch' responses: 200: description: OK /safesearch/disable: post: tags: - safesearch operationId: safesearchDisable summary: 'Disable safesearch' responses: 200: description: OK /safesearch/status: get: tags: - safesearch operationId: safesearchStatus summary: 'Get safesearch status' responses: 200: description: OK examples: application/json: enabled: false # -------------------------------------------------- # I18N methods # -------------------------------------------------- /i18n/change_language: post: tags: - i18n operationId: changeLanguage summary: "Change current language. Argument must be an ISO 639-1 two-letter code" consumes: - text/plain parameters: - in: body name: language description: "New language. It must be known to the server and must be an ISO 639-1 two-letter code" schema: # TODO: use JSON? type: string example: en responses: 200: description: OK /i18n/current_language: get: tags: - i18n operationId: currentLanguage summary: "Get currently set language. Result is ISO 639-1 two-letter code. Empty result means default language." responses: 200: description: OK examples: text/plain: en # -------------------------------------------------- # First-time install configuration methods # -------------------------------------------------- /install/get_addresses: get: tags: - install operationId: installGetAddresses summary: "Gets the network interfaces information." responses: 200: description: OK schema: $ref: "#/definitions/AddressesInfo" /install/configure: post: tags: - install operationId: installConfigure summary: "Applies the initial configuration." parameters: - in: "body" name: "body" description: "Initial configuration JSON" required: true schema: $ref: "#/definitions/InitialConfiguration" responses: 200: description: OK 400: description: "Failed to parse initial configuration or cannot listen to the specified addresses" 500: description: "Cannot start the DNS server" definitions: ServerStatus: type: "object" description: "AdGuard Home server status and configuration" required: - "dns_address" - "dns_port" - "protection_enabled" - "querylog_enabled" - "running" - "bootstrap_dns" - "upstream_dns" - "version" - "language" properties: dns_address: type: "string" example: "127.0.0.1" dns_port: type: "integer" format: "int32" example: 53 minimum: 1 maximum: 65535 protection_enabled: type: "boolean" querylog_enabled: type: "boolean" running: type: "boolean" bootstrap_dns: type: "string" example: "8.8.8.8:53" upstream_dns: type: "array" items: type: "string" example: - "tls://1.1.1.1" - "tls://1.0.0.1" version: type: "string" example: "0.1" language: type: "string" example: "en" Filter: type: "object" description: "Filter subscription info" required: - "enabled" - "id" - "lastUpdated" - "name" - "rulesCount" - "url" properties: enabled: type: "boolean" id: type: "integer" example: 1234 lastUpdated: type: "string" format: "date-time" example: "2018-10-30T12:18:57.223101822+03:00" name: type: "string" example: "AdGuard Simplified Domain Names filter" rulesCount: type: "integer" example: 5912 url: type: "string" example: "https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt" FilteringStatus: type: "object" description: "Filtering settings" required: - "enabled" - "filters" - "user_rules" properties: enabled: type: "boolean" filters: type: "array" items: $ref: "#/definitions/Filter" user_rules: type: "array" items: type: "string" example: - '||example.org^' - '||example.com^' VersionInfo: type: "object" description: "Information about the latest available version of AdGuard Home" required: - "version" - "announcement" - "announcement_url" - "download_darwin_amd64" - "download_linux_amd64" - "download_linux_386" - "download_linux_arm" - "selfupdate_min_version" properties: version: type: "string" example: "v0.9" announcement: type: "string" example: "AdGuard Home v0.9 is now available!" announcement_url: type: "string" example: "https://github.com/AdguardTeam/AdGuardHome/releases/tag/v0.9" download_darwin_amd64: type: "string" example: "https://github.com/AdguardTeam/AdGuardHome/releases/download/v0.9/AdGuardHome_v0.9_MacOS.zip" download_linux_amd64: type: "string" example: "https://github.com/AdguardTeam/AdGuardHome/releases/download/v0.9/AdGuardHome_v0.9_linux_amd64.tar.gz" download_linux_386: type: "string" example: "https://github.com/AdguardTeam/AdGuardHome/releases/download/v0.9/AdGuardHome_v0.9_linux_386.tar.gz" download_linux_arm: type: "string" example: "https://github.com/AdguardTeam/AdGuardHome/releases/download/v0.9/AdGuardHome_v0.9_linux_arm.tar.gz" selfupdate_min_version: type: "string" example: "v0.0" Stats: type: "object" description: "General server stats for the last 24 hours" required: - "dns_queries" - "blocked_filtering" - "replaced_safebrowsing" - "replaced_parental" - "replaced_safesearch" - "avg_processing_time" properties: dns_queries: type: "integer" description: "Total number of DNS queries" example: 123 blocked_filtering: type: "integer" description: "Number of requests blocked by filtering rules" example: 50 replaced_safebrowsing: type: "integer" description: "Number of requests blocked by the safebrowsing module" example: 5 replaced_parental: type: "integer" description: "Number of blocked adult websites" example: 15 avg_processing_time: type: "number" format: "float" description: "Average time in milliseconds on processing a DNS" example: 0.34 StatsTop: type: "object" description: "Server stats top charts" required: - "top_queried_domains" - "top_clients" - "top_blocked_domains" properties: top_queried_domains: type: "array" items: type: "object" example: example.org: 12312 example.com: 321 example.net: 5555 top_clients: type: "array" items: type: "object" example: 127.0.0.1: 12312 192.168.0.1: 13211 192.168.0.3: 13211 top_blocked_domains: type: "array" items: type: "object" example: example.org: 12312 example.com: 321 example.net: 5555 StatsHistory: type: "object" description: "Historical stats of the DNS server. Example below is for 5 minutes. Values are from oldest to newest." required: - "dns_queries" - "blocked_filtering" - "replaced_safebrowsing" - "replaced_parental" - "replaced_safesearch" - "avg_processing_time" properties: dns_queries: type: "array" items: type: "integer" example: - 1201 - 1501 - 1251 - 1231 - 120 blocked_filtering: type: "array" items: type: "integer" example: - 421 - 124 - 5 - 12 - 43 replaced_safebrowsing: type: "array" items: type: "integer" example: - 1 - 0 - 5 - 0 - 0 replaced_parental: type: "array" items: type: "integer" example: - 120 - 10 - 5 - 12 - 1 replaced_safesearch: type: "array" items: type: "integer" example: - 1 - 0 - 0 - 0 - 5 avg_processing_time: type: "array" items: type: "number" format: "float" example: - 1.25 - 5.12 - 4.12 - 123.12 - 0.12 DhcpConfig: type: "object" description: "Built-in DHCP server configuration" required: - "enabled" - "gateway_ip" - "subnet_mask" - "range_start" - "range_end" - "lease_duration" properties: enabled: type: "boolean" gateway_ip: type: "string" example: "192.168.1.1" subnet_mask: type: "string" example: "255.255.255.0" range_start: type: "string" example: "192.168.1.2" range_end: type: "string" example: "192.168.10.50" lease_duration: type: "string" example: "12h" DhcpLease: type: "object" description: "DHCP lease information" required: - "mac" - "ip" - "hostname" - "expires" properties: mac: type: "string" example: "001109b3b3b8" ip: type: "string" example: "192.168.1.22" hostname: type: "string" example: "dell" expires: type: "string" format: "date-time" example: "2017-07-21T17:32:28Z" DhcpStatus: type: "object" description: "Built-in DHCP server configuration and status" required: - "config" - "leases" properties: config: $ref: "#/definitions/DhcpConfig" leases: type: "array" items: $ref: "#/definitions/DhcpLease" DhcpSearchResult: type: "object" description: "Information about a DHCP server discovered in the current network" required: - "found" properties: found: type: "boolean" gateway_ip: type: "string" example: "192.168.1.1" DnsAnswer: type: "object" description: "DNS answer section" properties: ttl: type: "integer" example: 55 type: type: "string" example: "A" value: type: "string" example: "217.69.139.201" DnsQuestion: type: "object" description: "DNS question section" properties: class: type: "string" example: "IN" host: type: "string" example: "example.org" type: type: "string" example: "A" QueryLogItem: type: "object" description: "Query log item" properties: answer: type: "array" items: $ref: "#/definitions/DnsAnswer" client: type: "string" example: "192.168.0.1" elapsedMs: type: "string" example: "54.023928" question: $ref: "#/definitions/DnsQuestion" filterId: type: "integer" example: 123123 description: "In case if there's a rule applied to this DNS request, this is ID of the filter that rule belongs to." rule: type: "string" example: "||example.org^" description: "Filtering rule applied to the request (if any)" reason: type: "string" description: "DNS filter status" enum: - "NotFilteredNotFound" - "NotFilteredWhiteList" - "NotFilteredError" - "FilteredBlackList" - "FilteredSafeBrowsing" - "FilteredParental" - "FilteredInvalid" - "FilteredSafeSearch" status: type: "string" description: "DNS response status" example: "NOERROR" time: type: "string" description: "DNS request processing start time" example: "2018-11-26T00:02:41+03:00" QueryLog: type: "array" description: "Query log" items: $ref: "#/definitions/QueryLogItem" TlsConfig: type: "object" description: "TLS configuration settings and status" properties: # TLS configuration enabled: type: "boolean" example: "true" description: "enabled is the encryption (DOT/DOH/HTTPS) status" server_name: type: "string" example: "example.org" description: "server_name is the hostname of your HTTPS/TLS server" force_https: type: "boolean" example: "true" description: "if true, forces HTTP->HTTPS redirect" port_https: type: "integer" format: "int32" example: 443 description: "HTTPS port. If 0, HTTPS will be disabled." port_dns_over_tls: type: "integer" format: "int32" example: 853 description: "DNS-over-TLS port. If 0, DOT will be disabled." certificate_chain: type: "string" description: "Base64 string with PEM-encoded certificates chain" private_key: type: "string" description: "Base64 string with PEM-encoded private key" # Below goes validation fields valid_cert: type: "boolean" example: "true" description: "valid_cert is true if the specified certificates chain is a valid chain of X509 certificates" valid_chain: type: "boolean" example: "true" description: "valid_chain is true if the specified certificates chain is verified and issued by a known CA" subject: type: "string" example: "CN=example.org" description: "subject is the subject of the first certificate in the chain" issuer: type: "string" example: "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US" description: "issuer is the issuer of the first certificate in the chain" not_before: type: "string" example: "2019-01-31T10:47:32Z" description: "not_before is the NotBefore field of the first certificate in the chain" not_after: type: "string" example: "2019-05-01T10:47:32Z" description: "not_after is the NotAfter field of the first certificate in the chain" dns_names: type: "array" items: type: "string" description: "dns_names is the value of SubjectAltNames field of the first certificate in the chain" example: - "*.example.org" valid_key: type: "boolean" example: "true" description: "valid_key is true if the key is a valid private key" key_type: type: "string" example: "RSA" description: "key_type is either RSA or ECDSA" warning_validation: type: "string" example: "You have specified an empty certificate" description: "warning_validation is a validation warning message with the issue description" NetInterface: type: "object" description: "Network interface info" properties: flags: type: "string" example: "up|broadcast|multicast" hardware_address: type: "string" example: "52:54:00:11:09:ba" mtu: type: "integer" format: "int32" example: 1500 name: type: "string" example: "eth0" ip_addresses: type: "array" items: type: "string" example: - "127.0.0.1" AddressInfo: type: "object" description: "Port information" properties: ip: type: "string" example: "127.0.01" port: type: "integer" format: "int32" example: 53 warning: type: "string" example: "Cannot bind to this port" AddressesInfo: type: "object" description: "AdGuard Home addresses configuration" properties: dns: $ref: "#/definitions/AddressInfo" web: $ref: "#/definitions/AddressInfo" interfaces: type: "object" description: "Network interfaces dictionary (key is the interface name)" additionalProperties: $ref: "#/definitions/NetInterface" InitialConfiguration: type: "object" description: "AdGuard Home initial configuration (for the first-install wizard)" properties: dns: $ref: "#/definitions/AddressInfo" web: $ref: "#/definitions/AddressInfo" username: type: "string" description: "Basic auth username" example: "admin" password: type: "string" description: "Basic auth password" example: "password"