Break: Migrate to Hugo (#3609)
* import migrate directory * create _index.html & docs.html * move products -> content * migrate docs-configs -> data yaml * initial code style * remove docs-engine content * normalize; fix links, images, frontmatter * mdx -> hugo partials * rewrite partial & component imports * rename list pages to _index.md * import robots.txt file * rm -rf products * import static content files * import assets directory * import layouts directory * import config.toml file * import .vscode dir * update root files * update github actions * import Pages build scripts * remove migrate directory * remove component dirs * remove website dir * manual: import content-table page layout w/ overrides * manual: fix runtime-api html markup * manual: whitespace for quickstarts * manual: update example pages * manual: update root files * manual: update pages tutorial layout * manual: import stylesheets * manual: fix layout, sidebar, pages-images * manual: remove duplicate `content/*/images` files * fix(sidebar): render expanded subnav when section-index active; - example: /workers/platform/ - example: /workers/platform/sites/ * manual: ensure correct product names in sidebar * fix(sidebar): ensure "/examples/" pages not in sidebar * manual: import icons, favicon, & manifest * manual: valid og:image asset paths * fix(theme): only auto-detect system theme if no lcs value * fix(events): handle focus attrs for topbar search inputs * fix: attach `home.ts` script to `home` layout * manual: misc formatting fixes * fix(highlight): find/render indented code snippets * chore: file perm changes post-build * updating image paths * manual: code formatting updates; - add code fences if missing - remove useless trailing newline * fix links in headers * manual: more `highlight` code normalization; - allow `content/images` directory to be highlighted * convert link to markdown for styling * Override layout for DDOS landing pages * manual: generate `sponsorships.html` page * manual: feedback batch * fix theme button * fix(theme): operation ordering, oops * chore: save format output Co-authored-by: Jon Kuperman <jon.kuperman@gmail.com>
13
.editorconfig
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = false
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
5
.github/ISSUE_TEMPLATE/issue_template.md
vendored
|
|
@ -4,17 +4,20 @@ about: Submit this issue to help us improve documentation
|
|||
title: ''
|
||||
labels: documentation
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
Link to the documentation or explain the expected outcome of following the documentation.
|
||||
|
||||
### Actual Behavior
|
||||
|
||||
Explain what actually happens when you follow the documentation.
|
||||
|
||||
### Section that requires update
|
||||
|
||||
Provide a link to the page that needs an update and be specific about which section requires the update.
|
||||
|
||||
### Additional information
|
||||
|
||||
Any other details or screenshots you think are relevant.
|
||||
|
|
|
|||
1113
.github/workflows/build.yml
vendored
48
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '_ignore/**' # todo
|
||||
- '_components/**' # todo
|
||||
branches:
|
||||
- '**'
|
||||
tags-ignore:
|
||||
- '**'
|
||||
pull_request:
|
||||
branches:
|
||||
- production
|
||||
- dev # todo
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
- name: (env) pnpm
|
||||
run: curl -L https://raw.githubusercontent.com/pnpm/self-installer/master/install.js | node
|
||||
- run: pnpm install
|
||||
# - run: pnpm run lint
|
||||
|
||||
compile:
|
||||
name: Compiles
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
- uses: peaceiris/actions-hugo@v2
|
||||
with:
|
||||
hugo-version: '0.92.0'
|
||||
extended: true
|
||||
- name: (env) pnpm
|
||||
run: curl -L https://raw.githubusercontent.com/pnpm/self-installer/master/install.js | node
|
||||
- run: pnpm install
|
||||
- run: hugo --minify
|
||||
1866
.github/workflows/deploy.yml
vendored
185
.github/workflows/preview.yml
vendored
|
|
@ -1,185 +0,0 @@
|
|||
name: Preview
|
||||
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
name: Check preview label
|
||||
outputs:
|
||||
result: ${{ steps.step1.outputs.result || 'false' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set env variable to true when label is present
|
||||
id: step1
|
||||
if: ${{ contains( github.event.pull_request.labels.*.name, 'preview' ) }}
|
||||
run: echo "::set-output name=result::true"
|
||||
|
||||
changes:
|
||||
name: "Check for docs changes"
|
||||
needs: preview
|
||||
if: ${{ needs.preview.outputs.result == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
outputs:
|
||||
products: ${{ steps.filter.outputs.products }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dorny/paths-filter@v2.4.2
|
||||
id: filter
|
||||
with:
|
||||
list-files: shell
|
||||
filters: |
|
||||
products:
|
||||
- 'products/**'
|
||||
- run: echo ${{ steps.filter.outputs.products_files }}
|
||||
- name: Setup NodeJS
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.2.0
|
||||
- name: Get PR number
|
||||
env:
|
||||
PRNUMBER: ${{ steps.filter.outputs.products == 'true' && format(github.event.number) || '0' }}
|
||||
run: echo "pr_number=${{ env.PRNUMBER }}" >> $GITHUB_ENV
|
||||
- name: Checkout changes
|
||||
if: ${{ env.pr_number != '0' }}
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.workflow_run.head_sha }}
|
||||
- name: Checkout docs engine
|
||||
if: ${{ env.pr_number != '0' }}
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "cloudflare/cloudflare-docs-engine"
|
||||
path: "engine"
|
||||
|
||||
- name: Install docs engine
|
||||
if: ${{ env.pr_number != '0' }}
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE/engine
|
||||
yarn link
|
||||
- name: Build updated docs
|
||||
if: ${{ env.pr_number != '0' }}
|
||||
run: |
|
||||
while read tile; do
|
||||
echo "Building $tile..."
|
||||
if [ $tile == "developers.cloudflare.com" ]; then
|
||||
pushd developers.cloudflare.com
|
||||
yarn install --pure-lockfile
|
||||
yarn build
|
||||
popd
|
||||
else
|
||||
if [ ! -d "products/$tile" ]; then
|
||||
echo "Warning: Skipping build because the 'products/$tile' directory no longer exists"
|
||||
continue
|
||||
fi
|
||||
pushd products/$tile
|
||||
yarn link cloudflare-docs-engine
|
||||
mkdir .docs
|
||||
yarn ghactionsbootstrap
|
||||
yarn build
|
||||
popd
|
||||
fi
|
||||
done < <(echo ${{ steps.filter.outputs.products_files }} | node ./get-products-from-file-paths.js)
|
||||
env:
|
||||
WORKERS_ENV: development
|
||||
|
||||
- name: Publish preview
|
||||
if: ${{ env.pr_number != '0' }}
|
||||
run: |
|
||||
export WRANGLER_HOME="$HOME"
|
||||
mkdir -p "$HOME/.wrangler"
|
||||
chmod -R 770 "$HOME/.wrangler"
|
||||
export CF_API_TOKEN=${{ secrets.CF_API_TOKEN }}
|
||||
yarn global add "@cloudflare/wrangler"
|
||||
COPIED="false"
|
||||
while read tile; do
|
||||
if [ $tile == "developers.cloudflare.com" ]; then
|
||||
pushd developers.cloudflare.com
|
||||
if [ $COPIED == "false" ]; then
|
||||
cp wrangler.toml ${GITHUB_WORKSPACE}/
|
||||
COPIED=true
|
||||
fi
|
||||
echo "
|
||||
[env.preview]
|
||||
# Opt into backwards-incompatible changes through September 17, 2021.
|
||||
compatibility_date = "2021-09-17"
|
||||
name = \"pr-$prnumber\"
|
||||
type = \"webpack\"
|
||||
route = \"https://pr-$prnumber.cloudflare-docs.workers.dev/*\"
|
||||
account_id = \"b54f07a6c269ecca2fa60f1ae4920c99\"
|
||||
workers_dev = \"true\" " >> wrangler.toml
|
||||
wrangler publish -e $ENVIRONMENT
|
||||
popd
|
||||
else
|
||||
if [ ! -d "products/$tile" ]; then
|
||||
echo "Warning: Skipping publish because the 'products/$tile' directory no longer exists"
|
||||
continue
|
||||
fi
|
||||
pushd products/$tile
|
||||
if [ $COPIED == "false" ]; then
|
||||
cp wrangler.toml ${GITHUB_WORKSPACE}/
|
||||
COPIED=true
|
||||
fi
|
||||
echo "
|
||||
[env.preview]
|
||||
# Opt into backwards-incompatible changes through September 17, 2021.
|
||||
compatibility_date = "2021-09-17"
|
||||
name = \"pr-$prnumber-$tile\"
|
||||
type = \"webpack\"
|
||||
account_id = \"b54f07a6c269ecca2fa60f1ae4920c99\"
|
||||
workers_dev = \"true\" " >> wrangler.toml
|
||||
wrangler publish -e $ENVIRONMENT
|
||||
popd
|
||||
fi
|
||||
done < <(echo ${{ steps.filter.outputs.products_files }} | node ./get-products-from-file-paths.js)
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
# iconv removes emoji in output; xargs does a trim
|
||||
echo "SUBDOMAIN=$(wrangler subdomain | iconv -c -f utf-8 -t ascii | xargs)" >> $GITHUB_ENV
|
||||
env:
|
||||
prnumber: ${{env.pr_number}}
|
||||
ENVIRONMENT: preview
|
||||
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
|
||||
- name: Build PR comment with URLs
|
||||
if: ${{ env.pr_number != '0' }}
|
||||
id: build-comment
|
||||
run: |
|
||||
BASE_URL=$(echo "https://pr-${PR}.${SUBDOMAIN}")
|
||||
# %0A is escaped newline:
|
||||
# https://github.com/peter-evans/create-or-update-comment/issues/51
|
||||
MESSAGE="[Previewer] Preview up to commit \`${SHA::7}\` available at the following URIs:%0A"
|
||||
while read tile; do
|
||||
if [ $tile == "developers.cloudflare.com" ]; then
|
||||
CURR_URL=${BASE_URL}
|
||||
MESSAGE="${MESSAGE}- ${CURR_URL}%0A"
|
||||
else
|
||||
if [ ! -d "products/$tile" ]; then
|
||||
continue
|
||||
fi
|
||||
CURR_URL="https://pr-${PR}-${tile}.${SUBDOMAIN}"
|
||||
MESSAGE="${MESSAGE}- ${CURR_URL}/${tile}%0A"
|
||||
fi
|
||||
done < <(echo ${{ steps.filter.outputs.products_files }} | node ./get-products-from-file-paths.js)
|
||||
echo ::set-output name=body::$MESSAGE
|
||||
env:
|
||||
SUBDOMAIN: ${{ env.SUBDOMAIN }}
|
||||
PR: ${{ env.pr_number }}
|
||||
SHA: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Find comment about preview
|
||||
if: ${{ env.pr_number != '0' }}
|
||||
uses: peter-evans/find-comment@v1
|
||||
id: find-comment
|
||||
with:
|
||||
issue-number: ${{ env.pr_number }}
|
||||
body-includes: "[Previewer]"
|
||||
|
||||
- name: Create or update comment
|
||||
if: ${{ env.pr_number != '0' }}
|
||||
uses: peter-evans/create-or-update-comment@v1
|
||||
with:
|
||||
comment-id: ${{ steps.find-comment.outputs.comment-id }}
|
||||
issue-number: ${{ env.pr_number }}
|
||||
body: ${{ steps.build-comment.outputs.body }}
|
||||
edit-mode: replace
|
||||
13
.gitignore
vendored
|
|
@ -1,8 +1,7 @@
|
|||
.docs
|
||||
node_modules
|
||||
package-lock.json
|
||||
dist/worker.js
|
||||
products/*/dist/worker.js
|
||||
products/*/package-lock.json
|
||||
.DS_Store
|
||||
product-icons/*
|
||||
node_modules
|
||||
*-lock.*
|
||||
*.lock
|
||||
*.log
|
||||
|
||||
/public
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
MD001: false
|
||||
MD002: false
|
||||
MD003: false
|
||||
MD004: false
|
||||
MD005: false
|
||||
MD006: false
|
||||
MD007: false
|
||||
MD010: false
|
||||
MD011: false
|
||||
MD013: false
|
||||
MD014: false
|
||||
MD018: false
|
||||
MD019: false
|
||||
MD020: false
|
||||
MD021: false
|
||||
MD022: false
|
||||
MD023: false
|
||||
MD024: false
|
||||
MD025: false
|
||||
MD026: false
|
||||
MD027: false
|
||||
MD028: false
|
||||
MD029: false
|
||||
MD030: false
|
||||
MD031: false
|
||||
MD032: false
|
||||
MD033: false
|
||||
MD034: false
|
||||
MD035: false
|
||||
MD036: false
|
||||
MD037: false
|
||||
MD038: false
|
||||
MD039: false
|
||||
MD040: false
|
||||
MD041: false
|
||||
MD042: false
|
||||
MD043: false
|
||||
MD044: false
|
||||
MD045: false
|
||||
MD046: false
|
||||
MD047: false
|
||||
MD048: false
|
||||
3
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"files.insertFinalNewline": false
|
||||
}
|
||||
|
|
@ -4,15 +4,15 @@
|
|||
|
||||
[Open an issue](https://github.com/cloudflare/cloudflare-docs/issues/new/choose) when something in the content is incorrect, out-of-date, or if the documentation doesn’t match the actual functionality. The items below are covered in our issue template.
|
||||
|
||||
* What is the expected behavior?
|
||||
* Link to the documentation or explain the expected outcome of following the documentation.
|
||||
* What is the actual behavior?
|
||||
* Explain what actually happens when you follow the documentation.
|
||||
* Which part of the documentation requires an update?
|
||||
* Provide a link to the page that needs an update and be specific about which section requires the update.
|
||||
* Additional information
|
||||
* Any other details or screenshots you think are relevant.
|
||||
* Issue Labels
|
||||
- What is the expected behavior?
|
||||
- Link to the documentation or explain the expected outcome of following the documentation.
|
||||
- What is the actual behavior?
|
||||
- Explain what actually happens when you follow the documentation.
|
||||
- Which part of the documentation requires an update?
|
||||
- Provide a link to the page that needs an update and be specific about which section requires the update.
|
||||
- Additional information
|
||||
- Any other details or screenshots you think are relevant.
|
||||
- Issue Labels
|
||||
|
||||
## Pull Requests
|
||||
|
||||
|
|
@ -20,20 +20,19 @@ Before proposing significant changes, open an issue so that we can discuss your
|
|||
|
||||
### Pull Request Guidelines
|
||||
|
||||
* Commits and commit messages
|
||||
* Use smaller commits for your work to make it easier to review. In your commit messages, be specific about what you changed in the files.
|
||||
* Pull request titles
|
||||
* Follow the title structure of [Product Name]+ work you did + affected file(s)
|
||||
* Example: [Access] fix broken link in example_file.md
|
||||
* Pull request descriptions
|
||||
* Use bullet points to summarize the changes in the commits
|
||||
* Add any other information you think is helpful or needs addressed. If your PR fixes an open issue, indicate that your PR is addressing the issue and provide a link to the issue.
|
||||
|
||||
- Commits and commit messages
|
||||
- Use smaller commits for your work to make it easier to review. In your commit messages, be specific about what you changed in the files.
|
||||
- Pull request titles
|
||||
- Follow the title structure of [Product Name]+ work you did + affected file(s)
|
||||
- Example: [Access] fix broken link in example_file.md
|
||||
- Pull request descriptions
|
||||
- Use bullet points to summarize the changes in the commits
|
||||
- Add any other information you think is helpful or needs addressed. If your PR fixes an open issue, indicate that your PR is addressing the issue and provide a link to the issue.
|
||||
|
||||
## Package manager
|
||||
|
||||
* [Yarn](https://classic.yarnpkg.com/en/docs/install) is the recommended package manager that must be used in installing dependencies.
|
||||
* Generated yarn.lock files must be committed to git.
|
||||
|
||||
- [Yarn](https://classic.yarnpkg.com/en/docs/install) is the recommended package manager that must be used in installing dependencies.
|
||||
- Generated yarn.lock files must be committed to git.
|
||||
|
||||
A member of the Product Content Experience team will review the pull request. If the changes are straightforward, the pull request is approved and can be merged. If the pull request is more technical and requires an additional review, the new reviewer will leave any additional feedback.
|
||||
If a pull request is not approved, the “won't fix” label is applied and a comment is added to explain why the pull request was closed.
|
||||
|
|
|
|||
8
Makefile
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
download:
|
||||
curl -L https://github.com/tdewolff/minify/releases/download/v2.9.24/minify_linux_amd64.tar.gz > minify.tar.gz
|
||||
tar -xf minify.tar.gz
|
||||
|
||||
build: download
|
||||
npm run format -- --quiet
|
||||
npm run build
|
||||
./minify -r public -o .
|
||||
85
README.md
|
|
@ -1,6 +1,6 @@
|
|||
# Cloudflare Docs
|
||||
|
||||
__[View the docs →](https://developers.cloudflare.com/docs/)__
|
||||
**[View the docs →](https://developers.cloudflare.com/docs/)**
|
||||
|
||||
[Contribute to the docs](https://developers.cloudflare.com/docs-engine/contributing/to-cloudflare-docs)
|
||||
|
||||
|
|
@ -8,51 +8,51 @@ __[View the docs →](https://developers.cloudflare.com/docs/)__
|
|||
|
||||
## For Cloudflare employees
|
||||
|
||||
To get write access to this repo, please reach out to the __Developer Docs__ room in chat.
|
||||
To get write access to this repo, please reach out to the **Developer Docs** room in chat.
|
||||
|
||||
## Products
|
||||
|
||||
| Product | `pathPrefix` | Test | Prod |
|
||||
| :---------------------- | :------------------- | :------------------------------------------------------------------------------------ | :------------------------------------------------------------- |
|
||||
| 1.1.1.1 | 1.1.1.1 | [Test](https://1-1-1-1.cloudflare-docs.workers.dev/1.1.1.1) | [Prod](https://developers.cloudflare.com/1.1.1.1) |
|
||||
| Analytics | analytics | [Test](https://analytics.cloudflare-docs.workers.dev/analytics) | [Prod](https://developers.cloudflare.com/analytics) |
|
||||
| API | api | [Test](https://api.cloudflare-docs.workers.dev/api) | [Prod](https://developers.cloudflare.com/api) |
|
||||
| Product | `pathPrefix` | Test | Prod |
|
||||
| :------------------------------ | :------------------------------ | :---------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------ |
|
||||
| 1.1.1.1 | 1.1.1.1 | [Test](https://1-1-1-1.cloudflare-docs.workers.dev/1.1.1.1) | [Prod](https://developers.cloudflare.com/1.1.1.1) |
|
||||
| Analytics | analytics | [Test](https://analytics.cloudflare-docs.workers.dev/analytics) | [Prod](https://developers.cloudflare.com/analytics) |
|
||||
| API | api | [Test](https://api.cloudflare-docs.workers.dev/api) | [Prod](https://developers.cloudflare.com/api) |
|
||||
| Automatic Platform Optimization | automatic-platform-optimization | [Test](https://automatic-platform-optimization.cloudflare-docs.workers.dev/automatic-platform-optimization) | [Prod](https://developers.cloudflare.com/automatic-platform-optimization) |
|
||||
| Bots | bots | [Test](https://bots.cloudflare-docs.workers.dev/bots) | [Prod](https://developers.cloudflare.com/bots)
|
||||
| BYOIP | byoip | [Test](https://byoip.cloudflare-docs.workers.dev/byoip) | [Prod](https://developers.cloudflare.com/byoip) |
|
||||
| Cache | cache | [Test](https://cache.cloudflare-docs.workers.dev/cache/) | [Prod](https://developers.cloudflare.com/cache/) |
|
||||
| Cloudflare One | cloudflare-one | [Test](https://cloudflare-one.cloudflare-docs.workers.dev/cloudflare-one) | [Prod](https://developers.cloudflare.com/cloudflare-one) |
|
||||
| DDoS Protection | ddos-protection | [Test](https://ddos-protection.cloudflare-docs.workers.dev/ddos-protection) | [Prod](https://developers.cloudflare.com/ddos-protection) |
|
||||
| Distributed Web Gateway | distributed-web | [Test](https://distributed-web.cloudflare-docs.workers.dev/distributed-web) | [Prod](https://developers.cloudflare.com/distributed-web) |
|
||||
| Docs Engine | docs-engine | [Test](https://docs-engine.cloudflare-docs.workers.dev/docs-engine) | [Prod](https://developers.cloudflare.com/docs-engine) |
|
||||
| Email Routing | email-routing | [Test](https://email-routing.cloudflare-docs.workers.dev/email-routing) | [Prod](https://developers.cloudflare.com/email-routing) |
|
||||
| Events | events | [Test](https://events.cloudflare-docs.workers.dev/events) | [Prod](https://developers.cloudflare.com/events) |
|
||||
| Firewall | firewall | [Test](https://firewall.cloudflare-docs.workers.dev/firewall) | [Prod](https://developers.cloudflare.com/firewall) |
|
||||
| Fundamentals | fundamentals | [Test](https://fundamentals.cloudflare-docs.workers.dev/fundamentals) | [Prod](https://developers.cloudflare.com/fundamentals) |
|
||||
| HTTP/3 | http3 | [Test](https://http3.cloudflare-docs.workers.dev/http3) | [Prod](https://developers.cloudflare.com/http3) |
|
||||
| Image Optimization | images | [Test](https://images.cloudflare-docs.workers.dev/images) | [Prod](https://developers.cloudflare.com/images) |
|
||||
| Load Balancing | load-balancing | [Test](https://load-balancing.cloudflare-docs.workers.dev/load-balancing) | [Prod](https://developers.cloudflare.com/load-balancing) |
|
||||
| Logs | logs | [Test](https://logs.cloudflare-docs.workers.dev/logs) | [Prod](https://developers.cloudflare.com/logs) |
|
||||
| Magic Firewall | magic-firewall | [Test](https://magic-firewall.cloudflare-docs.workers.dev/magic-firewall) | [Prod](https://developers.cloudflare.com/magic-firewall) |
|
||||
| Magic Transit | magic-transit | [Test](https://magic-transit.cloudflare-docs.workers.dev/magic-transit) | [Prod](https://developers.cloudflare.com/magic-transit) |
|
||||
| Network Interconnect | network-interconnect | [Test](https://network-interconnect.cloudflare-docs.workers.dev/network-interconnect) | [Prod](https://developers.cloudflare.com/network-interconnect) |
|
||||
| Pages | pages | [Test](https://pages.cloudflare-docs.workers.dev/pages) | [Prod](https://developers.cloudflare.com/pages) |
|
||||
| Railgun | railgun | [Test](https://railgun.cloudflare-docs.workers.dev/railgun) | [Prod](https://developers.cloudflare.com/railgun) |
|
||||
| Randomness Beacon | randomness-beacon | [Test](https://randomness-beacon.cloudflare-docs.workers.dev/randomness-beacon) | [Prod](https://developers.cloudflare.com/randomness-beacon) |
|
||||
| Registrar | registrar | [Test](https://registrar.cloudflare-docs.workers.dev/registrar) | [Prod](https://developers.cloudflare.com/registrar) |
|
||||
| Rules | rules | [Test](https://rules.cloudflare-docs.workers.dev/rules) | [Prod](https://developers.cloudflare.com/rules) |
|
||||
| Ruleset Engine | ruleset-engine | [Test](https://ruleset-engine.cloudflare-docs.workers.dev/ruleset-engine) | [Prod](https://developers.cloudflare.com/ruleset-engine) |
|
||||
| Security Center | security-center | [Test](https://security-center.cloudflare-docs.workers.dev/security-center) | [Prod](https://developers.cloudflare.com/security-center) |
|
||||
| Spectrum | spectrum | [Test](https://spectrum.cloudflare-docs.workers.dev/spectrum) | [Prod](https://developers.cloudflare.com/spectrum) |
|
||||
| SSL | ssl | [Test](https://ssl.cloudflare-docs.workers.dev/ssl) | [Prod](https://developers.cloudflare.com/ssl) |
|
||||
| Stream | stream | [Test](https://stream.cloudflare-docs.workers.dev/stream) | [Prod](https://developers.cloudflare.com/stream) |
|
||||
| Tenant | tenant | [Test](https://tenant.cloudflare-docs.workers.dev/tenant) | [Prod](https://developers.cloudflare.com/tenant) |
|
||||
| Terraform | terraform | [Test](https://terraform.cloudflare-docs.workers.dev/terraform) | [Prod](https://developers.cloudflare.com/terraform) |
|
||||
| Time Services | time-services | [Test](https://time-services.cloudflare-docs.workers.dev/time-services) | [Prod](https://developers.cloudflare.com/time-services) |
|
||||
| WAF | waf | [Test](https://waf.cloudflare-docs.workers.dev/waf) | [Prod](https://developers.cloudflare.com/waf) |
|
||||
| WARP Client | warp-client | [Test](https://warp-client.cloudflare-docs.workers.dev/warp-client) | [Prod](https://developers.cloudflare.com/warp-client) |
|
||||
| Workers | workers | [Test](https://workers.cloudflare-docs.workers.dev/workers) | [Prod](https://developers.cloudflare.com/workers) |
|
||||
| Zaraz | zaraz | [Test](https://zaraz.cloudflare-docs.workers.dev/zaraz) | [Prod](https://developers.cloudflare.com/zaraz) |
|
||||
| Bots | bots | [Test](https://bots.cloudflare-docs.workers.dev/bots) | [Prod](https://developers.cloudflare.com/bots) |
|
||||
| BYOIP | byoip | [Test](https://byoip.cloudflare-docs.workers.dev/byoip) | [Prod](https://developers.cloudflare.com/byoip) |
|
||||
| Cache | cache | [Test](https://cache.cloudflare-docs.workers.dev/cache/) | [Prod](https://developers.cloudflare.com/cache/) |
|
||||
| Cloudflare One | cloudflare-one | [Test](https://cloudflare-one.cloudflare-docs.workers.dev/cloudflare-one) | [Prod](https://developers.cloudflare.com/cloudflare-one) |
|
||||
| DDoS Protection | ddos-protection | [Test](https://ddos-protection.cloudflare-docs.workers.dev/ddos-protection) | [Prod](https://developers.cloudflare.com/ddos-protection) |
|
||||
| Distributed Web Gateway | distributed-web | [Test](https://distributed-web.cloudflare-docs.workers.dev/distributed-web) | [Prod](https://developers.cloudflare.com/distributed-web) |
|
||||
| Docs Engine | docs-engine | [Test](https://docs-engine.cloudflare-docs.workers.dev/docs-engine) | [Prod](https://developers.cloudflare.com/docs-engine) |
|
||||
| Email Routing | email-routing | [Test](https://email-routing.cloudflare-docs.workers.dev/email-routing) | [Prod](https://developers.cloudflare.com/email-routing) |
|
||||
| Events | events | [Test](https://events.cloudflare-docs.workers.dev/events) | [Prod](https://developers.cloudflare.com/events) |
|
||||
| Firewall | firewall | [Test](https://firewall.cloudflare-docs.workers.dev/firewall) | [Prod](https://developers.cloudflare.com/firewall) |
|
||||
| Fundamentals | fundamentals | [Test](https://fundamentals.cloudflare-docs.workers.dev/fundamentals) | [Prod](https://developers.cloudflare.com/fundamentals) |
|
||||
| HTTP/3 | http3 | [Test](https://http3.cloudflare-docs.workers.dev/http3) | [Prod](https://developers.cloudflare.com/http3) |
|
||||
| Image Optimization | images | [Test](https://images.cloudflare-docs.workers.dev/images) | [Prod](https://developers.cloudflare.com/images) |
|
||||
| Load Balancing | load-balancing | [Test](https://load-balancing.cloudflare-docs.workers.dev/load-balancing) | [Prod](https://developers.cloudflare.com/load-balancing) |
|
||||
| Logs | logs | [Test](https://logs.cloudflare-docs.workers.dev/logs) | [Prod](https://developers.cloudflare.com/logs) |
|
||||
| Magic Firewall | magic-firewall | [Test](https://magic-firewall.cloudflare-docs.workers.dev/magic-firewall) | [Prod](https://developers.cloudflare.com/magic-firewall) |
|
||||
| Magic Transit | magic-transit | [Test](https://magic-transit.cloudflare-docs.workers.dev/magic-transit) | [Prod](https://developers.cloudflare.com/magic-transit) |
|
||||
| Network Interconnect | network-interconnect | [Test](https://network-interconnect.cloudflare-docs.workers.dev/network-interconnect) | [Prod](https://developers.cloudflare.com/network-interconnect) |
|
||||
| Pages | pages | [Test](https://pages.cloudflare-docs.workers.dev/pages) | [Prod](https://developers.cloudflare.com/pages) |
|
||||
| Railgun | railgun | [Test](https://railgun.cloudflare-docs.workers.dev/railgun) | [Prod](https://developers.cloudflare.com/railgun) |
|
||||
| Randomness Beacon | randomness-beacon | [Test](https://randomness-beacon.cloudflare-docs.workers.dev/randomness-beacon) | [Prod](https://developers.cloudflare.com/randomness-beacon) |
|
||||
| Registrar | registrar | [Test](https://registrar.cloudflare-docs.workers.dev/registrar) | [Prod](https://developers.cloudflare.com/registrar) |
|
||||
| Rules | rules | [Test](https://rules.cloudflare-docs.workers.dev/rules) | [Prod](https://developers.cloudflare.com/rules) |
|
||||
| Ruleset Engine | ruleset-engine | [Test](https://ruleset-engine.cloudflare-docs.workers.dev/ruleset-engine) | [Prod](https://developers.cloudflare.com/ruleset-engine) |
|
||||
| Security Center | security-center | [Test](https://security-center.cloudflare-docs.workers.dev/security-center) | [Prod](https://developers.cloudflare.com/security-center) |
|
||||
| Spectrum | spectrum | [Test](https://spectrum.cloudflare-docs.workers.dev/spectrum) | [Prod](https://developers.cloudflare.com/spectrum) |
|
||||
| SSL | ssl | [Test](https://ssl.cloudflare-docs.workers.dev/ssl) | [Prod](https://developers.cloudflare.com/ssl) |
|
||||
| Stream | stream | [Test](https://stream.cloudflare-docs.workers.dev/stream) | [Prod](https://developers.cloudflare.com/stream) |
|
||||
| Tenant | tenant | [Test](https://tenant.cloudflare-docs.workers.dev/tenant) | [Prod](https://developers.cloudflare.com/tenant) |
|
||||
| Terraform | terraform | [Test](https://terraform.cloudflare-docs.workers.dev/terraform) | [Prod](https://developers.cloudflare.com/terraform) |
|
||||
| Time Services | time-services | [Test](https://time-services.cloudflare-docs.workers.dev/time-services) | [Prod](https://developers.cloudflare.com/time-services) |
|
||||
| WAF | waf | [Test](https://waf.cloudflare-docs.workers.dev/waf) | [Prod](https://developers.cloudflare.com/waf) |
|
||||
| WARP Client | warp-client | [Test](https://warp-client.cloudflare-docs.workers.dev/warp-client) | [Prod](https://developers.cloudflare.com/warp-client) |
|
||||
| Workers | workers | [Test](https://workers.cloudflare-docs.workers.dev/workers) | [Prod](https://developers.cloudflare.com/workers) |
|
||||
| Zaraz | zaraz | [Test](https://zaraz.cloudflare-docs.workers.dev/zaraz) | [Prod](https://developers.cloudflare.com/zaraz) |
|
||||
|
||||
### Deployment
|
||||
|
||||
|
|
@ -62,6 +62,7 @@ Each [product](https://github.com/cloudflare/cloudflare-docs/tree/production/pro
|
|||
TEST: https://$pathPrefix.cloudflare-docs.workers.dev/$pathPrefix/
|
||||
PROD: https://developers.cloudflare.com/$pathPrefix/
|
||||
```
|
||||
|
||||
### License and Legal Notices
|
||||
|
||||
Except as otherwise noted, Cloudflare and any contributors grant you a license to the Cloudflare Developer Documentation and other content in this repository under the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode), see the [LICENSE file](https://github.com/cloudflare/cloudflare-docs/blob/production/LICENSE), and grant you a license to any code in the repository under the [MIT License](https://opensource.org/licenses/MIT), see the [LICENSE-CODE file](https://github.com/cloudflare/cloudflare-docs/blob/production/LICENSE-CODE).
|
||||
|
|
|
|||
38
assets/contents.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
type ListItem = HTMLLIElement & {
|
||||
h: string;
|
||||
};
|
||||
|
||||
export function toc() {
|
||||
let target = document.querySelector('ul.DocsTableOfContents');
|
||||
let article = target && document.querySelector('article.DocsMarkdown');
|
||||
|
||||
if (article) {
|
||||
let headers = article.querySelectorAll('h2,h3,h4');
|
||||
let i = 0,
|
||||
tmp: Element,
|
||||
last: ListItem,
|
||||
container = target;
|
||||
if (!headers.length) return; // exit & leave hidden
|
||||
|
||||
for (; i < headers.length; i++) {
|
||||
tmp = headers[i];
|
||||
|
||||
if (tmp.nodeName === 'H2') {
|
||||
container = target;
|
||||
} else if (last && tmp.nodeName > last.h) {
|
||||
// eg; "H4" > "H2" ==> true
|
||||
container = last.appendChild(document.createElement('ul'));
|
||||
} else if (last && tmp.nodeName < last.h) {
|
||||
container = container.parentElement || target;
|
||||
}
|
||||
|
||||
last = document.createElement('li') as ListItem;
|
||||
let text = tmp.lastElementChild.textContent.trim();
|
||||
last.innerHTML = `<a class="DocsTableOfContents-link" href="#${tmp.id}">${text}</a>`;
|
||||
container.appendChild(last);
|
||||
last.h = tmp.nodeName;
|
||||
}
|
||||
|
||||
target.removeAttribute('hidden');
|
||||
}
|
||||
}
|
||||
152
assets/events.ts
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
let SEARCH_ID = /^(Docs|Site)Search/;
|
||||
let SEARCH_INPUT: HTMLElement;
|
||||
|
||||
function $clickaway(ev: MouseEvent) {
|
||||
if (SEARCH_INPUT && ev.target !== SEARCH_INPUT) {
|
||||
$focus(SEARCH_INPUT, false);
|
||||
}
|
||||
}
|
||||
|
||||
export function $focus(elem: HTMLElement, bool: boolean) {
|
||||
elem.toggleAttribute('is-focus-visible', bool);
|
||||
if (bool) elem.focus();
|
||||
|
||||
// if is topbar search input
|
||||
if (SEARCH_ID && SEARCH_ID.test(elem.id)) {
|
||||
SEARCH_INPUT = elem;
|
||||
|
||||
elem.parentElement.parentElement.toggleAttribute('is-focused', bool);
|
||||
elem.setAttribute('aria-expanded', '' + bool);
|
||||
|
||||
if (bool) addEventListener('click', $clickaway);
|
||||
else removeEventListener('click', $clickaway);
|
||||
}
|
||||
}
|
||||
|
||||
export function $tabbable(links: NodeListOf<Element>, bool: boolean) {
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
bool ? links[i].removeAttribute('tabindex') : links[i].setAttribute('tabindex', '-1');
|
||||
}
|
||||
}
|
||||
|
||||
// mobile sidebar toggle
|
||||
export function mobile() {
|
||||
let root = document.documentElement;
|
||||
let btn = document.querySelector('.DocsMobileTitleHeader--sidebar-toggle-button');
|
||||
if (btn)
|
||||
btn.addEventListener('click', () => {
|
||||
root.toggleAttribute('is-mobile-sidebar-open');
|
||||
});
|
||||
|
||||
// clicking on mobile search icon
|
||||
let input: HTMLInputElement =
|
||||
document.querySelector('#DocsSearch--input') || document.querySelector('#SiteSearch--input');
|
||||
|
||||
// register init handler
|
||||
if (input)
|
||||
input.addEventListener('click', () => {
|
||||
$focus(input, true);
|
||||
});
|
||||
}
|
||||
|
||||
function $copy(ev: MouseEvent) {
|
||||
let btn = (ev.target as HTMLElement).closest('button');
|
||||
let txt = btn.getAttribute('data-clipboard');
|
||||
if (txt) {
|
||||
try {
|
||||
navigator.clipboard.writeText(txt);
|
||||
} catch (err) {
|
||||
/* no support */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function copy() {
|
||||
let btns = document.querySelectorAll('button[data-clipboard]');
|
||||
for (let i = 0; i < btns.length; i++) btns[i].addEventListener('click', $copy);
|
||||
}
|
||||
|
||||
// add focus attribute to activeElement if keyboard trigger
|
||||
export function focus() {
|
||||
let isTAB = false;
|
||||
addEventListener('keydown', ev => {
|
||||
isTAB = ev.which === 9;
|
||||
});
|
||||
|
||||
addEventListener('focusin', ev => {
|
||||
if (isTAB) $focus(ev.target as HTMLElement, true);
|
||||
});
|
||||
|
||||
addEventListener('focusout', ev => {
|
||||
$focus(ev.target as HTMLElement, false);
|
||||
});
|
||||
}
|
||||
|
||||
export function dropdowns() {
|
||||
let attr = 'data-expanded';
|
||||
|
||||
document.querySelectorAll('.Dropdown').forEach(div => {
|
||||
let btn = div.querySelector('button');
|
||||
let links = div.querySelectorAll<HTMLAnchorElement>('li>a');
|
||||
let focused = 0; // index
|
||||
|
||||
if (btn && links.length > 0) {
|
||||
let arrows: EventListener = (ev: KeyboardEvent) => {
|
||||
let key = ev.which;
|
||||
let isTAB = key === 9;
|
||||
|
||||
// ESCAPE ~> close
|
||||
if (key === 27) return close(ev);
|
||||
|
||||
// DOWN / TAB ~> next
|
||||
if (isTAB || key === 40) focused++;
|
||||
// UP / SHIFT+TAB ~> prev
|
||||
else if (key === 38 || (isTAB && ev.shiftKey)) focused--;
|
||||
|
||||
// loop focus around menu
|
||||
if (focused < 0) focused = links.length;
|
||||
else focused %= links.length;
|
||||
|
||||
if (isTAB) ev.preventDefault();
|
||||
$focus(links[focused], true);
|
||||
};
|
||||
|
||||
let close: EventListener = ev => {
|
||||
ev.stopPropagation();
|
||||
removeEventListener('click', close);
|
||||
|
||||
// tab-inactive sublinks
|
||||
$tabbable(links, false);
|
||||
|
||||
div.setAttribute(attr, 'false');
|
||||
btn.setAttribute(attr, 'false');
|
||||
|
||||
div.removeEventListener('keydown', arrows);
|
||||
};
|
||||
|
||||
let open: EventListener = ev => {
|
||||
ev.stopPropagation();
|
||||
addEventListener('click', close);
|
||||
|
||||
// tab-friendly sublinks
|
||||
$tabbable(links, true);
|
||||
|
||||
div.setAttribute(attr, 'true');
|
||||
btn.setAttribute(attr, 'true');
|
||||
|
||||
// focus the first link
|
||||
$focus(links[(focused = 0)], true);
|
||||
|
||||
div.addEventListener('keydown', arrows);
|
||||
};
|
||||
|
||||
btn.addEventListener('click', ev => {
|
||||
if (div.getAttribute(attr) === 'true') {
|
||||
close(ev);
|
||||
} else {
|
||||
open(ev);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
7
assets/home.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import * as events from './events';
|
||||
import * as timeago from './timeago';
|
||||
|
||||
timeago.init();
|
||||
|
||||
events.focus();
|
||||
events.mobile();
|
||||
8
assets/jsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"*": ["*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
21
assets/main.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import * as events from './events';
|
||||
import * as contents from './contents';
|
||||
import * as timeago from './timeago';
|
||||
import * as navs from './navlinks';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
// algolia; @see search.ts
|
||||
docsearch?(options: any): any;
|
||||
}
|
||||
}
|
||||
|
||||
navs.init();
|
||||
timeago.init();
|
||||
|
||||
events.focus();
|
||||
events.mobile();
|
||||
events.dropdowns();
|
||||
events.copy();
|
||||
|
||||
contents.toc();
|
||||
62
assets/navlinks.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// Sidebar navlink expansions
|
||||
// ---
|
||||
|
||||
import { $tabbable } from './events';
|
||||
|
||||
export function init() {
|
||||
document
|
||||
.querySelectorAll<HTMLButtonElement>('.DocsSidebar--nav-expand-collapse-button')
|
||||
.forEach(btn => {
|
||||
let item = btn.parentNode; // .DocsSidebar--nav-item
|
||||
if (item) btn.addEventListener('click', toggle);
|
||||
|
||||
let div = item.querySelector('div'); // .DocsSidebar--nav-item-collapse-container
|
||||
if (div && div.hasAttribute('is-expanded')) div.style.height = 'auto';
|
||||
});
|
||||
}
|
||||
|
||||
type ListItem = HTMLLIElement & {
|
||||
timer?: NodeJS.Timeout | void;
|
||||
};
|
||||
|
||||
function toggle(ev: Event) {
|
||||
let attr = 'is-expanded';
|
||||
|
||||
let item: ListItem = (ev.target as HTMLLIElement).closest('li')!;
|
||||
if (item.timer) item.timer = clearTimeout(item.timer);
|
||||
|
||||
let isExpanded = item.hasAttribute(attr);
|
||||
let aria = item.querySelector('span[is-visually-hidden]');
|
||||
aria!.textContent = isExpanded ? 'Expand' : 'Collapse';
|
||||
|
||||
let container = item.querySelector('div')!; // .DocsSidebar--nav-item-collapse-container
|
||||
container.className = 'DocsSidebar--nav-item-collapse-container';
|
||||
container.style.cssText = 'min-height:0px;transition-duration:400ms;';
|
||||
|
||||
// .DocsSidebar--nav-item-collapse-wrapper
|
||||
let sizes = [0, container.firstElementChild!.clientHeight];
|
||||
|
||||
let initial = +isExpanded;
|
||||
// expanded:: height -> 0 || minimize:: 0 -> height
|
||||
container.style.height = sizes[initial] + 'px';
|
||||
|
||||
// only adjust immediate <ul> child
|
||||
let subnav = container.querySelector('ul');
|
||||
let items = subnav && subnav.querySelectorAll('li>a,li>button');
|
||||
if (items) $tabbable(items, !isExpanded);
|
||||
item.toggleAttribute(attr, !isExpanded);
|
||||
|
||||
setTimeout(() => {
|
||||
container.style.height = sizes[1 - initial] + 'px';
|
||||
}, 1);
|
||||
|
||||
if (isExpanded) {
|
||||
// minimizing
|
||||
} else {
|
||||
// expanding
|
||||
item.timer = setTimeout(() => {
|
||||
container.style.height = 'auto';
|
||||
container.classList.add('DocsSidebar--nav-item-collapse-entered');
|
||||
}, 400);
|
||||
}
|
||||
}
|
||||
87
assets/search.ts
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
let tag = document.currentScript;
|
||||
let $ = document.querySelector.bind(document);
|
||||
|
||||
let dataset = tag && tag.dataset;
|
||||
let { index, key, filters } = dataset || {};
|
||||
|
||||
function loaded() {
|
||||
let element = $('#DocsSearch--input') || $('#SiteSearch--input');
|
||||
|
||||
let algolia = window.docsearch({
|
||||
indexName: index,
|
||||
apiKey: key,
|
||||
algoliaOptions: {
|
||||
facetFilters: filters || '',
|
||||
},
|
||||
|
||||
inputSelector: '#' + element.id,
|
||||
|
||||
autocompleteOptions: {
|
||||
// https://github.com/algolia/autocomplete.js#global-options
|
||||
autoselect: true,
|
||||
openOnFocus: true,
|
||||
clearOnSelected: false,
|
||||
tabAutocomplete: false,
|
||||
|
||||
appendTo: '.' + element.parentNode.className,
|
||||
hint: false,
|
||||
|
||||
autoselectOnBlur: matchMedia('(pointer: course)').matches,
|
||||
},
|
||||
|
||||
// https://docsearch.algolia.com/docs/behavior
|
||||
handleSelected(input, event, suggestion, datasetNumber, context) {
|
||||
let ctx = new URL(suggestion.url);
|
||||
|
||||
algolia.input.autocomplete.setVal('');
|
||||
algolia.input[0].blur();
|
||||
|
||||
// no scroll if is H1 tag
|
||||
if (suggestion.isLvl0) ctx.hash = '';
|
||||
|
||||
// redirect to new path
|
||||
return location.assign(ctx.pathname + ctx.search + ctx.hash);
|
||||
},
|
||||
|
||||
transformData(hits) {
|
||||
// Remove empty results
|
||||
for (let len = hits.length; len-- > 0; ) {
|
||||
let info = hits[len].hierarchy;
|
||||
if (!info.lvl0 && !info.lvl1) {
|
||||
hits.splice(len, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let input = algolia.input[0];
|
||||
let wrapper = algolia.autocomplete.autocomplete.getWrapper();
|
||||
|
||||
algolia.autocomplete.on('autocomplete:shown', () => {
|
||||
wrapper.setAttribute('data-expanded', true);
|
||||
});
|
||||
|
||||
algolia.autocomplete.on('autocomplete:closed', () => {
|
||||
wrapper.setAttribute('data-expanded', false);
|
||||
});
|
||||
|
||||
addEventListener('keydown', ev => {
|
||||
if (ev.target === input) return;
|
||||
|
||||
let key = ev.which;
|
||||
|
||||
// is '/' or SHIFT+'s'
|
||||
if (key === 191 || (ev.shiftKey && key === 83)) {
|
||||
ev.preventDefault();
|
||||
window.scrollTo(0, 0);
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// init
|
||||
(function check() {
|
||||
if (!index || !key) return;
|
||||
if (window.docsearch) loaded();
|
||||
else setTimeout(check, 25);
|
||||
})();
|
||||
59
assets/theme.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
(function () {
|
||||
let tooEarly = false;
|
||||
let btn: HTMLInputElement;
|
||||
let media: MediaQueryList | void;
|
||||
|
||||
if (document.readyState !== 'loading') init();
|
||||
else addEventListener('DOMContentLoaded', init);
|
||||
|
||||
btn = document.querySelector('#ThemeToggle')!;
|
||||
tooEarly = !btn;
|
||||
|
||||
function setter(isDark: boolean) {
|
||||
try {
|
||||
let theme = isDark ? 'dark' : 'light';
|
||||
document.documentElement.setAttribute('theme', theme);
|
||||
localStorage.theme = JSON.stringify({ theme });
|
||||
|
||||
if (btn) {
|
||||
btn.checked = isDark;
|
||||
tooEarly = false;
|
||||
} else if (tooEarly) {
|
||||
setTimeout(setter, 1, isDark);
|
||||
}
|
||||
} catch (err) {
|
||||
// security error
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
btn = btn || document.querySelector('#ThemeToggle')!;
|
||||
btn.addEventListener('change', () => setter(!!btn.checked));
|
||||
|
||||
// Shift+D for toggle
|
||||
addEventListener('keydown', ev => {
|
||||
if (ev.target !== document.body) return;
|
||||
if (ev.which === 68 && ev.shiftKey) {
|
||||
ev.preventDefault();
|
||||
setter(!btn.checked);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
media = window.matchMedia('(prefers-color-scheme:dark)');
|
||||
media.onchange = ev => setter(ev.matches);
|
||||
} catch (err) {
|
||||
// no support
|
||||
}
|
||||
|
||||
try {
|
||||
let value = localStorage.theme;
|
||||
let row = value && JSON.parse(value);
|
||||
|
||||
// defaults to "light" theme
|
||||
setter(row ? /dark/.test(row.theme) : !!(media && media.matches));
|
||||
} catch (err) {
|
||||
// security error
|
||||
}
|
||||
})();
|
||||
11
assets/timeago.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import fromnow from 'fromnow';
|
||||
|
||||
export function init() {
|
||||
let i = 0,
|
||||
tmp: string;
|
||||
let arr = document.querySelectorAll('time.relative');
|
||||
for (; i < arr.length; i++) {
|
||||
tmp = arr[i].getAttribute('datetime');
|
||||
if (tmp) arr[i].textContent = fromnow(tmp, { max: 1, suffix: true });
|
||||
}
|
||||
}
|
||||
12
assets/twitter.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
setTimeout(
|
||||
function (x) {
|
||||
x.setAttribute('data-theme', document.documentElement.getAttribute('theme'));
|
||||
var nxt = document.createElement('script');
|
||||
nxt.src = 'https://platform.twitter.com/widgets.js';
|
||||
nxt.charset = 'utf-8';
|
||||
nxt.async = true;
|
||||
document.body.appendChild(nxt);
|
||||
},
|
||||
50,
|
||||
document.currentScript.parentElement
|
||||
);
|
||||
178
bin/adjust.ts
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/**
|
||||
* sweeping changes to "content/**" markdown
|
||||
* 1) ensure every frontmatter as a `title` value
|
||||
* 2) ensure index pages are "_index.md"
|
||||
* 3) ensure all same-origin links are absolute paths
|
||||
*/
|
||||
|
||||
import * as fs from 'fs/promises';
|
||||
import { join, resolve } from 'path';
|
||||
import { toMarkdown } from 'mdast-util-to-markdown';
|
||||
import { fromMarkdown } from 'mdast-util-from-markdown';
|
||||
import { parse } from 'node-html-parser';
|
||||
import * as astray from 'astray';
|
||||
import yaml from 'yaml';
|
||||
|
||||
import type * as MDAST from 'mdast';
|
||||
|
||||
const isMD = /\.md$/;
|
||||
const ROOT = resolve('.');
|
||||
const CONTENT = join(ROOT, 'content');
|
||||
|
||||
const ORIGIN = 'https://developers.cloudflare.com';
|
||||
|
||||
function toHref(prefix: string, input: string): string {
|
||||
if (input.startsWith('#')) return input;
|
||||
|
||||
if (/^(https?:)?\/\//.test(input)) {
|
||||
let tmp = new URL(input);
|
||||
if (tmp.origin !== ORIGIN) return input;
|
||||
return tmp.pathname + tmp.search + tmp.hash;
|
||||
}
|
||||
|
||||
if (input.startsWith(prefix)) return input;
|
||||
|
||||
let tmp = new URL(input, ORIGIN);
|
||||
|
||||
let path = tmp.pathname;
|
||||
if (!path.endsWith('/')) {
|
||||
path += '/';
|
||||
}
|
||||
|
||||
if (!path.startsWith(prefix)) {
|
||||
path = prefix + path.substring(1);
|
||||
}
|
||||
|
||||
return path + tmp.search + tmp.hash;
|
||||
}
|
||||
|
||||
async function task(file: string) {
|
||||
let fileArr = file.split('/');
|
||||
// The product name will be whatever comes after "content"
|
||||
// i.e. cloudflare-docs/content/workers/index.md
|
||||
let product = fileArr[fileArr.indexOf('content') + 1];
|
||||
let data = await fs.readFile(file, 'utf8');
|
||||
|
||||
if (data.substring(0, 3) !== '---') {
|
||||
return console.log('Missing frontmatter!', file);
|
||||
}
|
||||
|
||||
let index = data.indexOf('---', 3);
|
||||
let ftxt = data.substring(3, index);
|
||||
let fmatter = yaml.parse(ftxt);
|
||||
|
||||
let content = data.substring(index + 3).trim();
|
||||
let tree = fromMarkdown(content);
|
||||
|
||||
let title = '';
|
||||
let prefix = `/${product}/`;
|
||||
|
||||
// look for title value from h1
|
||||
astray.walk<MDAST.Root, void, any>(tree, {
|
||||
heading(node: MDAST.Heading) {
|
||||
if (node.depth !== 1) return;
|
||||
|
||||
astray.walk<MDAST.Heading, void, any>(node, {
|
||||
text(t: MDAST.Text) {
|
||||
title += t.value;
|
||||
},
|
||||
});
|
||||
|
||||
return astray.SKIP;
|
||||
},
|
||||
|
||||
link(node: MDAST.Link) {
|
||||
node.url = toHref(prefix, node.url);
|
||||
},
|
||||
|
||||
html(node: MDAST.HTML) {
|
||||
if (node.value.startsWith('<button ') && node.value.includes(' href=')) {
|
||||
let html = parse(node.value);
|
||||
let button = html.querySelector('button[href]');
|
||||
|
||||
if (button) {
|
||||
let href = button.getAttribute('href');
|
||||
|
||||
if (href) {
|
||||
button.setAttribute('href', toHref(prefix, href));
|
||||
node.value = button.toString().slice(0, -9);
|
||||
} else {
|
||||
console.log('Missing "href" value!', node.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
title = title.trim();
|
||||
fmatter.title = (fmatter.title || '').trim();
|
||||
|
||||
if (!title) {
|
||||
return console.error('[ERROR] Missing title!', file);
|
||||
}
|
||||
|
||||
if (fmatter.title === title) {
|
||||
// do nothing
|
||||
} else if (fmatter.title) {
|
||||
fmatter.meta = fmatter.meta || {};
|
||||
fmatter.meta.title = (fmatter.meta.title || title).trim();
|
||||
if (fmatter.meta.title !== title) {
|
||||
console.warn('[WARN] Mismatch `meta.title` value!', file);
|
||||
}
|
||||
} else {
|
||||
fmatter.title = title;
|
||||
}
|
||||
|
||||
// regenerate new front matter
|
||||
ftxt = '---\n' + yaml.stringify(fmatter) + '---\n\n';
|
||||
|
||||
content = toMarkdown(tree);
|
||||
|
||||
// write the updated markdown file
|
||||
await fs.writeFile(file, ftxt + content);
|
||||
}
|
||||
|
||||
async function walk(dir: string): Promise<void> {
|
||||
let files = await fs.readdir(dir);
|
||||
|
||||
let count = 0;
|
||||
let ignores = new Set(['images', 'static']);
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
let tmp = files[i];
|
||||
// has many markdown OR directory siblings
|
||||
if (isMD.test(tmp)) count++;
|
||||
else if (ignores.has(tmp)) continue;
|
||||
else if (!~tmp.indexOf('.')) count++;
|
||||
|
||||
if (count > 1) break;
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
files.map(async fname => {
|
||||
let absolute = join(dir, fname);
|
||||
|
||||
if (!isMD.test(fname)) {
|
||||
let stats = await fs.stat(absolute);
|
||||
return stats.isDirectory() && walk(absolute);
|
||||
}
|
||||
|
||||
if (fname === 'index.md' && count > 1) {
|
||||
let nxt = join(dir, '_index.md');
|
||||
await fs.rename(absolute, nxt);
|
||||
absolute = nxt;
|
||||
}
|
||||
|
||||
return task(absolute);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// --- init
|
||||
|
||||
try {
|
||||
await walk(CONTENT);
|
||||
} catch (err) {
|
||||
console.error(err.stack || err);
|
||||
process.exit(1);
|
||||
}
|
||||
91
bin/format-pool.ts
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import * as fs from 'fs/promises';
|
||||
import { join, resolve } from 'path';
|
||||
import { Callback, Pool } from './pool';
|
||||
import { options } from './prettier.config';
|
||||
|
||||
import type { Result } from './worker';
|
||||
|
||||
const ROOT = resolve('.');
|
||||
const ROOTLEN = ROOT.length + 1;
|
||||
|
||||
const isSILENT = process.argv.includes('--quiet');
|
||||
const isCHECK = process.argv.includes('--check');
|
||||
|
||||
const isFILE = /\.(mdx?|[mc]?[tj]sx?|json|ya?ml|s?css)$/;
|
||||
|
||||
// Unknown languages / missing parsers
|
||||
const Missing = new Set<string>();
|
||||
|
||||
let warns = 0;
|
||||
let errors = 0;
|
||||
|
||||
const task = new Pool({
|
||||
script: join(ROOT, 'bin/worker.ts'),
|
||||
spawn: {
|
||||
execArgv: ['--loader', 'tsm'],
|
||||
env: { NODE_NO_WARNINGS: '1' },
|
||||
workerData: { isCHECK, ROOTLEN, options },
|
||||
},
|
||||
});
|
||||
|
||||
const handler: Callback<Result> = (err, result) => {
|
||||
if (err) return console.error(err);
|
||||
|
||||
errors += result.error;
|
||||
warns += result.warn;
|
||||
|
||||
if (result.warn && isCHECK) process.exitCode = 1;
|
||||
else if (result.error) process.exitCode = 1;
|
||||
|
||||
result.missing.forEach(x => {
|
||||
Missing.add(x);
|
||||
});
|
||||
};
|
||||
|
||||
async function walk(dir: string): Promise<void> {
|
||||
let files = await fs.readdir(dir);
|
||||
|
||||
await Promise.all(
|
||||
files.map(fname => {
|
||||
let absolute = join(dir, fname);
|
||||
|
||||
if (fname === '.github') return walk(absolute);
|
||||
if (fname === 'node_modules' || fname === 'public') return;
|
||||
if (/^[._]/.test(fname) || /\.hbs$/.test(fname)) return;
|
||||
// TODO: temporarily disable `*.hbs` formatting
|
||||
|
||||
if (isFILE.test(fname)) {
|
||||
return task.run(absolute, handler);
|
||||
}
|
||||
|
||||
return fs.stat(absolute).then(stats => {
|
||||
if (stats.isDirectory()) return walk(absolute);
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
await walk(ROOT);
|
||||
|
||||
if (Missing.size > 0) {
|
||||
let langs = [...Missing].sort();
|
||||
console.warn('\n\nMissing parser for language(s):\n');
|
||||
console.warn(langs.map(x => ' - ' + x).join('\n'));
|
||||
}
|
||||
|
||||
if (errors || warns) {
|
||||
console.error('\n');
|
||||
if (errors) {
|
||||
console.error('Finished with %d error(s)', errors);
|
||||
}
|
||||
if (isCHECK && warns) {
|
||||
console.error('Finished with %d warning(s)', warns);
|
||||
}
|
||||
console.error('\n');
|
||||
isSILENT || process.exit(1);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err.stack || err);
|
||||
process.exit(1);
|
||||
}
|
||||
223
bin/format.ts
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
import prettier from 'prettier';
|
||||
import * as fs from 'fs/promises';
|
||||
import { join, resolve } from 'path';
|
||||
import { langs } from './prism.config';
|
||||
import { options } from './prettier.config';
|
||||
|
||||
const ROOT = resolve('.');
|
||||
const ROOTLEN = ROOT.length + 1;
|
||||
|
||||
const isSILENT = process.argv.includes('--quiet');
|
||||
const isCHECK = process.argv.includes('--check');
|
||||
const isBAIL = process.argv.includes('--bail');
|
||||
|
||||
const isMD = /\.md$/;
|
||||
const isFILE = /\.([mc]?[tj]sx?|json|ya?ml|s?css)$/;
|
||||
const YAML = /^\s*(---[^]+(?:---\r?\n))/;
|
||||
|
||||
// Unknown languages / missing parsers
|
||||
const Missing = new Set<string>();
|
||||
|
||||
// Prism languages to ignore
|
||||
const Ignores = new Set(['txt', 'diff', 'bash', 'sh', 'toml']);
|
||||
|
||||
// Prism language -> prettier parser
|
||||
export const Parsers: Record<string, prettier.BuiltInParserName> = {
|
||||
js: 'babel',
|
||||
javascript: 'babel',
|
||||
|
||||
md: 'mdx',
|
||||
markdown: 'mdx',
|
||||
mdx: 'mdx',
|
||||
|
||||
json: 'json',
|
||||
json5: 'json5',
|
||||
|
||||
ts: 'typescript',
|
||||
typescript: 'typescript',
|
||||
|
||||
gql: 'graphql',
|
||||
graphql: 'graphql',
|
||||
|
||||
xml: 'html',
|
||||
html: 'html',
|
||||
svelte: 'html',
|
||||
hbs: 'html',
|
||||
vue: 'vue',
|
||||
|
||||
yaml: 'yaml',
|
||||
yml: 'yaml',
|
||||
};
|
||||
|
||||
interface Metadata {
|
||||
file: string;
|
||||
lang: string;
|
||||
content?: string;
|
||||
}
|
||||
|
||||
let warns = 0;
|
||||
let errors = 0;
|
||||
|
||||
function toError(msg: string, meta: Metadata): void {
|
||||
errors++;
|
||||
|
||||
msg += '\n~> file: ' + meta.file.substring(ROOTLEN);
|
||||
msg += '\n~> language: ' + meta.lang;
|
||||
if (meta.content) {
|
||||
msg += '\n~> code: ';
|
||||
meta.content.split(/\r?\n/g).forEach(txt => {
|
||||
msg += '\n\t' + txt;
|
||||
});
|
||||
}
|
||||
console.error('\n\n' + msg);
|
||||
}
|
||||
|
||||
function format(code: string, lang: string) {
|
||||
let parser = Parsers[lang];
|
||||
if (parser == null) {
|
||||
Missing.add(lang);
|
||||
return code;
|
||||
}
|
||||
return prettier.format(code, { ...options, parser });
|
||||
}
|
||||
|
||||
async function write(file: string, output: string, isMatch: boolean) {
|
||||
let txt = isCHECK ? 'PASS' : 'OK';
|
||||
if (isCHECK && !isMatch) {
|
||||
process.exitCode = 1;
|
||||
txt = 'FAIL';
|
||||
warns++;
|
||||
}
|
||||
isCHECK || (await fs.writeFile(file, output));
|
||||
process.stdout.write(`[${txt}] ${file.substring(ROOTLEN)}\n`);
|
||||
}
|
||||
|
||||
async function prettify(file: string, lang?: string) {
|
||||
let extn = file.substring(file.lastIndexOf('.') + 1);
|
||||
|
||||
let input = await fs.readFile(file, 'utf8');
|
||||
let output = format(input, lang || langs[extn] || extn);
|
||||
await write(file, output, input === output);
|
||||
}
|
||||
|
||||
async function walk(dir: string): Promise<void> {
|
||||
let files = await fs.readdir(dir);
|
||||
|
||||
await Promise.all(
|
||||
files.map(fname => {
|
||||
let absolute = join(dir, fname);
|
||||
|
||||
if (fname === '.github') return walk(absolute);
|
||||
if (fname === 'node_modules' || fname === 'public') return;
|
||||
if (/^[._]/.test(fname) || /\.hbs$/.test(fname)) return;
|
||||
// TODO: temporarily disable `*.hbs` formatting
|
||||
|
||||
if (isMD.test(fname)) return markdown(absolute);
|
||||
if (isFILE.test(fname)) return prettify(absolute);
|
||||
|
||||
return fs.stat(absolute).then(stats => {
|
||||
if (stats.isDirectory()) return walk(absolute);
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async function markdown(file: string): Promise<void> {
|
||||
let last = 0;
|
||||
let output = '';
|
||||
let match: RegExpExecArray | null;
|
||||
let input = await fs.readFile(file, 'utf8');
|
||||
let BACKTICKS = /^( +)?([`]{3})([A-Za-z]+?)\n([^]+?)(\2)/gm;
|
||||
|
||||
while ((match = BACKTICKS.exec(input))) {
|
||||
let [full, lead, open, hint, inner, close] = match;
|
||||
|
||||
let current = match.index;
|
||||
output += input.substring(last, current);
|
||||
|
||||
lead = lead || '';
|
||||
hint = hint || 'txt';
|
||||
let lang = (langs[hint] || hint).toLowerCase();
|
||||
|
||||
if (Ignores.has(lang) || Missing.has(lang)) {
|
||||
last = current + full.length;
|
||||
output += full;
|
||||
continue;
|
||||
}
|
||||
|
||||
let isYAML = YAML.exec(inner);
|
||||
let frontmatter = (isYAML && isYAML[1]) || '';
|
||||
|
||||
if (frontmatter.length > 0) {
|
||||
// TODO: parse for `format: false` value
|
||||
inner = inner.substring(frontmatter.length + lead.length);
|
||||
|
||||
if (lead.length > 0) {
|
||||
frontmatter = frontmatter.replace(new RegExp('\n' + lead, 'g'), '\n');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
var pretty = format(inner, lang).trimEnd();
|
||||
} catch (err) {
|
||||
toError('Error formatting code snippet!', { file, lang });
|
||||
if (isBAIL) throw err;
|
||||
return console.error(err.message || err);
|
||||
}
|
||||
|
||||
output += lead + '```' + lang + '\n';
|
||||
|
||||
if (lead.length > 0) {
|
||||
(frontmatter + pretty).split(/\r?\n/g).forEach(line => {
|
||||
output += lead + line + '\n';
|
||||
});
|
||||
} else {
|
||||
output += frontmatter + pretty + '\n';
|
||||
}
|
||||
|
||||
output += lead + '```';
|
||||
|
||||
last = current + full.length;
|
||||
}
|
||||
|
||||
if (last && last < input.length) {
|
||||
output += input.substring(last);
|
||||
} else if (last < 1) {
|
||||
output = input;
|
||||
}
|
||||
|
||||
try {
|
||||
output = format(output, 'mdx');
|
||||
} catch (err) {
|
||||
toError('Error w/ final MDX format!', { file, lang: 'mdx' });
|
||||
if (isBAIL) throw err;
|
||||
return console.error(err.stack || err);
|
||||
}
|
||||
|
||||
await write(file, output, input === output);
|
||||
}
|
||||
|
||||
try {
|
||||
await walk(ROOT);
|
||||
|
||||
if (Missing.size > 0) {
|
||||
let langs = [...Missing].sort();
|
||||
console.warn('\n\nMissing parser for language(s):\n');
|
||||
console.warn(langs.map(x => ' - ' + x).join('\n'));
|
||||
}
|
||||
|
||||
if (errors || warns) {
|
||||
console.error('\n');
|
||||
if (errors) {
|
||||
console.error('Finished with %d error(s)', errors);
|
||||
}
|
||||
if (isCHECK && warns) {
|
||||
console.error('Finished with %d warning(s)', warns);
|
||||
}
|
||||
console.error('\n');
|
||||
isSILENT || process.exit(1);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err.stack || err);
|
||||
process.exit(1);
|
||||
}
|
||||
111
bin/highlight.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* tsm bin/highlight.ts replace
|
||||
* tsm bin/highlight.ts restore
|
||||
*/
|
||||
import * as fs from 'fs/promises';
|
||||
import { join, resolve } from 'path';
|
||||
import { highlight } from './prism.config';
|
||||
|
||||
const ROOT = resolve('.');
|
||||
const ROOTLEN = ROOT.length + 1;
|
||||
const CONTENT = join(ROOT, 'content');
|
||||
|
||||
const REPLACE = process.argv.includes('replace');
|
||||
const RESTORE = !REPLACE && process.argv.includes('restore');
|
||||
|
||||
const isMD = /\.md$/;
|
||||
const isBACKUP = /\.md\.backup$/;
|
||||
// const YAML = /^\s*(---[^]+(?:---\r?\n))/;
|
||||
|
||||
async function walk(dir: string): Promise<void> {
|
||||
let ignores = new Set(['static', 'media']);
|
||||
let files = await fs.readdir(dir, { withFileTypes: true });
|
||||
|
||||
await Promise.all(
|
||||
files.map(dirent => {
|
||||
let fname = dirent.name;
|
||||
let absolute = join(dir, fname);
|
||||
|
||||
if (isMD.test(fname)) {
|
||||
if (REPLACE) return markdown(absolute);
|
||||
else return;
|
||||
}
|
||||
|
||||
if (isBACKUP.test(fname)) {
|
||||
if (RESTORE) return restore(absolute);
|
||||
else return;
|
||||
}
|
||||
|
||||
if (dirent.isDirectory() && !ignores.has(fname)) {
|
||||
return walk(absolute);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// mv foo.md.backup foo.md
|
||||
async function restore(backup: string) {
|
||||
let original = backup.substring(0, backup.length - 7);
|
||||
await fs.copyFile(backup, original);
|
||||
await fs.unlink(backup);
|
||||
}
|
||||
|
||||
// @modified `bin/format.ts` function
|
||||
async function markdown(file: string): Promise<void> {
|
||||
let last = 0;
|
||||
let output = '';
|
||||
let match: RegExpExecArray | null;
|
||||
let input = await fs.readFile(file, 'utf8');
|
||||
let BACKTICKS = /^(\s+)?([`]{3})([A-Za-z]+?)\r?\n([^]+?)(\2)/gm;
|
||||
|
||||
while ((match = BACKTICKS.exec(input))) {
|
||||
let current = match.index;
|
||||
let [full, ws, open, hint, inner, close] = match;
|
||||
output += input.substring(last, current);
|
||||
|
||||
ws = ws || '';
|
||||
|
||||
// codeblock => HTML markup
|
||||
let lang = (hint || 'txt').toLowerCase();
|
||||
|
||||
// dedent codeblock, only if indented
|
||||
let [spaces] = ws.match(/[ ]+$/) || '';
|
||||
if (spaces && spaces.length > 0) {
|
||||
let rgx = new RegExp('^([ ]){' + spaces.length + '}', 'gm');
|
||||
inner = inner.replace(rgx, '');
|
||||
}
|
||||
|
||||
let html = highlight(inner, lang);
|
||||
|
||||
// prevent hugo from looking at "{{<" pattern
|
||||
output += '{{<raw>}}' + html.replace(/\{\{\</g, '{\\{<') + '{{</raw>}}';
|
||||
|
||||
last = current + full.length;
|
||||
}
|
||||
|
||||
if (last && last < input.length) {
|
||||
output += input.substring(last);
|
||||
} else if (last < 1) {
|
||||
output = input;
|
||||
}
|
||||
|
||||
let label = 'SKIP';
|
||||
|
||||
if (last > 0) {
|
||||
label = 'PASS';
|
||||
//~> cp foo.md foo.md.backup
|
||||
await fs.writeFile(file + '.backup', input);
|
||||
// overwrite with HTML replacements
|
||||
await fs.writeFile(file, output);
|
||||
}
|
||||
|
||||
process.stdout.write(`[${label}] ` + file.substring(ROOTLEN) + '\n');
|
||||
}
|
||||
|
||||
try {
|
||||
await walk(CONTENT);
|
||||
console.log('~> DONE~!');
|
||||
} catch (err) {
|
||||
console.error(err.stack || err);
|
||||
process.exit(1);
|
||||
}
|
||||
139
bin/pool.ts
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
import { AsyncResource } from 'async_hooks';
|
||||
import { isMainThread, parentPort, Worker } from 'worker_threads';
|
||||
import { EventEmitter } from 'events';
|
||||
import { cpus } from 'os';
|
||||
|
||||
import type { WorkerOptions } from 'worker_threads';
|
||||
|
||||
const FREE = Symbol('FREE');
|
||||
|
||||
export interface Options {
|
||||
script: URL | string;
|
||||
spawn?: WorkerOptions;
|
||||
max?: number;
|
||||
}
|
||||
|
||||
export type Callback<T = unknown> = (err: Error | null, result: T) => Promise<void> | void;
|
||||
|
||||
export interface Task<I = any, R = unknown> {
|
||||
input: I;
|
||||
handle?: Callback<R>;
|
||||
resolve(value: R): void;
|
||||
reject(reason?: any): void;
|
||||
}
|
||||
|
||||
async function exec<R = unknown>(callback: Callback<R>, err: Error | null, result: R | null) {
|
||||
let item = new AsyncResource('Task');
|
||||
let output = await item.runInAsyncScope(callback, null, err, result);
|
||||
item.emitDestroy(); // single use
|
||||
return output;
|
||||
}
|
||||
|
||||
export class Pool extends EventEmitter {
|
||||
jobs: Map<number, Callback<unknown>>;
|
||||
idles: Worker[];
|
||||
workers: Set<Worker>;
|
||||
script: URL | string;
|
||||
tasks: Task[];
|
||||
|
||||
private options?: WorkerOptions;
|
||||
private exit?: boolean;
|
||||
|
||||
constructor(options: Options) {
|
||||
super();
|
||||
|
||||
this.idles = [];
|
||||
this.script = options.script;
|
||||
this.workers = new Set();
|
||||
this.jobs = new Map();
|
||||
this.tasks = [];
|
||||
|
||||
this.options = {
|
||||
execArgv: [],
|
||||
...options.spawn,
|
||||
};
|
||||
|
||||
let i = 0;
|
||||
let max = Math.max(1, options.max || cpus().length);
|
||||
while (i++ < max) this.spawn();
|
||||
|
||||
this.on(FREE, () => {
|
||||
if (this.tasks.length > 0) {
|
||||
let task = this.tasks.shift()!;
|
||||
this.dispatch(task);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private dispatch(task: Task): void {
|
||||
if (this.idles.length < 1) {
|
||||
this.tasks.push(task);
|
||||
return;
|
||||
}
|
||||
|
||||
let worker = this.idles.pop()!;
|
||||
|
||||
worker.once('message', async result => {
|
||||
if (task.handle) {
|
||||
result = await exec(task.handle, null, result);
|
||||
}
|
||||
|
||||
worker.removeAllListeners('message');
|
||||
this.idles.push(worker);
|
||||
task.resolve(result);
|
||||
this.emit(FREE);
|
||||
});
|
||||
|
||||
worker.once('error', async err => {
|
||||
let result;
|
||||
if (task.handle) {
|
||||
result = await exec(task.handle, err, null);
|
||||
}
|
||||
|
||||
// replace current/dead worker
|
||||
this.workers.delete(worker);
|
||||
|
||||
// TODO: options.retry
|
||||
this.spawn();
|
||||
|
||||
if (result == null) task.reject(err);
|
||||
else task.resolve(result);
|
||||
});
|
||||
|
||||
worker.postMessage(task.input);
|
||||
}
|
||||
|
||||
spawn(options?: WorkerOptions): void {
|
||||
if (this.exit) return;
|
||||
|
||||
let worker = new Worker(this.script, {
|
||||
...this.options,
|
||||
...options,
|
||||
});
|
||||
|
||||
this.workers.add(worker);
|
||||
this.idles.push(worker);
|
||||
this.emit(FREE);
|
||||
}
|
||||
|
||||
run<T, R>(input: T, handle?: Callback<R>) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.dispatch({ input, handle, resolve, reject } as Task);
|
||||
});
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this.exit = true;
|
||||
for (let worker of this.workers) {
|
||||
worker.terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const isMain = isMainThread;
|
||||
export const isWorker = !isMainThread;
|
||||
|
||||
export function listen<R = unknown>(callback: Callback<R>) {
|
||||
if (parentPort) parentPort.on('message', callback);
|
||||
else throw new Error('Missing `parentPort` link');
|
||||
}
|
||||
21
bin/prettier.config.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import type { Options } from 'prettier';
|
||||
|
||||
export const options: Options = {
|
||||
arrowParens: 'avoid',
|
||||
bracketSameLine: false,
|
||||
bracketSpacing: true,
|
||||
embeddedLanguageFormatting: 'auto',
|
||||
htmlWhitespaceSensitivity: 'css',
|
||||
insertPragma: false,
|
||||
jsxSingleQuote: false,
|
||||
printWidth: 100,
|
||||
proseWrap: 'preserve',
|
||||
quoteProps: 'consistent',
|
||||
requirePragma: false,
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
tabWidth: 2,
|
||||
trailingComma: 'es5',
|
||||
useTabs: false,
|
||||
vueIndentScriptAndStyle: true,
|
||||
};
|
||||
290
bin/prism.config.ts
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
import Prism from 'prismjs';
|
||||
|
||||
import type { Token, TokenStream } from 'prismjs';
|
||||
|
||||
globalThis.Prism = Prism;
|
||||
import 'prismjs/components/prism-bash.min.js';
|
||||
import 'prismjs/components/prism-c.min.js';
|
||||
import 'prismjs/components/prism-diff.min.js';
|
||||
import 'prismjs/components/prism-git.min.js';
|
||||
import 'prismjs/components/prism-go.min.js';
|
||||
import 'prismjs/components/prism-graphql.min.js';
|
||||
import 'prismjs/components/prism-hcl.min.js';
|
||||
import 'prismjs/components/prism-http.min.js';
|
||||
import 'prismjs/components/prism-ini.min.js';
|
||||
import 'prismjs/components/prism-java.min.js';
|
||||
import 'prismjs/components/prism-json.min.js';
|
||||
import 'prismjs/components/prism-markdown.min.js';
|
||||
import 'prismjs/components/prism-python.min.js';
|
||||
import 'prismjs/components/prism-ruby.min.js';
|
||||
import 'prismjs/components/prism-rust.min.js';
|
||||
import 'prismjs/components/prism-sql.min.js';
|
||||
import 'prismjs/components/prism-typescript.min.js';
|
||||
import 'prismjs/components/prism-toml.min.js';
|
||||
import 'prismjs/components/prism-yaml.min.js';
|
||||
|
||||
// Custom `shell` grammar
|
||||
Prism.languages.sh = {
|
||||
comment: {
|
||||
pattern: /(^|[^'{\\$])#.*/,
|
||||
alias: 'unselectable',
|
||||
lookbehind: true,
|
||||
},
|
||||
|
||||
directory: {
|
||||
pattern: /^[^\r\n$*!]+(?=[$])/m,
|
||||
alias: 'unselectable',
|
||||
},
|
||||
|
||||
command: {
|
||||
pattern: /[$](?:[^\r\n])+/,
|
||||
inside: {
|
||||
prompt: {
|
||||
pattern: /^[$] /,
|
||||
alias: 'unselectable',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Prism language aliases
|
||||
export const langs: Record<string, string> = {
|
||||
tf: 'hcl', // terraform -> hashicorp config lang
|
||||
rs: 'rust',
|
||||
shell: 'sh',
|
||||
curl: 'bash',
|
||||
gql: 'graphql',
|
||||
svelte: 'html',
|
||||
javascript: 'js',
|
||||
typescript: 'ts',
|
||||
plaintext: 'txt',
|
||||
text: 'txt',
|
||||
py: 'python',
|
||||
vue: 'html',
|
||||
rb: 'ruby',
|
||||
};
|
||||
|
||||
// Custom token transforms
|
||||
const transformations: Record<string, any> = {
|
||||
js: {
|
||||
'keyword': {
|
||||
to: 'declaration-keyword',
|
||||
for: new Set(['const', 'let', 'var', 'async', 'await', 'function', 'class']),
|
||||
},
|
||||
'punctuation': {
|
||||
to: 'operator',
|
||||
for: new Set(['.']),
|
||||
},
|
||||
'class-name': {
|
||||
to: 'api',
|
||||
for: new Set(['HTMLRewriter', 'Request', 'Response', 'URL', 'Error']),
|
||||
},
|
||||
'function': {
|
||||
to: 'builtin',
|
||||
for: new Set([
|
||||
'fetch',
|
||||
'console',
|
||||
'addEventListener',
|
||||
'atob',
|
||||
'btoa',
|
||||
'setInterval',
|
||||
'clearInterval',
|
||||
'setTimeout',
|
||||
'clearTimeout',
|
||||
]),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
transformations.ts = transformations.js;
|
||||
|
||||
transformations.html = {
|
||||
keyword: transformations.js.keyword,
|
||||
};
|
||||
|
||||
interface Node {
|
||||
types: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
type Line = Node[];
|
||||
|
||||
const ESCAPE = /[&"<>]/g;
|
||||
const CHARS = {
|
||||
'"': '"',
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
};
|
||||
|
||||
// @see lukeed/tempura
|
||||
function toEscape(value: string) {
|
||||
let tmp = 0;
|
||||
let out = '';
|
||||
let last = (ESCAPE.lastIndex = 0);
|
||||
while (ESCAPE.test(value)) {
|
||||
tmp = ESCAPE.lastIndex - 1;
|
||||
out += value.substring(last, tmp) + CHARS[value[tmp] as keyof typeof CHARS];
|
||||
last = tmp + 1;
|
||||
}
|
||||
return out + value.substring(last);
|
||||
}
|
||||
|
||||
function normalize(tokens: (Token | string)[]) {
|
||||
let line: Line = [];
|
||||
let lines: Line[] = [];
|
||||
|
||||
function loop(types: string, item: TokenStream) {
|
||||
if (Array.isArray(item)) {
|
||||
item.forEach(x => loop(types, x));
|
||||
} else if (typeof item === 'string') {
|
||||
types = types || 'CodeBlock--token-plain';
|
||||
|
||||
if (item === '') {
|
||||
// ignore
|
||||
} else if (item === '\n') {
|
||||
line.push({ types, content: item });
|
||||
lines.push(line);
|
||||
line = [];
|
||||
} else if (item === '\n\n') {
|
||||
line.push({ types, content: '\n' });
|
||||
lines.push(line);
|
||||
|
||||
line = [{ types: 'CodeBlock--token-plain', content: '\n' }];
|
||||
lines.push(line);
|
||||
|
||||
line = [];
|
||||
} else if (item.includes('\n')) {
|
||||
item.split(/\r?\n/g).forEach((txt, idx, arr) => {
|
||||
if (!txt && !idx && idx < arr.length) return;
|
||||
let content = txt ? toEscape(txt) : '\n';
|
||||
|
||||
if (idx > 0) {
|
||||
lines.push(line);
|
||||
line = [];
|
||||
}
|
||||
line.push({ types, content });
|
||||
});
|
||||
} else {
|
||||
let content = toEscape(item);
|
||||
line.push({ types, content });
|
||||
}
|
||||
} else if (item) {
|
||||
if (types) types += ' ';
|
||||
types += 'CodeBlock--token-' + item.type;
|
||||
|
||||
if (item.alias) {
|
||||
([] as string[]).concat(item.alias).forEach(tt => {
|
||||
if (!types.includes(tt)) {
|
||||
if (types) types += ' ';
|
||||
types += 'CodeBlock--token-' + tt;
|
||||
}
|
||||
});
|
||||
}
|
||||
loop(types, item.content);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
loop('', tokens[i]);
|
||||
}
|
||||
|
||||
if (line.length > 0) {
|
||||
lines.push(line);
|
||||
}
|
||||
|
||||
let arr: Line[] = [];
|
||||
while ((line = lines.shift())) {
|
||||
if (line.length > 1 && line[0].content === '\n') {
|
||||
// remove extra leading "\n" items for non-whitespace lines
|
||||
} else {
|
||||
arr.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
lines = arr;
|
||||
|
||||
// check for useless newline
|
||||
// ~> last line will be single-item Array
|
||||
let last = lines.pop();
|
||||
if (last.length !== 1 || last[0].content.trim().length > 1) {
|
||||
lines.push(last); // add it back, was useful
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
export function highlight(code: string, lang: string): string {
|
||||
lang = langs[lang] || lang || 'txt';
|
||||
let grammar = Prism.languages[lang.toLowerCase()];
|
||||
|
||||
if (!grammar) {
|
||||
console.warn('[prism] Missing "%s" grammar; using "txt" fallback', lang);
|
||||
grammar = Prism.languages.txt;
|
||||
}
|
||||
|
||||
let frontmatter: {
|
||||
theme?: string | 'light';
|
||||
highlight?: `[${string}]`;
|
||||
filename?: string;
|
||||
header?: string;
|
||||
} = {};
|
||||
|
||||
if (code.substring(0, 3) === '---') {
|
||||
let index = code.indexOf('---', 3);
|
||||
if (index > 3) {
|
||||
index += 3;
|
||||
let content = code.substring(0, index);
|
||||
code = code.substring(index).replace(/^(\r?\n)+/, '');
|
||||
|
||||
// TODO: pass in `utils.frontmatter` here
|
||||
// frontmatter = utils.frontmatter(content);
|
||||
|
||||
let match = /^---\r?\n([\s\S]+?)\r?\n---/.exec(content);
|
||||
if (match != null)
|
||||
match[1].split('\n').forEach(pair => {
|
||||
let [key, ...v] = pair.split(':');
|
||||
frontmatter[key.trim() as 'theme'] = v.join(':').trim();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let highlights = new Set(JSON.parse(frontmatter.highlight || '[]').map((x: number) => x - 1));
|
||||
|
||||
// tokenize & build custom string output
|
||||
let tokens = Prism.tokenize(code, grammar);
|
||||
let output = '';
|
||||
|
||||
let theme = frontmatter.theme || 'light';
|
||||
output += '<pre class="CodeBlock CodeBlock-with-rows CodeBlock-scrolls-horizontally';
|
||||
|
||||
if (theme === 'light') output += ' CodeBlock-is-light-in-light-theme';
|
||||
output += ` CodeBlock--language-${lang}" language="${lang}">`;
|
||||
|
||||
if (frontmatter.header) output += `<span class="CodeBlock--header">${frontmatter.header}</span>`;
|
||||
else if (frontmatter.filename)
|
||||
output += `<span class="CodeBlock--filename">${frontmatter.filename}</span>`;
|
||||
|
||||
output += '<code>';
|
||||
output += '<span class="CodeBlock--rows">';
|
||||
output += '<span class="CodeBlock--rows-content">';
|
||||
|
||||
let i = 0;
|
||||
let row = '';
|
||||
let line: Line;
|
||||
let lines = normalize(tokens);
|
||||
|
||||
for (; i < lines.length; i++) {
|
||||
line = lines[i];
|
||||
row = '<span class="CodeBlock--row';
|
||||
row += highlights.has(i) ? ' CodeBlock--row-is-highlighted">' : '">';
|
||||
row += '<span class="CodeBlock--row-indicator"></span>';
|
||||
row += '<div class="CodeBlock--row-content">';
|
||||
for (let j = 0; j < line.length; j++) {
|
||||
row += '<span class="' + line[j].types + '">' + line[j].content + '</span>';
|
||||
}
|
||||
output += row + '</div></span>';
|
||||
}
|
||||
|
||||
return output + '</span></span></code></pre>';
|
||||
}
|
||||
184
bin/worker.ts
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
import prettier from 'prettier';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as thread from 'worker_threads';
|
||||
import { langs } from './prism.config';
|
||||
|
||||
export interface Result {
|
||||
file: string;
|
||||
missing: string[];
|
||||
error: 1 | 0;
|
||||
warn: 1 | 0;
|
||||
}
|
||||
|
||||
// Environment / inherited information
|
||||
const { isCHECK, ROOTLEN, options } = thread.workerData;
|
||||
const Parent = thread.parentPort!;
|
||||
|
||||
const YAML = /^\s*(---[^]+(?:---\r?\n))/;
|
||||
|
||||
// Unknown languages / missing parsers
|
||||
const Missing = new Set<string>();
|
||||
|
||||
// Prism languages to ignore
|
||||
const Ignores = new Set(['txt', 'diff', 'bash', 'sh', 'toml']);
|
||||
|
||||
// Prism language -> prettier parser
|
||||
const Parsers: Record<string, prettier.BuiltInParserName> = {
|
||||
js: 'babel',
|
||||
javascript: 'babel',
|
||||
|
||||
md: 'mdx',
|
||||
markdown: 'mdx',
|
||||
mdx: 'mdx',
|
||||
|
||||
json: 'json',
|
||||
json5: 'json5',
|
||||
|
||||
ts: 'typescript',
|
||||
typescript: 'typescript',
|
||||
|
||||
gql: 'graphql',
|
||||
graphql: 'graphql',
|
||||
|
||||
xml: 'html',
|
||||
html: 'html',
|
||||
svelte: 'html',
|
||||
hbs: 'html',
|
||||
vue: 'vue',
|
||||
|
||||
yaml: 'yaml',
|
||||
yml: 'yaml',
|
||||
};
|
||||
|
||||
function reply(
|
||||
label: 'ERRO' | 'OK' | 'PASS' | 'FAIL',
|
||||
data: Omit<Result, 'missing'>,
|
||||
extra?: string
|
||||
) {
|
||||
let text = `[${label}] ${data.file.substring(ROOTLEN)}\n`;
|
||||
if (extra) text += '\n\t' + extra.replace(/(\n)/g, '$1\t') + '\n\n';
|
||||
process.stdout.write(text);
|
||||
|
||||
let missing = [...Missing];
|
||||
let result: Result = { ...data, missing };
|
||||
Parent.postMessage(result);
|
||||
}
|
||||
|
||||
function toError(msg: string, file: string, lang: string, extra?: Error | string): never {
|
||||
let error = msg;
|
||||
if (lang) error += ' (lang = ' + lang + ')';
|
||||
if (extra) error += '\n' + extra;
|
||||
|
||||
reply('ERRO', { file, error: 1, warn: 0 }, error);
|
||||
throw 1;
|
||||
}
|
||||
|
||||
function format(code: string, lang: string) {
|
||||
let parser = Parsers[lang];
|
||||
|
||||
if (parser == null) {
|
||||
Missing.add(lang);
|
||||
return code;
|
||||
}
|
||||
|
||||
return prettier.format(code, { ...options, parser });
|
||||
}
|
||||
|
||||
async function markdown(file: string, input: string): Promise<string> {
|
||||
let last = 0;
|
||||
let output = '';
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
let BACKTICKS = /^( +)?([`]{3})([A-Za-z]+?)\n([^]+?)(\2)/gm;
|
||||
|
||||
while ((match = BACKTICKS.exec(input))) {
|
||||
let [full, lead, open, hint, inner, close] = match;
|
||||
|
||||
let current = match.index;
|
||||
output += input.substring(last, current);
|
||||
|
||||
lead = lead || '';
|
||||
hint = hint || 'txt';
|
||||
let lang = (langs[hint] || hint).toLowerCase();
|
||||
|
||||
if (Ignores.has(lang) || Missing.has(lang)) {
|
||||
last = current + full.length;
|
||||
output += full;
|
||||
continue;
|
||||
}
|
||||
|
||||
let isYAML = YAML.exec(inner);
|
||||
let frontmatter = (isYAML && isYAML[1]) || '';
|
||||
|
||||
if (frontmatter.length > 0) {
|
||||
// TODO: parse for `format: false` value
|
||||
inner = inner.substring(frontmatter.length + lead.length);
|
||||
|
||||
if (lead.length > 0) {
|
||||
frontmatter = frontmatter.replace(new RegExp('\n' + lead, 'g'), '\n');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
var pretty = format(inner, lang).trimEnd();
|
||||
} catch (err) {
|
||||
throw toError('Error formatting code snippet!', file, lang, err.message || err);
|
||||
}
|
||||
|
||||
output += lead + '```' + lang + '\n';
|
||||
|
||||
if (lead.length > 0) {
|
||||
(frontmatter + pretty).split(/\r?\n/g).forEach(line => {
|
||||
output += lead + line + '\n';
|
||||
});
|
||||
} else {
|
||||
output += frontmatter + pretty + '\n';
|
||||
}
|
||||
|
||||
output += lead + '```';
|
||||
|
||||
last = current + full.length;
|
||||
}
|
||||
|
||||
if (last && last < input.length) {
|
||||
output += input.substring(last);
|
||||
} else if (last < 1) {
|
||||
output = input;
|
||||
}
|
||||
|
||||
try {
|
||||
output = format(output, 'mdx');
|
||||
} catch (err) {
|
||||
throw toError('Error w/ final MDX format!', file, 'mdx', err.stack || err);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// Respond to `format.ts` task pool
|
||||
Parent.on('message', async file => {
|
||||
let input = await fs.readFile(file, 'utf8');
|
||||
let output: string | void;
|
||||
|
||||
try {
|
||||
if (/\.mdx?$/.test(file)) {
|
||||
output = await markdown(file, input);
|
||||
} else {
|
||||
let extn = file.substring(file.lastIndexOf('.') + 1);
|
||||
output = format(input, langs[extn] || extn);
|
||||
}
|
||||
|
||||
if (!isCHECK && output) {
|
||||
await fs.writeFile(file, output);
|
||||
}
|
||||
|
||||
const isMatch = input === output;
|
||||
const warn = +(isCHECK && !isMatch) as 1 | 0;
|
||||
const label = isCHECK ? (isMatch ? 'PASS' : 'FAIL') : 'OK';
|
||||
|
||||
return reply(label, { file, warn, error: 0 });
|
||||
} catch (err) {
|
||||
if (err === 1) return; // already handled
|
||||
return reply('ERRO', { file, warn: 0, error: 1 });
|
||||
}
|
||||
});
|
||||
39
config.toml
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
baseURL = "https://developers.cloudflare.com"
|
||||
|
||||
title = "Cloudflare Developers"
|
||||
languageCode = "en"
|
||||
DefaultContentLanguage = "en"
|
||||
disableHugoGeneratorInject = true
|
||||
enableRobotsTXT = true
|
||||
|
||||
disableAliases = true
|
||||
disableKinds = ["taxonomy", "taxonomyTerm"]
|
||||
|
||||
enableEmoji = true
|
||||
enableGitInfo = true
|
||||
|
||||
# TODO
|
||||
rssLimit = 10
|
||||
|
||||
paginate = 12 # default 10
|
||||
paginatePath = "page" # default
|
||||
|
||||
[sitemap]
|
||||
changefreq = "daily"
|
||||
filename = "sitemap.xml"
|
||||
priority = 0.7
|
||||
|
||||
[markup]
|
||||
[markup.goldmark]
|
||||
[markup.goldmark.renderer]
|
||||
unsafe = true
|
||||
[markup.highlight]
|
||||
tabWidth = 2
|
||||
style = "github"
|
||||
codeFences = true
|
||||
guessSyntax = true
|
||||
lineNumbersInTable = true
|
||||
noClasses = false
|
||||
lineNoStart = 1
|
||||
lineNos = false
|
||||
hl_Lines = ""
|
||||
89
content/1.1.1.1/1.1.1.1-for-families/_index.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
---
|
||||
pcx-content-type: reference
|
||||
title: Set up 1.1.1.1 for Families
|
||||
weight: 3
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 for Families
|
||||
|
||||
1.1.1.1 for Families adds a layer of protection to your home network, and protects it from malware and adult content. 1.1.1.1 for Families leverages Cloudflare's global network to ensure that it is fast and secure around the world, and includes the same [strong privacy guarantees](/1.1.1.1/privacy/public-dns-resolver/) that we committed to when we launched 1.1.1.1.
|
||||
|
||||
1.1.1.1 for Families categorizes destinations on the Internet based on the potential threat they pose regarding malware, phishing, or other types of security risks. When enabled, 1.1.1.1 for Families will block resolution to these destinations.
|
||||
|
||||
1.1.1.1 for Families has two default options:
|
||||
|
||||
<details>
|
||||
<summary>Protect your home against malware</summary>
|
||||
<div>
|
||||
|
||||
Using the following DNS resolvers will block malicious content:
|
||||
|
||||
* `1.1.1.2`
|
||||
* `1.0.0.2`
|
||||
* `2606:4700:4700::1112`
|
||||
* `2606:4700:4700::1002`
|
||||
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Protect your home against malware and adult content</summary>
|
||||
<div>
|
||||
|
||||
When you change your DNS resolvers to the addresses below, 1.1.1.1 for Families will block malware and adult content.
|
||||
|
||||
* `1.1.1.3`
|
||||
* `1.0.0.3`
|
||||
* `2606:4700:4700::1113`
|
||||
* `2606:4700:4700::1003`
|
||||
|
||||
</div>
|
||||
</details>
|
||||
|
||||
Cloudflare will return `0.0.0.0` if the [fully qualified domain name (FQDN)](https://en.wikipedia.org/wiki/Fully_qualified_domain_name) or IP in a DNS query is classified as malicious.
|
||||
|
||||
Choose one of the options on the left menu to read full step-by-step instructions on how to configure 1.1.1.1 for Families.
|
||||
|
||||
{{<Aside type="note" header="Domain miscategorization">}}
|
||||
|
||||
If you are using 1.1.1.1 for Families and see a domain that you believe is miscategorized, [fill in this form](https://radar.cloudflare.com/categorization-feedback/) to bring it to our attention. Your submission will remain anonymous.
|
||||
|
||||
We review these submissions to improve Cloudflare’s categorization.
|
||||
|
||||
{{</Aside>}}
|
||||
|
||||
## DNS over HTTPS (DoH)
|
||||
|
||||
If you have a DoH-compliant client, such as a compatible router, you can set up 1.1.1.1 for Families to encrypt your DNS queries over HTTPS. This prevents spoofing and tracking by malicious actors, advertisers, ISPs, and others. For more information on DoH, refer to the [Learning Center article on DNS encryption](https://www.cloudflare.com/learning/dns/dns-over-tls/).
|
||||
|
||||
To configure an encrypted DoH connection to 1.1.1.1 for Families, type one of the following URLs into the appropriate field of your DoH-compliant client:
|
||||
|
||||
**If you want to block malware:**
|
||||
|
||||
```txt
|
||||
https://security.cloudflare-dns.com/dns-query
|
||||
```
|
||||
|
||||
**If you want to block malware and adult content:**
|
||||
|
||||
```txt
|
||||
https://family.cloudflare-dns.com/dns-query
|
||||
```
|
||||
|
||||
## DNS over TLS (DoT)
|
||||
|
||||
1.1.1.1 for Families also supports DoT if you have a compliant client, such as a compatible DoT router. DoT allows you to encrypt your DNS queries, protecting you from spoofing, malicious actors, and others. You can learn more about DoT in the [Learning Center article on DNS encryption](https://www.cloudflare.com/learning/dns/dns-over-tls/).
|
||||
|
||||
To configure an encrypted DoT connection to 1.1.1.1 for Families, type one of the following URLs into the appropriate field of your DoT-compliant client:
|
||||
|
||||
**If you want to block malware:**
|
||||
|
||||
```txt
|
||||
security.cloudflare-dns.com
|
||||
```
|
||||
|
||||
**If you want to block malware and adult content:**
|
||||
|
||||
```txt
|
||||
family.cloudflare-dns.com
|
||||
```
|
||||
37
content/1.1.1.1/1.1.1.1-for-families/android.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title: Android
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 for Families - Android
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 for Families - Android
|
||||
|
||||
[1.1.1.1: Faster & Safer Internet](https://play.google.com/store/apps/details?id=com.cloudflare.onedotonedotonedotone) is the preferred method of setting up 1.1.1.1 for Families, as it allows you to automatically configure your phone to use 1.1.1.1 on any network you connect to.
|
||||
|
||||
The app also allows you to enable encryption for DNS queries or enable [WARP mode](/warp-client/), which keeps all your HTTP traffic private and secure, including your DNS queries to 1.1.1.1.
|
||||
|
||||
You can select between these two options in 1.1.1.1: Faster & Safer Internet's settings. By default, 1.1.1.1: Faster & Safer Internet is configured to WARP mode.
|
||||
|
||||
## Set up 1.1.1.1: Faster & Safer Internet
|
||||
|
||||
1. Download [1.1.1.1: Faster Internet from Google Play](https://play.google.com/store/apps/details?id=com.cloudflare.onedotonedotonedotone) for free.
|
||||
2. Launch 1.1.1.1: Faster & Safer Internet and accept the Terms of Service.
|
||||
3. Toggle the **WARP** button to **Connected**.
|
||||
4. Install the VPN profile that allows your phone to connect securely to 1.1.1.1.
|
||||
5. Tap the menu button.
|
||||
6. Select **Advanced** > **Connection options**.
|
||||
7. In **DNS settings** > **1.1.1.1 for Families**, select the option you want to use.
|
||||
|
||||
Your connection to the Internet and your DNS queries are now private and protected. Alternatively, you may want to only encrypt your DNS queries and leave the remaining traffic unencrypted. If this is the case:
|
||||
|
||||
1. Open 1.1.1.1: Faster & Safer Internet.
|
||||
2. Toggle the WARP button and choose **Switch to DNS only mode**. If the WARP toggle is disconnected, tap the **menu button**.
|
||||
3. You will see two options: 1.1.1.1 and WARP. Select **1.1.1.1**.
|
||||
4. Tap **Advanced** > **Connection options**.
|
||||
5. In **DNS settings** > **1.1.1.1 for Families**, select the option you want to use.
|
||||
|
||||
You are now using encryption only for your DNS queries.
|
||||
|
||||
{{<render file="_captive-portals.md">}}
|
||||
91
content/1.1.1.1/1.1.1.1-for-families/ios.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
---
|
||||
title: iOS
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 for Families - iOS
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 for Families - iOS
|
||||
|
||||
[1.1.1.1: Faster Internet](https://apps.apple.com/us/app/1-1-1-1-faster-internet/id1423538627) is the preferred method of setting up 1.1.1.1 for Families in iOS devices. It allows you to automatically configure your phone to use 1.1.1.1 for Families on any network you connect to, and solves iOS inability of using an alternative DNS resolver in cellular connections.
|
||||
|
||||
The app also allows you to enable encryption for DNS queries to the 1.1.1.1 DNS resolver or enable [WARP mode](/warp-client/), which keeps all your HTTP traffic private and secure, including your DNS queries to 1.1.1.1.
|
||||
|
||||
You can select between these two options in 1.1.1.1: Faster Internet's settings. By default, 1.1.1.1:Faster Internet is configured to WARP mode.
|
||||
|
||||
## Set up 1.1.1.1: Faster Internet
|
||||
|
||||
1. Download [1.1.1.1: Faster Internet from the App Store](https://apps.apple.com/us/app/1-1-1-1-faster-internet/id1423538627) for free.
|
||||
2. Launch 1.1.1.1: Faster Internet and accept the Terms of Service.
|
||||
3. Install the VPN profile that allows your phone to connect securely to 1.1.1.1.
|
||||
4. Toggle the **WARP** button to **Connected**.
|
||||
5. Tap the **menu button**.
|
||||
6. Select **Advanced** > **Connection options**.
|
||||
7. In **DNS settings** > **1.1.1.1 for Families**, select the option you want to use.
|
||||
|
||||
Your connection to the Internet and your DNS queries are now private and protected. Alternatively, you may want to only encrypt your DNS queries and leave the remaining traffic unencrypted. If this is the case:
|
||||
|
||||
1. Open 1.1.1.1: Faster Internet.
|
||||
2. Toggle the WARP button and choose **Switch to DNS only mode**. If the WARP toggle is disconnected, tap the **menu button**.
|
||||
3. You will see two options: 1.1.1.1 and WARP. Select **1.1.1.1**.
|
||||
4. Tap **Advanced** > **Connection options**.
|
||||
5. In **DNS settings** > **1.1.1.1 for Families**, select the option you want to use.
|
||||
|
||||
You are now using encryption only for your DNS queries.
|
||||
|
||||
## Manually configure 1.1.1.1 for Families
|
||||
|
||||
{{<Aside type="note">}}
|
||||
|
||||
If you configure 1.1.1.1 for Families manually, you will have to do it for every WiFi network your device connects to. This method does not work for cellular connections.
|
||||
|
||||
{{</Aside>}}
|
||||
|
||||
### Block malware
|
||||
|
||||
1. Go to **Settings** > **Wi-Fi**.
|
||||
|
||||
2. Select the **'i'** icon next to the WiFi network you are connected to.
|
||||
|
||||
3. Scroll down until you see the section called **Configure DNS**.
|
||||
|
||||
4. Change the configuration from **Automatic** to **Manual**.
|
||||
|
||||
5. Select **Add Server**.
|
||||
|
||||
6. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
|
||||
7. Remove any DNS addresses that may be already listed and in their place add:
|
||||
|
||||
```txt
|
||||
1.1.1.2
|
||||
1.0.0.2
|
||||
```
|
||||
|
||||
8. Select **Save**.
|
||||
|
||||
### Block malware and adult content
|
||||
|
||||
1. Go to **Settings** > **Wi-Fi**.
|
||||
|
||||
2. Select the **'i'** icon next to the WiFi network you are connected to.
|
||||
|
||||
3. Scroll down until you see the section called **Configure DNS**.
|
||||
|
||||
4. Change the configuration from **Automatic** to **Manual**.
|
||||
|
||||
5. Select **Add Server**.
|
||||
|
||||
6. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
|
||||
7. Remove any DNS addresses that may be already listed and in their place add:
|
||||
|
||||
```txt
|
||||
1.1.1.3
|
||||
1.0.0.3
|
||||
```
|
||||
|
||||
8. Select **Save**.
|
||||
|
||||
{{<render file="_captive-portals.md">}}
|
||||
75
content/1.1.1.1/1.1.1.1-for-families/linux.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
title: Linux
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 for Families - Linux
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 for Families - Linux
|
||||
|
||||
Take note of any DNS addresses you might have set up, and save them in a safe place in case you need to use them later.
|
||||
|
||||
## Ubuntu
|
||||
|
||||
### Block malware
|
||||
|
||||
1. Go to **Show Applications** > **Settings** > **Network**.
|
||||
|
||||
2. Select the adapter you want to configure - like your Ethernet adapter or Wi-Fi card - and click the **settings** button.
|
||||
|
||||
3. Click the **IPv4** tab.
|
||||
|
||||
4. In the **DNS** section, disable the **Automatic** toggle.
|
||||
|
||||
5. Change the DNS servers to:
|
||||
|
||||
```txt
|
||||
1.1.1.2
|
||||
1.0.0.2
|
||||
```
|
||||
|
||||
6. Click the **IPv6** tab.
|
||||
|
||||
7. In the **DNS** section, disable the **Automatic** toggle.
|
||||
|
||||
8. Change the DNS servers to:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1112
|
||||
2606:4700:4700::1002
|
||||
```
|
||||
|
||||
9. Click **Apply**.
|
||||
|
||||
### Block malware and adult content
|
||||
|
||||
1. Go to **Show Applications** > **Settings** > **Network**.
|
||||
|
||||
2. Select the adapter you want to configure - like your Ethernet adapter or Wi-Fi card - and click the **settings** button.
|
||||
|
||||
3. Click the **IPv4** tab.
|
||||
|
||||
4. In the **DNS** section, disable the **Automatic** toggle.
|
||||
|
||||
5. Change the DNS servers to:
|
||||
|
||||
```txt
|
||||
1.1.1.3
|
||||
1.0.0.3
|
||||
```
|
||||
|
||||
6. Click the **IPv6** tab.
|
||||
|
||||
7. In the **DNS** section, disable the **Automatic** toggle.
|
||||
|
||||
8. Change the DNS servers to:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1113
|
||||
2606:4700:4700::1003
|
||||
```
|
||||
|
||||
9. Click **Apply**.
|
||||
|
||||
{{<render file="_captive-portals.md">}}
|
||||
85
content/1.1.1.1/1.1.1.1-for-families/mac.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
---
|
||||
title: macOS
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 for Families - macOS
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 for Families - macOS
|
||||
|
||||
Follow these steps to configure 1.1.1.1 for Families:
|
||||
|
||||
## Block malware
|
||||
|
||||
### IPv4
|
||||
|
||||
1. Go to **System Preferences**. You can find it by pressing <kbd>Command</kbd> + <kbd>Space</kbd> on your keyboard and typing `System Preferences`.
|
||||
|
||||
2. Click **Network** > **Advanced**.
|
||||
|
||||
3. Select the **DNS** tab. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
|
||||
4. Remove any DNS addresses that may be already listed and replaced them with:
|
||||
|
||||
```txt
|
||||
1.1.1.2
|
||||
1.0.0.2
|
||||
```
|
||||
|
||||
5. Click **OK** > **Apply**.
|
||||
|
||||
### IPv6
|
||||
|
||||
1. Go to **System Preferences**. You can find it by pressing <kbd>Command</kbd> + <kbd>Space</kbd> on your keyboard and typing `System Preferences`.
|
||||
|
||||
2. Click **Network** > **Advanced**.
|
||||
|
||||
3. Select the **DNS** tab. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
|
||||
4. Remove any DNS addresses that may be already listed and replace them with:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1112
|
||||
2606:4700:4700::1002
|
||||
```
|
||||
|
||||
5. Click **OK** > **Apply**.
|
||||
|
||||
## Block malware and adult content
|
||||
|
||||
### IPv4
|
||||
|
||||
1. Go to **System Preferences**. You can find it by pressing <kbd>Command</kbd> + <kbd>Space</kbd> on your keyboard and typing `System Preferences`.
|
||||
|
||||
2. Click **Network** > **Advanced**.
|
||||
|
||||
3. Select the **DNS** tab. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
|
||||
4. Remove any DNS addresses that may be already listed and replace them with:
|
||||
|
||||
```txt
|
||||
1.1.1.3
|
||||
1.0.0.3
|
||||
```
|
||||
|
||||
5. Click **OK** > **Apply**.
|
||||
|
||||
### IPv6
|
||||
|
||||
1. Go to **System Preferences**. You can find it by pressing <kbd>Command</kbd> + <kbd>Space</kbd> on your keyboard and typing `System Preferences`.
|
||||
|
||||
2. Click **Network** > **Advanced**.
|
||||
|
||||
3. Select the **DNS** tab. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
|
||||
4. Remove any DNS addresses that may be already listed and replace them with:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1113
|
||||
2606:4700:4700::1003
|
||||
```
|
||||
|
||||
5. Click **OK** > **Apply**.
|
||||
|
||||
{{<render file="_captive-portals.md">}}
|
||||
73
content/1.1.1.1/1.1.1.1-for-families/router.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
title: Router
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 for Families - Router
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 for Families - Router
|
||||
|
||||
Follow these steps to configure 1.1.1.1 for Families:
|
||||
|
||||
## Block malware
|
||||
|
||||
1. Go to the IP address used to access your router's admin console in your browser.
|
||||
|
||||
- Linksys and Asus routers typically use `http://192.168.1.1` or `http://router.asus.com` (for ASUS).
|
||||
- Netgear routers typically use `http://192.168.1.1` or `http://routerlogin.net`.
|
||||
- D-Link routers typically use `http://192.168.0.1`.
|
||||
- Ubiquiti routers typically use `http://unifi.ubnt.com`.
|
||||
|
||||
2. Enter the router credentials. For consumer routers, the default credentials for the admin console are often found under or behind the device.
|
||||
|
||||
3. In the admin console, find the place where **DNS settings** are set. This may be contained within categories such as **WAN** and **IPv6** (Asus Routers) or **Internet** (Netgear Routers). Consult your router's documentation for details.
|
||||
|
||||
4. Take note of any DNS addresses that are currently set and save them in a safe place in case you need to use them later.
|
||||
|
||||
5. For **IPv4**, replace the existing addresses with:
|
||||
|
||||
```txt
|
||||
1.1.1.2
|
||||
1.0.0.2
|
||||
```
|
||||
|
||||
1. For **IPv6**, replace the existing addresses with:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1112
|
||||
2606:4700:4700::1002
|
||||
```
|
||||
|
||||
1. Save the updated settings.
|
||||
|
||||
## Block Malware and Adult Content
|
||||
|
||||
1. Go to the IP address used to access your router's admin console in your browser.
|
||||
|
||||
- Linksys and Asus routers typically use `http://192.168.1.1` or `http://router.asus.com` (for ASUS).
|
||||
- Netgear routers typically use `http://192.168.1.1` or `http://routerlogin.net`.
|
||||
- D-Link routers typically use `http://192.168.0.1`.
|
||||
- Ubiquiti routers typically use `http://unifi.ubnt.com`.
|
||||
|
||||
2. Enter the router credentials. For consumer routers, the default credentials for the admin console are often found under or behind the device.
|
||||
|
||||
3. In the admin console, find the place where **DNS settings** are set. This may be contained within categories such as **WAN** and **IPv6** (Asus Routers) or **Internet** (Netgear Routers). Consult your router's documentation for details.
|
||||
|
||||
4. Take note of any DNS addresses that are currently set and save them in a safe place in case you need to use them later.
|
||||
|
||||
5. For **IPv4**, replace the existing addresses with:
|
||||
|
||||
```txt
|
||||
1.1.1.3
|
||||
1.0.0.3
|
||||
```
|
||||
|
||||
1. For **IPv6**, replace the existing addresses with:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1113
|
||||
2606:4700:4700::1003
|
||||
```
|
||||
|
||||
1. Save the updated settings.
|
||||
77
content/1.1.1.1/1.1.1.1-for-families/windows.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
---
|
||||
title: Windows
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 for Families - Windows
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 for Families - Windows
|
||||
|
||||
## Windows 10
|
||||
|
||||
### Block malware
|
||||
|
||||
1. Click the **Start menu** > **Settings**.
|
||||
2. Select **Network and Internet** > **Change Adapter Options**.
|
||||
3. Right-click on the Ethernet or WiFi network you are connected to and click **Properties**.
|
||||
4. Select **Internet Protocol Version 4**.
|
||||
5. Click **Properties** > **Use the following DNS server addresses**.
|
||||
6. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
7. Remove any DNS addresses that may be already listed.
|
||||
8. Add `1.1.1.2` to the **Preferred DNS server** field, and `1.0.0.2` to the **Alternate DNS server** field.
|
||||
9. Click **OK**.
|
||||
10. Select **Internet Protocol Version 6**.
|
||||
11. Select **Properties** > **Use the following DNS server addresses**.
|
||||
12. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
13. Remove any DNS addresses that may be already listed.
|
||||
14. Add `2606:4700:4700::1112` to the **Preferred DNS server** field, and `2606:4700:4700::1002` to the **Alternate DNS server** field.
|
||||
15. Click **OK**.
|
||||
|
||||
### Block malware and adult content
|
||||
|
||||
1. Click the **Start menu** > **Settings**.
|
||||
2. Select **Network and Internet** > **Change Adapter Options**.
|
||||
3. Right-click on the Ethernet or WiFi network you are connected to and click **Properties**.
|
||||
4. Select **Internet Protocol Version 4**.
|
||||
5. Click **Properties** > **Use the following DNS server addresses**.
|
||||
6. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
7. Remove any DNS addresses that may be already listed.
|
||||
8. Add `1.1.1.3` to the **Preferred DNS server** field, and `1.0.0.3` to the **Alternate DNS server** field.
|
||||
9. Click **OK**.
|
||||
10. Select **Internet Protocol Version 6**.
|
||||
11. Select **Properties** > **Use the following DNS server addresses**.
|
||||
12. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
13. Remove any DNS addresses that may be already listed.
|
||||
14. Add `2606:4700:4700::1113` to the **Preferred DNS server** field, and `2606:4700:4700::1003` to the **Alternate DNS server** field.
|
||||
15. Click **OK**.
|
||||
|
||||
## Windows 11
|
||||
|
||||
### Block malware
|
||||
|
||||
1. Click the **Start menu** > **Settings**.
|
||||
2. Select **Network and Internet**.
|
||||
3. Click the adapter you want to configure - like your Ethernet adapter or Wi-Fi card.
|
||||
4. Scroll to **DNS server assignment** and click **Edit**.
|
||||
5. Click the **Automatic (DHCP)** drop-down menu and select **Manual**.
|
||||
6. Click the **IPv4** toggle to turn it on.
|
||||
7. Add `1.1.1.2` to the **Preferred DNS** field, and `1.0.0.2` to the **Alternate DNS** field.
|
||||
8. Click the **IPv6** toggle.
|
||||
9. Add `2606:4700:4700::1112` to the **Preferred DNS** field, and `2606:4700:4700::1002` to the **Alternate DNS** field.
|
||||
10. Click **Save**.
|
||||
|
||||
### Block malware and adult content
|
||||
|
||||
1. Click the **Start menu** > **Settings**.
|
||||
2. Select **Network and Internet**.
|
||||
3. Click the adapter you want to configure - like your Ethernet adapter or Wi-Fi card.
|
||||
4. Scroll to **DNS server assignment** and click **Edit**.
|
||||
5. Click the **Automatic (DHCP)** drop-down menu and select **Manual**.
|
||||
6. Click the **IPv4** toggle to turn it on.
|
||||
7. Add `1.1.1.3` to the **Preferred DNS** field, and `1.0.0.3` to the **Alternate DNS** field.
|
||||
8. Click the **IPv6** toggle.
|
||||
9. Add `2606:4700:4700::1113` to the **Preferred DNS** field, and `2606:4700:4700::1003` to the **Alternate DNS** field.
|
||||
10. Click **Save**.
|
||||
|
||||
{{<render file="_captive-portals.md">}}
|
||||
17
content/1.1.1.1/_index.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
title: Overview
|
||||
pcx-content-type: overview
|
||||
weight: 1
|
||||
meta:
|
||||
title: Cloudflare 1.1.1.1
|
||||
---
|
||||
|
||||
# Cloudflare 1.1.1.1
|
||||
|
||||
1.1.1.1 is Cloudflare’s public DNS resolver. It offers a fast and private way to browse the Internet. [DNS resolvers](https://www.cloudflare.com/learning/dns/what-is-dns/) translate domains like `cloudflare.com` into the IP addresses necessary to reach the website (like `104.16.123.96`).
|
||||
|
||||
Unlike most DNS resolvers, 1.1.1.1 does not sell user data to advertisers. 1.1.1.1 has also been measured to be the [fastest DNS resolver available](https://www.dnsperf.com/#!dns-resolvers) — it is deployed in hundreds of cities worldwide, and has access to the addresses of millions of domain names on the same servers it runs on.
|
||||
|
||||
Beyond the regular service, 1.1.1.1 also offers a [version made for families](/1.1.1.1/1.1.1.1-for-families/) with additional protection against malware and adult content, and an encrypted service through [DNS over HTTPS (DoH)](/1.1.1.1/encrypted-dns/dns-over-https/) or [DNS over TLS (DoT)](/1.1.1.1/encrypted-dns/dns-over-tls/) for increased security and privacy. You can also access 1.1.1.1 [as a Tor hidden service](/1.1.1.1/other-ways-to-use-1.1.1.1/dns-over-tor/).
|
||||
|
||||
1.1.1.1 is completely free. Setting it up takes minutes and requires no special software.
|
||||
18
content/1.1.1.1/_partials/_captive-portals.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
_build:
|
||||
publishResources: false
|
||||
render: never
|
||||
list: never
|
||||
---
|
||||
|
||||
{{<Aside type="note">}}
|
||||
|
||||
Setting up a static IP address to configure a DNS server may prevent you from connecting to some public Wi-Fi networks that use captive portals (these are the web pages some wireless networks employ to let users log in and use their services).
|
||||
|
||||
If you are experiencing connectivity issues related to captive portals:
|
||||
|
||||
1. Remove the static IP addresses from the device or disable the 1.1.1.1 app.
|
||||
2. Connect to the Wi-Fi network.
|
||||
3. Once the connection has been established, re-add the static IP addresses or enable the 1.1.1.1 app.
|
||||
|
||||
{{</Aside>}}
|
||||
10
content/1.1.1.1/_partials/_encrypted.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
_build:
|
||||
publishResources: false
|
||||
render: never
|
||||
list: never
|
||||
---
|
||||
|
||||
## Encrypt your DNS queries
|
||||
|
||||
1.1.1.1 supports DNS over TLS (DoT) and DNS over HTTPS (DoH), two standards developed for encrypting plaintext DNS traffic. This prevents untrustworthy entities from interpreting and manipulating your queries. For more information on how to encrypt your DNS queries, please refer to the [Encrypted DNS documentation](/1.1.1.1/encrypted-dns/).
|
||||
15
content/1.1.1.1/encrypted-dns/_index.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
pcx-content-type: reference
|
||||
title: Encrypt DNS traffic
|
||||
weight: 4
|
||||
---
|
||||
|
||||
# Encrypt DNS traffic
|
||||
|
||||
Traditionally, DNS queries and replies are performed over plaintext which means they are sent over the Internet without any kind of encryption or protection. This happens even when you are accessing a secured website. This has a huge impact on security and privacy, as these queries might be subject to surveillance, spoofing and tracking by malicious actors, advertisers, ISPs, and others.
|
||||
|
||||
To prevent this and secure your connections, 1.1.1.1 supports DNS over TLS (DoT) and DNS over HTTPS (DoH), two standards developed for encrypting plaintext DNS traffic. This prevents untrustworthy entities from interpreting and manipulating your queries.
|
||||
|
||||
Pick one of these standards to start.
|
||||
|
||||
{{<directory-listing>}}
|
||||
11
content/1.1.1.1/encrypted-dns/dns-over-https/_index.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
pcx-content-type: navigation
|
||||
title: DNS over HTTPS
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# DNS over HTTPS
|
||||
|
||||
With DNS over HTTPS (DoH), DNS queries and responses are encrypted and sent via the HTTP or HTTP/2 protocols. DoH ensures that attackers cannot forge or alter DNS traffic. DoH uses port 443, which is the standard HTTPS traffic port, to wrap the DNS query in an HTTPS request. DNS queries and responses are camouflaged within other HTTPS traffic, since it all comes and goes from the same port.
|
||||
|
||||
{{<directory-listing>}}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
---
|
||||
pcx-content-type: tutorial
|
||||
title: Connect to 1.1.1.1 using DoH clients
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# Connect to 1.1.1.1 using DoH clients
|
||||
|
||||
There are several DoH clients you can use to connect to 1.1.1.1.
|
||||
|
||||
## cloudflared
|
||||
|
||||
Follow this quick guide to start a DNS over HTTPS proxy to 1.1.1.1.
|
||||
|
||||
1. Download and install the [`cloudflared` daemon](/cloudflare-one/connections/connect-apps/install-and-setup/installation).
|
||||
|
||||
2. Verify that the `cloudflared` daemon is installed by entering the following command:
|
||||
|
||||
```sh
|
||||
$ cloudflared --version
|
||||
cloudflared version 2020.11.11 (built 2020-11-25-1643 UTC)
|
||||
```
|
||||
|
||||
3. Start the DNS proxy on an address and port in your network. If you do not specify an address and port, it will start listening on `localhost:53`. DNS (53) is a privileged port, so for the initial demo we will use a different port:
|
||||
|
||||
```sh
|
||||
$ cloudflared proxy-dns --port 5553
|
||||
INFO[2020-12-04T19:58:57Z] Adding DNS upstream - url: https://1.1.1.1/dns-query
|
||||
INFO[2020-12-04T19:58:57Z] Adding DNS upstream - url: https://1.0.0.1/dns-query
|
||||
INFO[2020-12-04T19:58:57Z] Starting metrics server on 127.0.0.1:44841/metrics
|
||||
INFO[2020-12-04T19:58:57Z] Starting DNS over HTTPS proxy server on: dns://localhost:5553
|
||||
```
|
||||
|
||||
4. You can verify that `cloudflared` is running using a `dig`, `kdig`, `host`, or any other DNS client.
|
||||
|
||||
```sh
|
||||
$ dig +short @127.0.0.1 -p5553 cloudflare.com AAAA
|
||||
2606:4700::6810:85e5
|
||||
2606:4700::6810:84e5
|
||||
```
|
||||
|
||||
5. Run `cloudflared` as a service so it starts on user login. On many Linux distributions, this can be done with:
|
||||
|
||||
```bash
|
||||
$ sudo tee /etc/systemd/system/cloudflared-proxy-dns.service >/dev/null <<EOF
|
||||
[Unit]
|
||||
Description=DNS over HTTPS (DoH) proxy client
|
||||
Wants=network-online.target nss-lookup.target
|
||||
Before=nss-lookup.target
|
||||
|
||||
[Service]
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
DynamicUser=yes
|
||||
ExecStart=/usr/local/bin/cloudflared proxy-dns
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
$ sudo systemctl enable --now cloudflared-proxy-dns
|
||||
```
|
||||
|
||||
6. Change your system DNS servers to use `127.0.0.1`. On Linux, you can modify `/etc/resolv.conf`:
|
||||
|
||||
```sh
|
||||
$ sudo rm -f /etc/resolv.conf
|
||||
$ echo nameserver 127.0.0.1 | sudo tee /etc/resolv.conf >/dev/null
|
||||
```
|
||||
|
||||
7. Finally, verify it locally with:
|
||||
|
||||
```sh
|
||||
$ dig +short @127.0.0.1 cloudflare.com AAAA
|
||||
2606:4700::6810:85e5
|
||||
2606:4700::6810:84e5
|
||||
```
|
||||
|
||||
## DNSCrypt-Proxy
|
||||
|
||||
The [DNSCrypt-Proxy](https://dnscrypt.info) 2.0+ supports DoH out of the box. It supports both 1.1.1.1 and other services. It also includes more advanced features, such as load balancing and local filtering.
|
||||
|
||||
1. Install [DNSCrypt-Proxy](https://github.com/jedisct1/dnscrypt-proxy/wiki/installation).
|
||||
|
||||
2. Verify that `dnscrypt-proxy` is installed and the version is 2.0 or later:
|
||||
|
||||
```sh
|
||||
$ dnscrypt-proxy -version
|
||||
2.0.8
|
||||
```
|
||||
|
||||
3. Set up the configuration file using the [official instructions](https://github.com/jedisct1/dnscrypt-proxy/wiki/installation#setting-up-dnscrypt-proxy), and add `cloudflare` and `cloudflare-ipv6` to the server list in `dnscrypt-proxy.toml`:
|
||||
|
||||
```toml
|
||||
server_names = ['cloudflare', 'cloudflare-ipv6']
|
||||
```
|
||||
|
||||
4. Make sure that nothing else is running on `localhost:53`, and check that everything works as expected:
|
||||
|
||||
```sh
|
||||
$ dnscrypt-proxy -resolve cloudflare-dns.com
|
||||
Resolving [cloudflare-dns.com]
|
||||
|
||||
Domain exists: yes, 3 name servers found
|
||||
Canonical name: cloudflare-dns.com.
|
||||
IP addresses: 2400:cb00:2048:1::6810:6f19, 2400:cb00:2048:1::6810:7019, 104.16.111.25, 104.16.112.25
|
||||
TXT records: -
|
||||
Resolver IP: 172.68.140.217
|
||||
```
|
||||
|
||||
5. Register it as a system service according to the [DNSCrypt-Proxy installation instructions](https://github.com/jedisct1/dnscrypt-proxy/wiki/installation).
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
pcx-content-type: how-to
|
||||
title: Configure DoH on your browser
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# Configure DoH on your browser
|
||||
|
||||
There are several browsers compatible with DNS over HTTPS (DoH). This protocol lets you encrypt your connection to 1.1.1.1 in order to protect your DNS queries from privacy intrusions and tampering.
|
||||
|
||||
Some browsers might already have this setting enabled.
|
||||
|
||||
## Mozilla Firefox
|
||||
|
||||
1. Click the menu button.
|
||||
2. Select **Settings**.
|
||||
3. In the **General** menu, scroll down to access **Network Settings**.
|
||||
4. Click **Settings**.
|
||||
5. Click **Enable DNS over HTTPS**. By default, it resolves to Cloudflare DNS.
|
||||
|
||||
## Google Chrome
|
||||
|
||||
1. Click the three-dot menu in your browser > **Settings**.
|
||||
2. Click **Privacy and security** > **Security**.
|
||||
3. Scroll down and enable **Use secure DNS**.
|
||||
4. Click the **With** option, and from the drop-down menu choose _Cloudflare (1.1.1.1)_.
|
||||
|
||||
## Microsoft Edge
|
||||
|
||||
1. Click the three-dot menu in your browser > **Settings**.
|
||||
2. Click **Privacy, Search, and Services**, and scroll down to **Security**.
|
||||
3. Enable **Use secure DNS**.
|
||||
4. Click **Choose a service provider**.
|
||||
5. Click the **Enter custom provider** drop-down menu and choose _Cloudflare (1.1.1.1)_.
|
||||
|
||||
## Brave
|
||||
|
||||
1. Click the menu button in your browser > **Settings**.
|
||||
2. Click **Security and Privacy** > **Security**.
|
||||
3. Enable **Use secure DNS**.
|
||||
4. Click **With Custom** and choose _Cloudflare (1.1.1.1)_ as a service provider from the drop-down menu.
|
||||
|
||||
## How to check if browser is configured correctly
|
||||
|
||||
Visit [1.1.1.1 help page](https://1.1.1.1/help) and check if `Using DNS over HTTPS (DoH)` is `Yes`.
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
title: Make API requests to 1.1.1.1
|
||||
pcx-content-type: reference
|
||||
weight: 2
|
||||
meta:
|
||||
title: Make API requests to 1.1.1.1 over DoH
|
||||
---
|
||||
|
||||
# Make API requests to 1.1.1.1 over DoH
|
||||
|
||||
Cloudflare offers a DNS over HTTPS resolver at:
|
||||
|
||||
```txt
|
||||
https://cloudflare-dns.com/dns-query
|
||||
```
|
||||
|
||||
## HTTP method
|
||||
|
||||
Cloudflare's DNS-over-HTTPS (DOH) endpoint supports `POST` and `GET` for UDP wireformat, and `GET` for JSON format.
|
||||
|
||||
When making requests using `POST`, the DNS query is included as the message body of the HTTP request, and the MIME type (`application/dns-udpwireformat`) is sent in the `Content-Type` request header. Cloudflare will use the message body of the HTTP request as sent by the client, so the message body should not be encoded.
|
||||
|
||||
When making requests using `GET`, the DNS query is encoded into the URL. An additional URL parameter of `ct` should indicate the MIME type (see below).
|
||||
|
||||
## Valid MIME types
|
||||
|
||||
If you use JSON format, set `application/dns-json` URL parameter, and if you use DNS wireformat, use `application/dns-message` as either the URL parameter of `ct` or a `Content-Type` header for `POST` requests.
|
||||
|
||||
See also curl examples for [UDP wireformat](/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-wireformat/) and [JSON](/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-json/).
|
||||
|
||||
## Send multiple questions in a query
|
||||
|
||||
Sending more than one question when making requests depends on the HTTP version used, as each DNS query maps to exactly one HTTP request. HTTP/2 and HTTP/3 have multiplexing and you can start multiple requests concurrently. HTTP/2 is, in fact, the minimum recommended version of HTTP for use with DNS over HTTPS (DoH). This is not specific to 1.1.1.1, but rather how DoH works.
|
||||
|
||||
You can learn more about how DoH works in RFC8484, more specifically [the HTTP layer requirements](https://datatracker.ietf.org/doc/html/rfc8484#section-5.2).
|
||||
|
||||
Example request:
|
||||
|
||||
```sh
|
||||
$ curl --http2 -H 'accept: application/dns-json' https://1.1.1.1/dns-query?name=cloudflare.com --next --http2 -H 'accept: application/dns-json' https://1.1.1.1/dns-query?name=example.com
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
No authentication is required to send requests to this API.
|
||||
|
||||
## Supported TLS versions
|
||||
|
||||
Cloudflare's DNS over HTTPS resolver supports TLS 1.2 and TLS 1.3.
|
||||
|
||||
## Return codes
|
||||
|
||||
{{<table-wrap>}}
|
||||
|
||||
| HTTP Status | Meaning |
|
||||
| ---|--- |
|
||||
| `400` | DNS query not specified or too small. |
|
||||
| `413` | DNS query is larger than maximum allowed DNS message size. |
|
||||
| `415` | Unsupported content type. |
|
||||
| `504` | Resolver timeout while waiting for the query response. |
|
||||
|
||||
{{</table-wrap>}}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
pcx-content-type: reference
|
||||
title: Using JSON
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# Using JSON
|
||||
|
||||
Cloudflare's DNS over HTTPS endpoint also supports JSON format for querying DNS data. For lack of an agreed upon JSON schema for DNS over HTTPS in the Internet Engineering Task Force (IETF), Cloudflare has chosen to follow the same schema as Google's DNS over HTTPS resolver.
|
||||
|
||||
JSON formatted queries are sent using a `GET` request. When making requests using `GET`, the DNS query is encoded into the URL. The client should include an HTTP `Accept` request header field with a MIME type of `application/dns-json` to indicate that the client is able to accept a JSON response from the DNS over HTTPS resolver.
|
||||
|
||||
Supported parameters:
|
||||
|
||||
{{<table-wrap>}}
|
||||
|
||||
| Field | Required? | Description | Example |
|
||||
| ------ | --------- | --------------------------------------------------------------------------- | ------------- |
|
||||
| `name` | Yes | Query Name. | `example.com` |
|
||||
| `type` | Yes | Query type (either a numeric value or text). | `AAAA` |
|
||||
| `do` | No | DO bit - set if client wants DNSSEC data (either boolean or numeric value). | `true` |
|
||||
| `cd` | No | CD bit - set to disable validation (either boolean or numeric value). | `false` |
|
||||
|
||||
{{</table-wrap>}}
|
||||
|
||||
Example request:
|
||||
|
||||
```sh
|
||||
$ curl -H 'accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=example.com&type=AAAA'
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"Status": 0,
|
||||
"TC": false,
|
||||
"RD": true,
|
||||
"RA": true,
|
||||
"AD": true,
|
||||
"CD": false,
|
||||
"Question": [
|
||||
{
|
||||
"name": "example.com.",
|
||||
"type": 28
|
||||
}
|
||||
],
|
||||
"Answer": [
|
||||
{
|
||||
"name": "example.com.",
|
||||
"type": 28,
|
||||
"TTL": 1726,
|
||||
"data": "2606:2800:220:1:248:1893:25c8:1946"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The following table has more information on each response field:
|
||||
|
||||
{{<table-wrap>}}
|
||||
|
||||
| Field | Description |
|
||||
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `Status` | The Response Code of the DNS Query. These are defined by [IANA](https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6). |
|
||||
| `TC` | If true, it means the truncated bit was set. This happens when the DNS answer is larger than a single UDP or TCP packet. `TC` will almost always be false with Cloudflare DNS over HTTPS because Cloudflare supports the maximum response size. |
|
||||
| `RD` | If true, it means the Recursive Desired bit was set. This is always set to true for Cloudflare DNS over HTTPS. |
|
||||
| `RA` | If true, it means the Recursion Available bit was set. This is always set to true for Cloudflare DNS over HTTPS. |
|
||||
| `AD` | If true, it means that every record in the answer was verified with DNSSEC. |
|
||||
| `CD` | If true, the client asked to disable DNSSEC validation. In this case, Cloudflare will still fetch the DNSSEC-related records, but it will not attempt to validate the records. |
|
||||
| `Question: name` | The record name requested. |
|
||||
| `Question: type` | The type of DNS record requested. These are defined by [IANA](https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4). |
|
||||
| `Answer: name` | The record owner. |
|
||||
| `Answer: type` | The type of DNS record. These are defined by [IANA](https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4). |
|
||||
| `Answer: TTL` | The number of seconds the answer can be stored in cache before it is considered stale. |
|
||||
| `Answer: data` | The value of the DNS record for the given name and type. The data will be in text for standardized record types and in hex for unknown types. |
|
||||
|
||||
{{</table-wrap>}}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
order:
|
||||
pcx-content-type: reference
|
||||
title: Using DNS Wireformat
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# Using DNS Wireformat
|
||||
|
|
@ -88,4 +89,4 @@ cf-ray: 3ffe69838a418c4c-SFO-DOG
|
|||
0000020 01 c0 0c 00 01 00 01 00 00 0a 8b 00 04 5d b8 d8
|
||||
0000030 22
|
||||
0000031
|
||||
```
|
||||
```
|
||||
56
content/1.1.1.1/encrypted-dns/dns-over-tls.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
pcx-content-type: concept
|
||||
title: DNS over TLS
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# DNS over TLS
|
||||
|
||||
By default, DNS is sent over a plaintext connection. DNS over TLS (DoT) is one way to send DNS queries over an encrypted connection. Cloudflare supports DNS over TLS on standard port 853 and is compliant with [RFC7858](https://tools.ietf.org/html/rfc7858). With DoT, the encryption happens at the transport layer, where it adds TLS encryption on top of the user datagram protocol (UDP).
|
||||
|
||||
## How it works
|
||||
|
||||
Cloudflare supports DNS over TLS (DoT) on `1.1.1.1` and `1.0.0.1` on port 853. If your DoT client does not support IP addresses, Cloudflare's DoT endpoint can also be reached by hostname on `1dot1dot1dot1.cloudflare-dns.com` and `one.one.one.one`. A stub resolver (the DNS client on a device that talks to the DNS resolver) connects to the resolver over a TLS connection:
|
||||
|
||||
1. Before the connection, the DNS stub resolver has stored a base64 encoded SHA256 hash of the TLS certificate from `cloudflare-dns.com` (called SPKI).
|
||||
2. DNS stub resolver establishes a TCP connection with `cloudflare-dns.com:853`.
|
||||
3. DNS stub resolver initiates a TLS handshake.
|
||||
4. In the TLS handshake, `cloudflare-dns.com` presents its TLS certificate.
|
||||
5. Once the TLS connection is established, the DNS stub resolver can send DNS over an encrypted connection, preventing eavesdropping and tampering.
|
||||
6. All DNS queries sent over the TLS connection must comply with specifications of [sending DNS over TCP](https://tools.ietf.org/html/rfc1035#section-4.2.2).
|
||||
|
||||
## Example
|
||||
|
||||
```sh
|
||||
$ kdig -d @1.1.1.1 +tls-ca +tls-host=cloudflare-dns.com example.com
|
||||
;; DEBUG: Querying for owner(example.com.), class(1), type(1), server(1.1.1.1), port(853), protocol(TCP)
|
||||
;; DEBUG: TLS, imported 170 system certificates
|
||||
;; DEBUG: TLS, received certificate hierarchy:
|
||||
;; DEBUG: #1, C=US,ST=CA,L=San Francisco,O=Cloudflare\, Inc.,CN=\*.cloudflare-dns.com
|
||||
;; DEBUG: SHA-256 PIN: yioEpqeR4WtDwE9YxNVnCEkTxIjx6EEIwFSQW+lJsbc=
|
||||
;; DEBUG: #2, C=US,O=DigiCert Inc,CN=DigiCert ECC Secure Server CA
|
||||
;; DEBUG: SHA-256 PIN: PZXN3lRAy+8tBKk2Ox6F7jIlnzr2Yzmwqc3JnyfXoCw=
|
||||
;; DEBUG: TLS, skipping certificate PIN check
|
||||
;; DEBUG: TLS, The certificate is trusted.
|
||||
;; TLS session (TLS1.3)-(ECDHE-SECP256R1)-(ECDSA-SECP256R1-SHA256)-(AES-256-GC
|
||||
;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 58548
|
||||
;; Flags: qr rd ra; QUERY: 1; ANSWER: 1; AUTHORITY: 0; ADDITIONAL: 1
|
||||
|
||||
;; EDNS PSEUDOSECTION:
|
||||
;; Version: 0; flags: ; UDP size: 1536 B; ext-rcode: NOERROR
|
||||
;; PADDING: 408 B
|
||||
|
||||
;; QUESTION SECTION:
|
||||
;; example.com. IN A
|
||||
|
||||
;; ANSWER SECTION:
|
||||
example.com. 2347 IN A 93.184.216.34
|
||||
|
||||
;; Received 468 B
|
||||
;; Time 2018-03-31 15:20:57 PDT
|
||||
;; From 1.1.1.1@853(TCP) in 12.6 ms
|
||||
```
|
||||
|
||||
## Supported TLS versions
|
||||
|
||||
Cloudflare's DNS over TLS supports TLS 1.3 and TLS 1.2.
|
||||
67
content/1.1.1.1/faq.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
pcx-content-type: faq
|
||||
title: FAQ
|
||||
weight: 9
|
||||
---
|
||||
|
||||
# FAQ
|
||||
|
||||
Below you will find answers to our most commonly asked questions on 1.1.1.1 DNS resolver. If you cannot find the answer you are looking for, visit our [community page](https://community.cloudflare.com/).
|
||||
|
||||
## What is 1.1.1.1?
|
||||
|
||||
1.1.1.1 is Cloudflare's fast and secure DNS resolver. When you request to visit an application like `cloudflare.com`, your computer needs to know which server to connect you to so that it can load the application. Computers don’t know how to do this name to address translation, so they ask a specialized server to do it for them.
|
||||
|
||||
This specialized server is called a DNS recursive resolver. The resolver’s job is to find the address for a given name, like `2400:cb00:2048:1::c629:d7a2` for `cloudflare.com`, and return it to the computer that asked for it.
|
||||
|
||||
Computers are configured to talk to specific DNS resolvers, identified by IP address. Usually the configuration is managed by your ISP (like Comcast or AT\&T) if you’re on your home or wireless Internet, and by your network administrator if you’re connected to the office Internet. You can also change the configured DNS resolver your computer talks to yourself.
|
||||
|
||||
## How can I check if my computer / smartphone / tablet is connected to 1.1.1.1?
|
||||
|
||||
Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1 and that it is working.
|
||||
|
||||
## What do DNS resolvers do?
|
||||
|
||||
DNS resolvers are like address books for the Internet. They translate the name of places to addresses so that your browser can figure out how to get there. DNS resolvers do this by working backwards from the top until they find the website your are looking for.
|
||||
|
||||
Every resolver knows how to find the invisible ‘.’ at the end of domain names (for example, `cloudflare.com.`). There are [hundreds of root servers](http://www.root-servers.org/) all over the world that host the ‘.’ file, and resolvers are [hard coded to know the IP addresses](http://www.internic.net/domain/named.root) of those servers. Cloudflare itself hosts [that file](http://www.internic.net/domain/root.zone) on all of its servers around the world through a [partnership with ISC](https://blog.cloudflare.com/f-root/).
|
||||
|
||||
The resolver asks one of the root servers where to find the next link in the chain — the top-level domain (abbreviated to TLD) or domain ending. An example of a TLD is `.com` or `.org`. Luckily, the root servers store the locations of all the TLD servers, so they can return which IP address the DNS resolver should go ask next.
|
||||
|
||||
The resolver then asks the TLD’s servers where it can find the domain it is looking for. For example, a resolver might ask `.com` where to find `cloudflare.com`. TLDs host a file containing the location of every domain using the TLD.
|
||||
|
||||
Once the resolver has the final IP address, it returns the answer to the computer that asked.
|
||||
|
||||
This whole system is called the Domain Name System (DNS). This system includes the servers that host the information (called authoritative DNS) and the servers that seek the information (the DNS resolvers).
|
||||
|
||||
## Does 1.1.1.1 support ANY?
|
||||
|
||||
Cloudflare [stopped supporting the ANY query](https://blog.cloudflare.com/deprecating-dns-any-meta-query-type/) in 2015 as ANY queries are more often used to perpetuate large volumetric attacks against the DNS system than valid use. 1.1.1.1 returns `NOTIMPL` when asked for `qtype==ANY`.
|
||||
|
||||
## How does 1.1.1.1 work with DNSSEC?
|
||||
|
||||
1.1.1.1 is a DNSSEC validating resolver. 1.1.1.1 sends the DO (DNSSEC Ok) bit on every query to convey to the authoritative server that it wishes to receive signed answers if available. 1.1.1.1 supports [all signature algorithms](https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml) including the newer DS-13, DS-14, and DNS-15.
|
||||
|
||||
## Does 1.1.1.1 send EDNS client subnet header?
|
||||
|
||||
1.1.1.1 is a privacy centric resolver so it does not send any client IP information and does not send the EDNS Client Subnet Header to authoritative servers.
|
||||
|
||||
## Does 1.1.1.1 support IPv6?
|
||||
|
||||
1.1.1.1 has full IPv6 support.
|
||||
|
||||
## What is Purge Cache?
|
||||
|
||||
1.1.1.1's Purge Cache tool allows you to refresh 1.1.1.1's DNS cache for domain names. To refresh the cache for a domain name, visit the [Purge Cache page](https://1.1.1.1/purge-cache/).
|
||||
|
||||
## What is query name minimization?
|
||||
|
||||
Cloudflare minimizes privacy leakage by only sending minimal query name to authoritative DNS servers. For example, if a client is looking for foo.bar.example.com, the only part of the query 1.1.1.1 discloses to .com is that we want to know who’s responsible for example.com and the zone internals stay hidden.
|
||||
|
||||
## What are root hints?
|
||||
|
||||
For decreased latency, reduced privacy leakage of queries and lower load on the DNS system, 1.1.1.1 upstreams to [locally hosted root zone files](https://blog.cloudflare.com/f-root/).
|
||||
|
||||
## Can IPs used by 1.1.1.1 be allowlisted?
|
||||
|
||||
Authoritative DNS providers may want to allowlist IP's 1.1.1.1 uses to query upstream DNS providers. The comprehensive list of IP's to allowlist is available at <https://www.cloudflare.com/ips/>.
|
||||
|
|
@ -1,21 +1,22 @@
|
|||
---
|
||||
order: 4
|
||||
pcx-content-type: reference
|
||||
title: Support for IPv6-only networks
|
||||
weight: 5
|
||||
---
|
||||
|
||||
# Support for IPv6-only networks
|
||||
|
||||
While network infrastructure is shifting towards IPv6-only networks, providers still need to support IPv4 addresses. Dual-stack networks are networks in which all nodes have both IPv4 and IPv6 connectivity capabilities, and can therefore understand both IPv4 and IPv6 packets.
|
||||
While network infrastructure is shifting towards IPv6-only networks, providers still need to support IPv4 addresses. Dual-stack networks are networks in which all nodes have both IPv4 and IPv6 connectivity capabilities, and can therefore understand both IPv4 and IPv6 packets.
|
||||
|
||||
1.1.1.1 supports DNS64, a mechanism that synthesizes AAAA records from A records when no AAAA records exist. DNS64 allows configuring a DNS resolver to synthesize IPv6 addresses from IPv4 answers.
|
||||
|
||||
<Aside type="note">
|
||||
{{<Aside type="note">}}
|
||||
|
||||
You should only enable DNS64 if you are managing or using an IPv6-only network. While the resolver can synthesize IPv6 addresses, it cannot synthesize their record signatures for domains using DNSSEC, so a DNS client that is able to revalidate signatures would reject these extra records without signatures.
|
||||
|
||||
A good tradeoff is to use a secure protocol such as DNS over TLS, or DNS over HTTPS between the client and the resolver to prevent tampering.
|
||||
|
||||
</Aside>
|
||||
{{</Aside>}}
|
||||
|
||||
## Configure DNS64
|
||||
|
||||
|
|
@ -37,4 +38,4 @@ Some devices use separate fields for all eight parts of IPv6 addresses and canno
|
|||
|
||||
After your configuration, visit an IPv4 only address to check if you can reach it. For example, you can visit https://ipv4.google.com.
|
||||
|
||||
Visit http://test-ipv6.com/ to test if it can detect your IPv6 address. If you receive a `10/10`, your IPv6 is configured correctly.
|
||||
Visit http://test-ipv6.com/ to test if it can detect your IPv6 address. If you receive a `10/10`, your IPv6 is configured correctly.
|
||||
58
content/1.1.1.1/network-operators.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
pcx-content-type: reference
|
||||
title: Network operators
|
||||
weight: 6
|
||||
---
|
||||
|
||||
# Network operators
|
||||
|
||||
Network operators, including Internet Service Providers (ISPs), device manufacturers, public WiFi networks, municipal broadband providers, and security scanning services can use [1.1.1.1](/1.1.1.1/setup-1.1.1.1/) and [1.1.1.1 for Families](/1.1.1.1/1.1.1.1-for-families/) in place of operating their own recursive DNS infrastructure.
|
||||
|
||||
Using 1.1.1.1 can improve performance for end-users due to Cloudflare's extensive [global network](https://www.cloudflare.com/network/), as well as provide higher overall cache hit rates due to our regional caches.
|
||||
|
||||
The 1.1.1.1 resolver was designed with a privacy-first approach. Refer to our [data and privacy policies](/1.1.1.1/privacy/public-dns-resolver/) for what is logged and retained by 1.1.1.1.
|
||||
|
||||
## Configuring 1.1.1.1
|
||||
|
||||
There are multiple ways to use 1.1.1.1 as an operator:
|
||||
|
||||
- Including a [DNS over HTTPS](/1.1.1.1/encrypted-dns/dns-over-https/) or [DNS over TLS](/1.1.1.1/encrypted-dns/dns-over-tls/) proxy on end-user routers or devices (best for privacy).
|
||||
- Pushing 1.1.1.1 to devices via DHCP/PPP within an operator network (recommended; most practical).
|
||||
- Having a DNS proxy on a edge router make requests to 1.1.1.1 on behalf of all connected devices.
|
||||
|
||||
Where possible, we recommend using encrypted transports (DNS over HTTPS or TLS) for queries, as this provides the highest degree of privacy for users over last-mile networks.
|
||||
|
||||
## Available Endpoints
|
||||
|
||||
{{<Aside type="note">}}
|
||||
|
||||
[Cloudflare Zero Trust](https://www.cloudflare.com/products/zero-trust/) supports customizable [DNS policies](/cloudflare-one/policies/filtering/dns-policies-builder), analytics, additional built-in filtering categories, and custom rate limiting capabilities.
|
||||
|
||||
If you require additional controls over our public 1.1.1.1 resolver, [contact us](https://www.cloudflare.com/products/zero-trust/).
|
||||
|
||||
{{</Aside>}}
|
||||
|
||||
The publicly available endpoints for 1.1.1.1 are detailed in the following table:
|
||||
|
||||
{{<table-wrap>}}
|
||||
|
||||
| Resolver | IP Addresses | DNS over HTTPS endpoint | DNS over TLS endpoint |
|
||||
| ---------------------------------- | --------------------- | ----------------------------------------------- | ----------------------------- |
|
||||
| 1.1.1.1 (unfiltered) | `1.1.1.1` / `1.0.0.1` | `https://cloudflare-dns.com/dns-query` | `cloudflare-dns.com` |
|
||||
| Families (Malware) | `1.1.1.2` / `1.0.0.2` | `https://security.cloudflare-dns.com/dns-query` | `security.cloudflare-dns.com` |
|
||||
| Families (Adult Content + Malware) | `1.1.1.3` / `1.0.0.3` | `https://family.cloudflare-dns.com/dns-query` | `family.cloudflare-dns.com` |
|
||||
|
||||
{{</table-wrap>}}
|
||||
|
||||
You may wish to provide end users with options to change from the default 1.1.1.1 resolver to one of the [1.1.1.1 for Families](/1.1.1.1/1.1.1.1-for-families/) endpoints.
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
Operators using 1.1.1.1 for typical Internet-facing applications and/or users should not encounter any rate limiting for their users. In some rare cases, security scanning use-cases or proxied traffic may be rate limited to protect our infrastructure as well as upstream DNS infrastructure from potential abuse.
|
||||
|
||||
Best practices include:
|
||||
|
||||
- Avoiding tunneling or proxying all queries from a single IP address at high rates. Distributing queries across multiple public IPs will improve this without impacting cache hit rates (caches are regional).
|
||||
- A high rate of "uncacheable" responses (such as `SERVFAIL`) against the same domain may be rate limited to protect upstream, authoritative nameservers. Many authoritative nameservers enforce their own rate limits, and we strive to avoid overloading third party infrastructure where possible.
|
||||
|
||||
If you're a network operator and still have outstanding questions, contact `resolver@cloudflare.com` with your use-case and we'll be happy to discuss further.
|
||||
11
content/1.1.1.1/other-ways-to-use-1.1.1.1/_index.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
pcx-content-type: navigation
|
||||
title: Other ways to use 1.1.1.1
|
||||
weight: 7
|
||||
---
|
||||
|
||||
# Other ways to use 1.1.1.1
|
||||
|
||||
There are many other ways to use 1.1.1.1 beyond the traditional set up in operating systems and routers.
|
||||
|
||||
{{<directory-listing>}}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
---
|
||||
pcx-content-type: tutorial
|
||||
title: DNS in Google Sheets
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# DNS in Google Sheets
|
||||
|
||||
1.1.1.1 works directly inside Google Sheets. To get started, create a [Google Function](https://developers.google.com/apps-script/guides/sheets/functions) with the following code:
|
||||
|
||||
```js
|
||||
function NSLookup(type, domain) {
|
||||
if (typeof type == 'undefined') {
|
||||
throw new Error('Missing parameter 1 dns type');
|
||||
}
|
||||
|
||||
if (typeof domain == 'undefined') {
|
||||
throw new Error('Missing parameter 2 domain name');
|
||||
}
|
||||
|
||||
type = type.toUpperCase();
|
||||
|
||||
var url =
|
||||
'https://cloudflare-dns.com/dns-query?name=' +
|
||||
encodeURIComponent(domain) +
|
||||
'&type=' +
|
||||
encodeURIComponent(type);
|
||||
|
||||
var options = {
|
||||
muteHttpExceptions: true,
|
||||
headers: {
|
||||
accept: 'application/dns-json',
|
||||
},
|
||||
};
|
||||
|
||||
var result = UrlFetchApp.fetch(url, options);
|
||||
var rc = result.getResponseCode();
|
||||
var resultText = result.getContentText();
|
||||
|
||||
if (rc !== 200) {
|
||||
throw new Error(rc);
|
||||
}
|
||||
|
||||
var errors = [
|
||||
{ name: 'NoError', description: 'No Error' }, // 0
|
||||
{ name: 'FormErr', description: 'Format Error' }, // 1
|
||||
{ name: 'ServFail', description: 'Server Failure' }, // 2
|
||||
{ name: 'NXDomain', description: 'Non-Existent Domain' }, // 3
|
||||
{ name: 'NotImp', description: 'Not Implemented' }, // 4
|
||||
{ name: 'Refused', description: 'Query Refused' }, // 5
|
||||
{ name: 'YXDomain', description: 'Name Exists when it should not' }, // 6
|
||||
{ name: 'YXRRSet', description: 'RR Set Exists when it should not' }, // 7
|
||||
{ name: 'NXRRSet', description: 'RR Set that should exist does not' }, // 8
|
||||
{ name: 'NotAuth', description: 'Not Authorized' }, // 9
|
||||
];
|
||||
|
||||
var response = JSON.parse(resultText);
|
||||
|
||||
if (response.Status !== 0) {
|
||||
return errors[response.Status].name;
|
||||
}
|
||||
|
||||
var outputData = [];
|
||||
|
||||
for (var i in response.Answer) {
|
||||
outputData.push(response.Answer[i].data);
|
||||
}
|
||||
|
||||
var outputString = outputData.join(',');
|
||||
|
||||
return outputString;
|
||||
}
|
||||
```
|
||||
|
||||
Now, when you feed the function `NSLookup` a record type and a domain, you will get a DNS record value in the cell you called `NSLookup`.
|
||||
|
||||
The record types supported are:
|
||||
|
||||
- A
|
||||
- AAAA
|
||||
- CAA
|
||||
- CNAME
|
||||
- DS
|
||||
- DNSKEY
|
||||
- MX
|
||||
- NS
|
||||
- NSEC
|
||||
- NSEC3
|
||||
- RRSIG
|
||||
- SOA
|
||||
- TXT
|
||||
|
||||
For example, typing:
|
||||
|
||||
```txt
|
||||
NSLookup(B1, B2)
|
||||
```
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
Returns
|
||||
|
||||
```txt
|
||||
198.41.214.162, 198.41.215.162
|
||||
```
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
300
content/1.1.1.1/other-ways-to-use-1.1.1.1/dns-over-discord.md
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
---
|
||||
pcx-content-type: tutorial
|
||||
title: DNS over Discord
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# DNS over Discord
|
||||
|
||||
1.1.1.1 works from a Discord server, thanks to the [@1.1.1.1 bot](https://cfl.re/3nM6VfQ).
|
||||
|
||||
To start using the DNS over Discord bot, invite it to your Discord server using this link: <https://cfl.re/3nM6VfQ>
|
||||
|
||||
## dig command
|
||||
|
||||
Once the bot is in your server, type `/dig` to begin using the bot's main command — performing DNS lookups. This will provide a native interface within Discord that allows you to specify the domain to lookup, an optional DNS record type and an optional flag for a short result.
|
||||
|
||||
If only a domain is given for the command, the bot will default to looking for 'A' DNS records, and will return the full format result, not the short form.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/dig domain: cloudflare.com`_
|
||||
|
||||
### Supported record types
|
||||
|
||||
Discord has a limit of 25 options in slash commands, so DNS over Discord offers the 25 most common DNS record types to choose from:
|
||||
|
||||
- A
|
||||
- AAAA
|
||||
- CAA
|
||||
- CDNSKEY
|
||||
- CDS
|
||||
- CERT
|
||||
- CNAME
|
||||
- DNSKEY
|
||||
- DS
|
||||
- HINFO
|
||||
- HTTPS
|
||||
- LOC
|
||||
- MX
|
||||
- NAPTR
|
||||
- NS
|
||||
- PTR
|
||||
- SMIMEA
|
||||
- SOA
|
||||
- SPF
|
||||
- SRV
|
||||
- SSHFP
|
||||
- SVCB
|
||||
- TLSA
|
||||
- TXT
|
||||
- URI
|
||||
|
||||
To query other DNS record types, or multiple record types at once, use the `/multi-dig` command.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
### Short form response
|
||||
|
||||
Much like the dig command itself, DNS over Discord has an optional flag in the dig command that allows the user to request a response in the short form.
|
||||
|
||||
When this is requested, the name and TTL columns will be excluded, with just the data column returned without the table formatting, similar to the equivalent dig command response.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/dig domain: cloudflare.com type: AAAA short: true`_
|
||||
|
||||
### Refreshing existing results
|
||||
|
||||
As part of the response that the DNS over Discord bot returns for dig commands, there is a button to refresh the results.
|
||||
|
||||
Any user can press this button, triggering the bot to re-request the DNS query in the message and update the results in the message.
|
||||
|
||||
The refresh button is available on all responses to the dig command, including those that resulted in an error, such as an unknown domain or no records found.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/dig domain: cloudflare.com`_
|
||||
|
||||
## multi-dig command
|
||||
|
||||
If you want to look up multiple DNS record types at once, use the `/multi-dig` command. This allows you to specify any supported DNS record type, and multiple types separated by a space.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/multi-dig domain: cloudflare.com types: A AAAA`_
|
||||
|
||||
### Supported record types
|
||||
|
||||
When providing DNS record types for the `/multi-dig` command, Discord will not prompt you with options. Please provide a space-separated list of valid DNS record types to lookup, as any invalid options will be silently dropped. 'A' records will be used as the default if no valid types are given.
|
||||
|
||||
The following DNS record types are supported and considered valid by the bot:
|
||||
|
||||
- A
|
||||
- AAAA
|
||||
- AFSDB
|
||||
- APL
|
||||
- CAA
|
||||
- CDNSKEY
|
||||
- CDS
|
||||
- CERT
|
||||
- CNAME
|
||||
- CSYNC
|
||||
- DHCID
|
||||
- DLV
|
||||
- DNAME
|
||||
- DNSKEY
|
||||
- DS
|
||||
- EUI48
|
||||
- EUI64
|
||||
- HINFO
|
||||
- HIP
|
||||
- HTTPS
|
||||
- IPSECKEY
|
||||
- KEY
|
||||
- KX
|
||||
- LOC
|
||||
- MX
|
||||
- NAPTR
|
||||
- NS
|
||||
- NSEC
|
||||
- NSEC3
|
||||
- NSEC3PARAM
|
||||
- OPENPGPKEY
|
||||
- PTR
|
||||
- RP
|
||||
- SMIMEA
|
||||
- SOA
|
||||
- SPF
|
||||
- SRV
|
||||
- SSHFP
|
||||
- SVCB
|
||||
- TA
|
||||
- TKEY
|
||||
- TLSA
|
||||
- TXT
|
||||
- URI
|
||||
- ZONEMD
|
||||
|
||||
_Use '\*' (asterisk) in place of a record type to get DNS results for all supported types._
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
### Short form response
|
||||
|
||||
Like the main dig command, the multi-dig command also supports the optional short flag after the types have been specified in the slash command.
|
||||
|
||||
<div class="large-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/multi-dig domain: cloudflare.com types: CDS CDNSKEY short: true`_
|
||||
|
||||
### Refreshing existing results
|
||||
|
||||
The multi-dig command also provides a refresh button below each set of DNS results requested (or after each block of 10 DNS record types if more than 10 were requested).
|
||||
|
||||
As with the dig command, any user can press the refresh button to refresh the displayed DNS results, including for DNS queries that had previously failed.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/multi-dig domain: cloudflare.com types: A AAAA`_
|
||||
|
||||
## whois command
|
||||
|
||||
The `/whois` command allows you to perform an RDAP/WHOIS lookup right in Discord for a given domain, IP or ASN.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
### Examples
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/whois query: cloudflare.com`_
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/whois query: 104.16.132.229`_
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/whois query: 2606:4700::6810:84e5`_
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/whois query: 13335`_
|
||||
|
||||
## Other commands
|
||||
|
||||
The bot also has a set of helper commands available to get more information about the bot and quick links.
|
||||
|
||||
### help command
|
||||
|
||||
The `/help` command provides in-Discord documentation about all the commands available in the 1.1.1.1 DNS over Discord bot.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/help`_
|
||||
|
||||
### privacy command
|
||||
|
||||
The `/privacy` command displays the privacy policy notice for using the 1.1.1.1 DNS over Discord bot. This notice can also be viewed at <https://dns-over-discord.v4.wtf/privacy>.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/privacy`_
|
||||
|
||||
### github command
|
||||
|
||||
The DNS over Discord bot is open-source, and the `/github` command provides a quick link to access the GitHub repository. The GitHub repository can be accessed at <https://github.com/MattIPv4/DNS-over-Discord/>.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/github`_
|
||||
|
||||
### invite command
|
||||
|
||||
The `/invite` command provides the user with a quick link to invite the 1.1.1.1 DNS over Discord bot to another Discord server.
|
||||
The bot can be invited at any time with <https://cfl.re/3nM6VfQ>.
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
_`/invite`_
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
The DNS over Discord bot is deployed on [Cloudflare Workers](https://workers.cloudflare.com/).
|
||||
|
||||
You can find the source code for the bot on GitHub, as well as information on getting started with contributing to the project, at <https://github.com/MattIPv4/DNS-over-Discord/>.
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
pcx-content-type: how-to
|
||||
title: DNS over Telegram
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# DNS over Telegram
|
||||
|
||||
To perform DNS over Telegram, you will need Telegram, an end-to-end encrypted messaging app. You can download it on [telegram.org](https://telegram.org/).
|
||||
|
||||
You will also need to add the 1.1.1.1 bot to your friends list in Telegram before using this functionality:
|
||||
|
||||
1. Open the Telegram app.
|
||||
2. Click **Contacts**.
|
||||
3. Search for `onedotonedotonedotonedotbot`.
|
||||
4. Click the **1.1.1.1 bot** when it appears in the search results, and press **Start**.
|
||||
5. You can send a single domain name, which will default to returning the AAAA record. For example:
|
||||
|
||||
<br />
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
Or you can send a record type followed by a domain name. The record types supported are:
|
||||
|
||||
- A
|
||||
- AAAA
|
||||
- CAA
|
||||
- CNAME
|
||||
- DNSKEY
|
||||
- DS
|
||||
- MX
|
||||
- NS
|
||||
- NSEC
|
||||
- NSEC3
|
||||
- RRSIG
|
||||
- SOA
|
||||
- TXT
|
||||
|
||||
<br />
|
||||
|
||||
Example:
|
||||
|
||||
<div class="medium-img">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
105
content/1.1.1.1/other-ways-to-use-1.1.1.1/dns-over-tor.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
---
|
||||
pcx-content-type: tutorial
|
||||
title: DNS over Tor
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# DNS over Tor
|
||||
|
||||
{{<Aside type="warning">}}
|
||||
|
||||
The hidden resolver is still an experimental service and should not be used in production or for other critical uses.
|
||||
|
||||
{{</Aside>}}
|
||||
|
||||
If you do not want to disclose your IP address to the resolver, you can use our Tor onion service. Resolving DNS queries through the Tor network guarantees a significantly higher level of anonymity than making the requests directly. Not only does doing so prevent the resolver from ever seeing your IP address, but it also prevents your ISP from knowing that you attempted to resolve a domain name.
|
||||
|
||||
Read more about this service in [this blog post](https://blog.cloudflare.com/welcome-hidden-resolver/).
|
||||
|
||||
## Setting up a Tor client
|
||||
|
||||
The important difference between using all other modes of DNS and this one is that packet routing no longer uses IP addresses, and therefore all connections must be routed through a Tor client.
|
||||
|
||||
Before you start, head to the [Tor Project website](https://www.torproject.org/download/download.html.en) to download and install a Tor client. If you use the Tor Browser, it will automatically start a [SOCKS proxy](https://en.wikipedia.org/wiki/SOCKS) at `127.0.0.1:9150`.
|
||||
|
||||
If you use Tor from the command line, create the following configuration file:
|
||||
|
||||
```txt
|
||||
SOCKSPort 9150
|
||||
```
|
||||
|
||||
Then you can run tor with:
|
||||
|
||||
```txt
|
||||
tor -f tor.conf
|
||||
```
|
||||
|
||||
Also, if you use the Tor Browser, you can head to the resolver's address to see the usual 1.1.1.1 page:
|
||||
|
||||
```txt
|
||||
https://dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion/
|
||||
```
|
||||
|
||||
{{<Aside type="note" header="Note">}}
|
||||
|
||||
The HTTPS certificate indicator should say "Cloudflare, Inc. (US)."
|
||||
|
||||
{{</Aside>}}
|
||||
|
||||
**Tip:** If you ever forget the `dns4torblahblahblah.onion` address, use cURL:
|
||||
|
||||
```sh
|
||||
$ curl -sI https://tor.cloudflare-dns.com | grep -i alt-svc
|
||||
alt-svc: h2="dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion:443"; ma=315360000; persist=1
|
||||
```
|
||||
|
||||
## Setting up a local DNS proxy using socat
|
||||
|
||||
Of course, not all DNS clients support connecting to the Tor client, so the easiest way to connect any DNS-speaking software to the hidden resolver is by forwarding ports locally, for instance [using `socat`](http://www.dest-unreach.org/socat/).
|
||||
|
||||
### DNS over TCP, TLS, and HTTPS
|
||||
|
||||
The hidden resolver is set up to listen on TCP ports 53 and 853 for DNS over TCP and TLS. After setting up a Tor proxy, run the following `socat` command as a privileged user, replacing the port number appropriately:
|
||||
|
||||
```sh
|
||||
$ PORT=853; socat TCP4-LISTEN:${PORT},reuseaddr,fork SOCKS4A:127.0.0.1:dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion:${PORT},socksport=9150
|
||||
```
|
||||
|
||||
From here, you can follow the regular guide for [Setting up 1.1.1.1](/1.1.1.1/setup-1.1.1.1/), except you should always use `127.0.0.1` instead of 1.1.1.1. If you need to access the proxy from another device, simply replace `127.0.0.1` in `socat` commands with your local IP address.
|
||||
|
||||
### DNS over UDP
|
||||
|
||||
Note that the Tor network does not support UDP connections, which is why some hacking is needed. If your client only supports UDP connections, the solution is to encapsulate packets to port `UDP:53` on localhost as TCP packets, using the following `socat` command:
|
||||
|
||||
```sh
|
||||
$ socat UDP4-LISTEN:53,reuseaddr,fork SOCKS4A:127.0.0.1:dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion:253,socksport=9150
|
||||
```
|
||||
|
||||
### DNS over HTTPS
|
||||
|
||||
[As explained in the blog post](https://blog.cloudflare.com/welcome-hidden-resolver/), our favorite way of using the hidden resolver is using DNS over HTTPS (DoH). To set it up:
|
||||
|
||||
1. Download `cloudflared` by following the guide for [Running a DNS over HTTPS Client](/1.1.1.1/encrypted-dns/dns-over-https/dns-over-https-client/).
|
||||
|
||||
2. Start a Tor SOCKS proxy and use `socat` to forward port TCP:443 to localhost:
|
||||
|
||||
```sh
|
||||
$ socat TCP4-LISTEN:443,reuseaddr,fork SOCKS4A:127.0.0.1:dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion:443,socksport=9150
|
||||
```
|
||||
|
||||
3. Instruct your machine to treat the `.onion` address as localhost:
|
||||
|
||||
```bash
|
||||
$ cat << EOF >> /etc/hosts
|
||||
127.0.0.1 dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion
|
||||
EOF
|
||||
```
|
||||
|
||||
4. Finally, start a local DNS over UDP daemon:
|
||||
|
||||
```sh
|
||||
$ cloudflared proxy-dns --upstream "https://dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion/dns-query"
|
||||
INFO[0000] Adding DNS upstream url="https://dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion/dns-query"
|
||||
INFO[0000] Starting DNS over HTTPS proxy server addr="dns://localhost:53"
|
||||
INFO[0000] Starting metrics server addr="127.0.0.1:35659"
|
||||
```
|
||||
13
content/1.1.1.1/privacy/_index.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
pcx-content-type: reference
|
||||
title: Privacy
|
||||
weight: 8
|
||||
---
|
||||
|
||||
# Privacy
|
||||
|
||||
* [1.1.1.1 Public DNS Resolver](/1.1.1.1/public-dns-resolver/): This document provides details on our collection, use, and disclosure of the information processed by the 1.1.1.1 public DNS resolver. The 1.1.1.1 public DNS resolver service is governed by our [Privacy Policy](https://www.cloudflare.com/privacypolicy/).
|
||||
|
||||
* [Resolver for Firefox](/1.1.1.1/cloudflare-resolver-firefox/): This document outlines our collection, use, and disclosure of the information processed by the Cloudflare Resolver for Firefox. Any data Cloudflare processes in connection with the Cloudflare Resolver for Firefox is as a data processor acting pursuant to Mozilla’s data processing instructions. Cloudflare Resolver for Firefox is not covered by our main Privacy Policy and is separate from the 1.1.1.1 public DNS resolver.
|
||||
|
||||
* [1.1.1.1 Application](https://www.cloudflare.com/application/privacypolicy/): This policy applies to our collection, use, and disclosure of the information from Cloudflare’s consumer-facing 1.1.1.1 Applications, such as our 1.1.1.1 Application for iOS and Android.
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
order:
|
||||
pcx-content-type: reference
|
||||
title: Cloudflare Resolver for Firefox
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# Cloudflare Resolver for Firefox
|
||||
|
|
@ -19,37 +20,37 @@ To counter such threats, Mozilla has partnered with Cloudflare to provide direct
|
|||
|
||||
Any data Cloudflare handles as a result of its resolver for Firefox is as a data processor acting pursuant to Firefox’s data processing instructions. Therefore, the data Cloudflare collects and processes pursuant to its agreement with Firefox is not covered by the [Cloudflare Privacy Policy](https://www.cloudflare.com/privacypolicy/). As part of its agreement with Firefox, Cloudflare has agreed to collect only a limited amount of data about the DNS requests that are sent to the Cloudflare Resolver for Firefox via the Firefox browser. Cloudflare will collect only the following information from Firefox users:
|
||||
|
||||
* date
|
||||
* dateTime
|
||||
* srcAsNum
|
||||
* srcIPVersion
|
||||
* dstIPVersion
|
||||
* dstIPv6
|
||||
* dstIPv4
|
||||
* dstPort
|
||||
* protocol
|
||||
* queryName
|
||||
* queryType
|
||||
* queryClass
|
||||
* queryRd
|
||||
* queryDo
|
||||
* querySize
|
||||
* queryEdns
|
||||
* ednsVersion
|
||||
* ednsPayload
|
||||
* ednsNsid
|
||||
* responseType
|
||||
* responseCode
|
||||
* responseSize
|
||||
* responseCount
|
||||
* responseTimeMs
|
||||
* responseCached
|
||||
* responseMinTTL
|
||||
* answerData type
|
||||
* answerData
|
||||
* validationState
|
||||
* coloID (unique Cloudflare data center ID)
|
||||
* metalId (unique Cloudflare data center ID)
|
||||
- date
|
||||
- dateTime
|
||||
- srcAsNum
|
||||
- srcIPVersion
|
||||
- dstIPVersion
|
||||
- dstIPv6
|
||||
- dstIPv4
|
||||
- dstPort
|
||||
- protocol
|
||||
- queryName
|
||||
- queryType
|
||||
- queryClass
|
||||
- queryRd
|
||||
- queryDo
|
||||
- querySize
|
||||
- queryEdns
|
||||
- ednsVersion
|
||||
- ednsPayload
|
||||
- ednsNsid
|
||||
- responseType
|
||||
- responseCode
|
||||
- responseSize
|
||||
- responseCount
|
||||
- responseTimeMs
|
||||
- responseCached
|
||||
- responseMinTTL
|
||||
- answerData type
|
||||
- answerData
|
||||
- validationState
|
||||
- coloID (unique Cloudflare data center ID)
|
||||
- metalId (unique Cloudflare data center ID)
|
||||
|
||||
All of the above information will be stored briefly as part of Cloudflare’s temporary logs, and then permanently deleted within 24 hours of Cloudflare’s receipt of such information. In addition to the above information, Cloudflare will also collect and store the following information as part of its permanent logs.
|
||||
|
||||
|
|
@ -63,12 +64,12 @@ Information stored in Cloudflare’s permanent logs will be anonymized and may b
|
|||
|
||||
Cloudflare understands how important your data is to you, which is why we promise to use the information that we collect from the Cloudflare Resolver for Firefox solely to improve the performance of Cloudflare Resolver for Firefox and to assist us in debugging efforts if an issue arises. In addition to limiting our collection and use of your data, Cloudflare also promises:
|
||||
|
||||
* Cloudflare will not retain or sell or transfer to any third party (except as may be required by law) any personal information, IP addresses or other user identifiers from the DNS queries sent from the Firefox browser to the Cloudflare Resolver for Firefox;
|
||||
- Cloudflare will not retain or sell or transfer to any third party (except as may be required by law) any personal information, IP addresses or other user identifiers from the DNS queries sent from the Firefox browser to the Cloudflare Resolver for Firefox;
|
||||
|
||||
* Cloudflare will not combine the data that it collects from such queries, with any other Cloudflare or third party data in any way that can be used to identify individual end users;
|
||||
- Cloudflare will not combine the data that it collects from such queries, with any other Cloudflare or third party data in any way that can be used to identify individual end users;
|
||||
|
||||
* Cloudflare will not sell, license, sublicense, or grant any rights to your data to any other person or entity without Mozilla’s explicit written permission.
|
||||
- Cloudflare will not sell, license, sublicense, or grant any rights to your data to any other person or entity without Mozilla’s explicit written permission.
|
||||
|
||||
### What about government requests for content blocking?
|
||||
|
||||
Cloudflare does not block or filter content through the Cloudflare Resolver for Firefox. As part of its agreement with Mozilla, Cloudflare is providing only direct DNS resolution. If Cloudflare were to receive written requests from law enforcement and government agencies to block access to domains or content through the Cloudflare resolver for Firefox, Cloudflare would, in consultation with Mozilla, exhaust our legal remedies before complying with such a request. We also commit to documenting any government request to block access in our semi-annual transparency report, unless legally prohibited from doing so.
|
||||
Cloudflare does not block or filter content through the Cloudflare Resolver for Firefox. As part of its agreement with Mozilla, Cloudflare is providing only direct DNS resolution. If Cloudflare were to receive written requests from law enforcement and government agencies to block access to domains or content through the Cloudflare resolver for Firefox, Cloudflare would, in consultation with Mozilla, exhaust our legal remedies before complying with such a request. We also commit to documenting any government request to block access in our semi-annual transparency report, unless legally prohibited from doing so.
|
||||
117
content/1.1.1.1/privacy/public-dns-resolver.md
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
---
|
||||
pcx-content-type: reference
|
||||
title: 1.1.1.1 Public DNS Resolver
|
||||
weight: 0
|
||||
---
|
||||
|
||||
# 1.1.1.1 Public DNS Resolver
|
||||
|
||||
_Last updated September 30, 2020_
|
||||
|
||||
## Cloudflare’s commitment to privacy: 1.1.1.1 Public DNS Resolver
|
||||
|
||||
The 1.1.1.1 public DNS resolver is governed by our [Privacy Policy](https://www.cloudflare.com/privacypolicy/). This document provides additional details on our collection, use, and disclosure of the information collected from the 1.1.1.1 public DNS resolver.
|
||||
|
||||
---
|
||||
|
||||
Nearly everything on the Internet starts with a DNS request. DNS is the Internet’s directory. Click on a link, open an app, send an email, and the first thing your phone or computer does is ask its directory: where can I find this?
|
||||
|
||||
Unfortunately, by default, DNS is usually slow and insecure. Your ISP, and anyone else listening in on the Internet, can see every site you visit and every app you use — even if their content is encrypted. Creepily, some DNS providers sell data about your Internet activity or use it to target you with ads.
|
||||
|
||||
Given the current state of affairs, Cloudflare created a DNS resolver with your privacy and security in mind. Cloudflare, in partnership with APNIC, runs the 1.1.1.1 public resolver, a recursive DNS service that values user privacy and security. DNS requests sent to our public resolver are sent over a secure channel, significantly decreasing the odds of any unwanted spying or man in the middle attacks.
|
||||
|
||||
The 1.1.1.1 public DNS resolver was designed for privacy first, and Cloudflare commits to the following:
|
||||
|
||||
1. Cloudflare will not sell or share Public Resolver users’ personal data with third parties or use personal data from the Public Resolver to target any user with advertisements.
|
||||
2. Cloudflare will only retain or use what is being asked, not information that will identify who is asking it. Except for randomly sampled network packets captured from at most 0.05% of all traffic sent to Cloudflare’s network infrastructure, Cloudflare will not retain the source IP from DNS queries to the Public Resolver in non-volatile storage. These randomly sampled packets are solely used for network troubleshooting and DoS mitigation purposes.
|
||||
3. A Public Resolver user’s IP address (referred to as the client or source IP address) will not be stored in non-volatile storage. Cloudflare will anonymize source IP addresses via IP truncation methods (last octet for IPv4 and last 80 bits for IPv6). Cloudflare will delete the truncated IP address within 25 hours.
|
||||
4. Cloudflare will retain only the limited transaction and debug log data (“Public Resolver Logs”) set forth below, for the legitimate operation of our Public Resolver and research purposes, and Cloudflare will delete the Public Resolver Logs within 25 hours.
|
||||
5. Cloudflare will not share the Public Resolver Logs with any third parties except for APNIC pursuant to a Research Cooperative Agreement. APNIC will only have limited access to query the anonymized data in the Public Resolver Logs and conduct research related to the operation of the DNS system.
|
||||
|
||||
Cloudflare has taken technical steps to ensure that we cannot retain our user’s information.
|
||||
|
||||
We have also retained one of the top four accounting firms to audit our practices and publish a public report confirming we are doing what we said we would. The report is available in the [Certifications and compliance resources](https://www.cloudflare.com/trust-hub/compliance-resources/) page.
|
||||
|
||||
## Limited data sharing with APNIC
|
||||
|
||||
Cloudflare has partnered with [APNIC Labs](https://labs.apnic.net/?p=1127), the regional Internet registry for the Asia-Pacific region to make the 1.1.1.1 IP address the home of the Cloudflare Public DNS Resolver. As part of its mission to ensure a global, open and secure Internet, APNIC conducts research about the functioning and governance of the Internet, which it makes available on its website, located at www.apnic.net.
|
||||
|
||||
Cloudflare has agreed to provide APNIC with access to some of the anonymized data that Cloudflare collects through the Cloudflare Public DNS Resolver. Specifically, APNIC will be permitted to access query names, query types, resolver location and other metadata via a Cloudflare API that will allow APNIC to study topics like the volume of DDoS attacks launched on the Internet and adoption of IPv6.
|
||||
|
||||
APNIC Labs will use such data for non-profit operational research. As part of Cloudflare’s commitment to privacy, Cloudflare will not provide APNIC with any access to the IP address associated with a client.
|
||||
|
||||
Aside from APNIC, Cloudflare will not share the Public Resolver Logs with any third party.
|
||||
|
||||
## Data in public resolver logs
|
||||
|
||||
The Public Resolver Logs we store consist entirely of the following fields:
|
||||
|
||||
- date
|
||||
- dateTime
|
||||
- srcAsNum
|
||||
- srcIPVersion
|
||||
- dstIPVersion
|
||||
- dstIPv6
|
||||
- dstIPv4
|
||||
- dstPort
|
||||
- protocol
|
||||
- queryName
|
||||
- queryType
|
||||
- queryClass
|
||||
- queryRd
|
||||
- queryDo
|
||||
- querySize
|
||||
- queryEdns
|
||||
- ednsVersion
|
||||
- ednsPayload
|
||||
- ednsNsid
|
||||
- responseType
|
||||
- responseCode
|
||||
- responseSize
|
||||
- responseCount
|
||||
- responseTimeMs
|
||||
- responseCached
|
||||
- responseMinTTL
|
||||
- answerData type
|
||||
- answerData
|
||||
- validationState
|
||||
- coloID (unique Cloudflare data center ID)
|
||||
- metalId (unique Cloudflare data center ID)
|
||||
|
||||
Additionally, recursive resolvers perform outgoing queries to various authoritative nameservers in the DNS hierarchy that are logged in subrequest fields. These logs are used for the operation and debugging of our public DNS resolver service.
|
||||
|
||||
The following subrequest data is included in the Public Resolver Logs:
|
||||
|
||||
- subrequest.ipv6 (authoritative nameserver)
|
||||
- subrequest.ipv4 (authoritative nameserver)
|
||||
- subrequest.protocol
|
||||
- subrequest.durationMs
|
||||
- subrequest.queryName
|
||||
- subrequest.queryType
|
||||
- subrequest.responseCode
|
||||
- subrequest.responseCount
|
||||
- subrequest.recordType
|
||||
- subrequest.recordData
|
||||
- subrequest.error
|
||||
|
||||
Except for the limited aggregated data generated using the Public Resolver Logs described below, all of the Public Resolver Logs are deleted within 25 hours of Cloudflare’s receipt of such information.
|
||||
|
||||
Cloudflare will only store the following aggregated data:
|
||||
|
||||
- Total number of queries with different protocol settings (for example, tcp/udp/dnssec) by Cloudflare data centers.
|
||||
- Response code/time quantiles with different protocol settings by Cloudflare data centers.
|
||||
- Total Number of Requests Processed by Cloudflare data centers.
|
||||
- Aggregate List of All Domain Names Requested, aggregate number of requests and timestamp of first time requested
|
||||
- Number of unique clients, queries over IPv4, queries over IPv6, queries with the RD bit set, queries asking for DNSSEC, number of bogus, valid, and invalid DNSSEC answers, queries by type, number of answers with each response code, response time quantiles (e.g. 50 percentile), and number of cached answers per minute, per day, per protocol (HTTPS/UDP/TCP/TLS), per Cloudflare data center, and per Autonomous System Number.
|
||||
- Number of queries, number of queries with EDNS, number of bytes and time in answers quantiles (e.g. 50 percentile) by day, month, Cloudflare data center, and by IPv4 vs IPv6.
|
||||
- Number of queries, response codes and response code quantiles (e.g. 50 percentile) by day, region, name and type.
|
||||
|
||||
Cloudflare may store the aggregated data described above indefinitely in order to power Cloudflare Radar and assist Cloudflare in improving Cloudflare services, such as, enhancing the overall performance of the Cloudflare Resolver and identifying security threats.
|
||||
|
||||
# What about requests for content blocking?
|
||||
|
||||
Cloudflare does not block or filter any content through the 1.1.1.1 Public DNS Resolver, which is designed for direct, fast DNS resolution, not for blocking or filtering content. Cloudflare does block and filter malware and adult content through 1.1.1.1 for Families, which is designed to help individuals protect their home networks.
|
||||
|
||||
In general, Cloudflare views government or civil requests to block content at the DNS level as ineffective, inefficient, and overboard. Because such a block would apply globally to all users of the resolver, regardless of where they are located, it would affect end users outside of the blocking government’s jurisdiction. A government request to block content through a globally available public recursive resolver like the 1.1.1.1 Public DNS Resolver and 1.1.1.1 for Families should therefore be evaluated as a request to block content globally.
|
||||
|
||||
Given the broad extraterritorial effect, if Cloudflare were to receive written requests from law enforcement and government agencies to block access to domains or content through the 1.1.1.1 Public DNS Resolver or to block access to domains or content through 1.1.1.1 for Families that is outside the scope of the filtering in that product, Cloudflare would pursue its legal remedies before complying with such a request. We also commit to documenting any government request to block access in our semi-annual transparency report, unless legally prohibited from doing so.
|
||||
17
content/1.1.1.1/setup-1.1.1.1/_index.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
pcx-content-type: navigation
|
||||
title: Set up 1.1.1.1
|
||||
weight: 2
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1
|
||||
|
||||
By default, the DNS server your devices use is provided by your Internet provider. To start using 1.1.1.1 for your DNS queries, you will need to change the DNS settings in your device or router.
|
||||
|
||||
Before changing your DNS servers to 1.1.1.1, take note of any information already in place. This way, you can revert to using your previous DNS server should you want to.
|
||||
|
||||
After configuring your system, you can check if you are connected to 1.1.1.1 by visiting [1.1.1.1/help](https://1.1.1.1/help).
|
||||
|
||||
Select a platform to get started:
|
||||
|
||||
{{<directory-listing>}}
|
||||
72
content/1.1.1.1/setup-1.1.1.1/android.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
title: Android
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 - Android
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 - Android
|
||||
|
||||
[1.1.1.1: Faster Internet](https://play.google.com/store/apps/details?id=com.cloudflare.onedotonedotonedotone) is the preferred method of setting up 1.1.1.1 DNS resolver, as it allows you to automatically configure your phone to use 1.1.1.1 on any network you connect to.
|
||||
|
||||
The app also allows you to enable encryption for DNS queries or enable [WARP mode](/warp-client/), which keeps all your HTTP traffic private and secure, including your DNS queries to 1.1.1.1.
|
||||
|
||||
You can select between these two options in 1.1.1.1: Faster Internet's settings. By default, 1.1.1.1:Faster Internet is configured to WARP mode.
|
||||
|
||||
## Set up 1.1.1.1: Faster Internet
|
||||
|
||||
1. Download [1.1.1.1: Faster Internet from Google Play](https://play.google.com/store/apps/details?id=com.cloudflare.onedotonedotonedotone) for free.
|
||||
2. Launch 1.1.1.1: Faster Internet and accept the Terms of Service.
|
||||
3. Toggle the **WARP** button to **Connected**.
|
||||
4. Install the VPN profile that allows your phone to connect securely to 1.1.1.1.
|
||||
5. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
Your connection to the Internet and your DNS queries are now protected. Alternatively, you may want to only encrypt your DNS queries and leave the remaining traffic unencrypted. If this is the case:
|
||||
|
||||
1. Open 1.1.1.1: Faster Internet.
|
||||
2. Toggle the WARP button and choose **Switch to DNS only mode**. If the WARP toggle is disconnected, tap the **menu button**.
|
||||
3. You will see two options: 1.1.1.1 and WARP. Select **1.1.1.1**.
|
||||
|
||||
You are now using encryption only for your DNS queries. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure everything is working.
|
||||
|
||||
## Configure 1.1.1.1 manually
|
||||
|
||||
### Android 9 Pie or later
|
||||
|
||||
Android Pie and later supports DNS over TLS to secure your queries through encryption. In Android, this option is called Private DNS and it prevents your queries from being tracked, modified or surveilled by third-parties. Unlike previous versions of Android, this method also ensures 1.1.1.1 does not need to be configured for each new WiFi network your smartphone joins.
|
||||
|
||||
1. Go to **Settings** > **Network & internet**.
|
||||
2. Select **Advanced** > **Private DNS**.
|
||||
3. Select the **Private DNS provider hostname** option.
|
||||
4. Enter `one.one.one.one` or `1dot1dot1dot1.cloudflare-dns.com` and press **Save**.
|
||||
5. Visit [1.1.1.1/help](https://1.1.1.1/help) to verify DNS over TLS is enabled.
|
||||
|
||||
### Previous Android versions
|
||||
|
||||
1. Open **Settings** > **Wi-Fi**.
|
||||
|
||||
2. Press down and hold on the name of the network you are currently connected to.
|
||||
|
||||
3. Click **Modify Network**.
|
||||
|
||||
4. Select the check box **Show Advanced Options**.
|
||||
|
||||
5. Change the IP Settings to **Static**.
|
||||
|
||||
6. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
|
||||
7. Remove any DNS addresses that may be already listed and in their place add:
|
||||
|
||||
```txt
|
||||
1.1.1.1
|
||||
1.0.0.1
|
||||
2606:4700:4700::1111
|
||||
2606:4700:4700::1001
|
||||
```
|
||||
|
||||
8. Click **Save**. You may need to disconnect from the Wi-Fi and reconnect for the changes to take place.
|
||||
|
||||
9. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
{{<render file="_captive-portals.md">}}
|
||||
26
content/1.1.1.1/setup-1.1.1.1/azure.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
title: Azure
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 - Azure
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 - Azure
|
||||
|
||||
Follow these steps to configure 1.1.1.1:
|
||||
|
||||
1. Log in to your Azure portal.
|
||||
|
||||
2. From the Azure portal side menu, select **Virtual Networks**.
|
||||
|
||||
3. Navigate to the virtual network associated with your virtual machine (VM).
|
||||
|
||||
4. Select **DNS Servers** > **Custom**, and add two entries:
|
||||
|
||||
```txt
|
||||
1.1.1.1
|
||||
1.0.0.1
|
||||
```
|
||||
|
||||
5. Click **Save**.
|
||||
104
content/1.1.1.1/setup-1.1.1.1/gaming-consoles.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
---
|
||||
title: Gaming consoles
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 - Gaming consoles
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 - Gaming consoles
|
||||
|
||||
Follow these steps to configure 1.1.1.1:
|
||||
|
||||
## PS4
|
||||
|
||||
1. Go to **Settings** > **Network** > **Set Up Internet Connection**.
|
||||
|
||||
2. Select **WiFi** or **LAN** depending on your Internet connection.
|
||||
|
||||
3. Select **Custom**.
|
||||
|
||||
4. Set **IP Address Settings** to **Automatic**.
|
||||
|
||||
5. Change **DHCP Host Name** to **Do Not Specify**.
|
||||
|
||||
6. Set **DNS Settings** to **Manual**.
|
||||
|
||||
7. Change **Primary DNS** to: `1.1.1.1`.
|
||||
|
||||
8. Set **Secondary DNS** to: `1.0.0.1`.
|
||||
|
||||
9. If you are able to add more DNS servers, you can add the IPv6 addresses as well:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1111
|
||||
2606:4700:4700::1001
|
||||
```
|
||||
|
||||
10. Set **MTU Settings** to **Automatic**.
|
||||
|
||||
11. Set **Proxy Server** to **Do Not Use**.
|
||||
|
||||
## Xbox One
|
||||
|
||||
1. Open the Network screen by pressing the Xbox button on your controller.
|
||||
|
||||
2. Go to **Settings** > **Network** > **Network Settings**.
|
||||
|
||||
3. Next, go to **Advanced Settings** > **DNS Settings**.
|
||||
|
||||
4. Select **Manual**.
|
||||
|
||||
5. Set **Primary DNS** to: `1.1.1.1`.
|
||||
|
||||
6. Set **Secondary DNS** to: `1.0.0.1`.
|
||||
|
||||
7. If you have the option to add more DNS servers, you can add the IPv6 addresses as well:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1111
|
||||
2606:4700:4700::1001
|
||||
```
|
||||
|
||||
8. When you are done, you will be shown a confirmation screen. Press **B** to save.
|
||||
|
||||
## Nintendo
|
||||
|
||||
The following instructions work on New Nintendo 3DS, New Nintendo 3DS XL, New Nintendo 2DS XL, Nintendo 3DS, Nintendo 3DS XL, and Nintendo 2DS.
|
||||
|
||||
1. Go to the home menu and choose **System Settings** (the wrench icon).
|
||||
|
||||
2. Select **Internet Settings** > **Connection Settings**.
|
||||
|
||||
3. Select your Internet connection and then select **Change Settings**.
|
||||
|
||||
4. Select **Change DNS**.
|
||||
|
||||
5. Set **Auto-Obtain DNS** to **No**.
|
||||
|
||||
6. Click **Detailed Setup**.
|
||||
|
||||
7. Set **Primary DNS** to: `1.1.1.1`.
|
||||
|
||||
8. Set **Secondary DNS** to: `1.0.0.1`.
|
||||
|
||||
9. If you are able to add more DNS servers, you can add the IPv6 addresses as well:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1111
|
||||
2606:4700:4700::1001
|
||||
```
|
||||
|
||||
10. Click **Save**.
|
||||
|
||||
11. Click **OK**.
|
||||
|
||||
## Nintendo Switch
|
||||
|
||||
1. Press the home button and select **System Settings** (the symbol that looks like a sun).
|
||||
2. Scroll down and select **Internet** > **Internet Settings**.
|
||||
3. Select your Internet connection and then select **Change Settings**.
|
||||
4. Click **DNS Settings** > **Manual**.
|
||||
5. Set **Primary DNS** to: `1.1.1.1`.
|
||||
6. Change **Secondary DNS** to: `1.0.0.1`.
|
||||
7. Press **Save** > **OK**.
|
||||
38
content/1.1.1.1/setup-1.1.1.1/google-cloud.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
title: Google Cloud
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 - Google Cloud
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 - Google Cloud
|
||||
|
||||
Google Cloud supports configuring [outbound server policy](https://cloud.google.com/dns/docs/server-policies-overview#dns-server-policy-out) within Cloud DNS. Policies are applied per Virtual Private Cloud (VPC) network, and will affect all resources within that VPC network, including any existing virtual machines.
|
||||
|
||||
{{<Aside type="note">}}
|
||||
|
||||
If you are using [Cloudflare Zero Trust](/cloudflare-one/), you can choose assigned [locations](/cloudflare-one/connections/connect-networks/locations) to apply custom [DNS policies](/cloudflare-one/policies/filtering/dns-policies-builder) via Gateway.
|
||||
|
||||
{{</Aside>}}
|
||||
|
||||
To configure 1.1.1.1 for your Google Cloud VPC network(s):
|
||||
|
||||
1. Open the [Google Cloud Console](https://console.cloud.google.com).
|
||||
|
||||
2. Navigate to **Network Services** > **Cloud DNS** and click [**DNS Server Policies**](https://console.cloud.google.com/net-services/dns/policies).
|
||||
|
||||
3. Click **Create Policy**.
|
||||
|
||||
4. Provide a name for your Policy (such as `cloudflare-1-1-1-1`) and select associated VPC network or networks.
|
||||
|
||||
5. Under **Alternate DNS servers**, click **Add Item** and type:
|
||||
|
||||
```txt
|
||||
1.1.1.1
|
||||
1.0.0.1
|
||||
```
|
||||
|
||||
6. Click **Create**.
|
||||
|
||||
DNS requests within the configured VPC network(s) will now use 1.1.1.1.
|
||||
66
content/1.1.1.1/setup-1.1.1.1/ios.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
title: iOS
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 - iOS
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 - iOS
|
||||
|
||||
[1.1.1.1: Faster Internet](https://apps.apple.com/us/app/1-1-1-1-faster-internet/id1423538627) is the preferred method of setting up 1.1.1.1 DNS resolver in iOS devices. It allows you to automatically configure your phone to use 1.1.1.1 on any network you connect to, and solves iOS inability of using an alternative DNS resolver in cellular connections.
|
||||
|
||||
The app also allows you to enable encryption for DNS queries or enable [WARP mode](/warp-client/), which keeps all your HTTP traffic private and secure, including your DNS queries to 1.1.1.1.
|
||||
|
||||
You can select between these two options in 1.1.1.1: Faster Internet's settings. By default, 1.1.1.1:Faster Internet is configured to WARP mode.
|
||||
|
||||
## Set up 1.1.1.1: Faster Internet
|
||||
|
||||
1. Download [1.1.1.1: Faster Internet from the App Store](https://apps.apple.com/us/app/1-1-1-1-faster-internet/id1423538627) for free.
|
||||
2. Launch 1.1.1.1: Faster Internet and accept the Terms of Service.
|
||||
3. Install the VPN profile that allows your phone to connect securely to 1.1.1.1.
|
||||
4. Toggle the **WARP** button to **Connected**.
|
||||
5. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
Your connection to the Internet and your DNS queries are now protected. Alternatively, you may want to only encrypt your DNS queries and leave the remaining traffic unencrypted. If this is the case:
|
||||
|
||||
1. Open 1.1.1.1: Faster Internet.
|
||||
2. Toggle the WARP button and choose **Switch to DNS only mode**. If the WARP toggle is disconnected, tap the **menu button**.
|
||||
3. You will see two options: 1.1.1.1 and WARP. Select **1.1.1.1** > **Done**.
|
||||
|
||||
You are now using encryption only for your DNS queries. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
## Configure 1.1.1.1 manually
|
||||
|
||||
{{<Aside type="note">}}
|
||||
|
||||
If you configure 1.1.1.1 manually, you will have to do it for every WiFi network your device connects to. This method does not work for cellular connections.
|
||||
|
||||
{{</Aside>}}
|
||||
|
||||
1. Go to **Settings** > **Wi-Fi**.
|
||||
|
||||
2. Select the **'i'** icon next to the WiFi network you are connected to.
|
||||
|
||||
3. Scroll down until you see the section called **Configure DNS**.
|
||||
|
||||
4. Change the configuration from **Automatic** to **Manual**.
|
||||
|
||||
5. Select **Add Server**.
|
||||
|
||||
6. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
|
||||
7. Remove any DNS addresses that may be already listed and in their place add:
|
||||
|
||||
```txt
|
||||
1.1.1.1
|
||||
1.0.0.1
|
||||
2606:4700:4700::1111
|
||||
2606:4700:4700::1001
|
||||
```
|
||||
|
||||
8. Select **Save**.
|
||||
|
||||
9. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
{{<render file="_captive-portals.md">}}
|
||||
45
content/1.1.1.1/setup-1.1.1.1/linux.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
title: Linux
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 - Linux
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 - Linux
|
||||
|
||||
Take note of any DNS addresses you might have set up, and save them in a safe place in case you need to use them later.
|
||||
|
||||
## Ubuntu
|
||||
|
||||
1. Go to **Show Applications** > **Settings** > **Network**.
|
||||
|
||||
2. Select the adapter you want to configure - like your Ethernet adapter or Wi-Fi card - and click the **settings** button.
|
||||
|
||||
3. Click the **IPv4** tab.
|
||||
|
||||
4. In the **DNS** section, disable the **Automatic** toggle.
|
||||
|
||||
5. Change the DNS servers to:
|
||||
|
||||
```txt
|
||||
1.1.1.1
|
||||
1.0.0.1
|
||||
```
|
||||
|
||||
6. Click the **IPv6** tab.
|
||||
|
||||
7. In the **DNS** section, disable the **Automatic** toggle.
|
||||
|
||||
8. Change the DNS servers to:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1111
|
||||
2606:4700:4700::1001
|
||||
```
|
||||
|
||||
9. Click **Apply**.
|
||||
|
||||
10. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
{{<render file="_captive-portals.md">}}
|
||||
53
content/1.1.1.1/setup-1.1.1.1/macos.md
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
title: macOS
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 - macOS
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 - macOS
|
||||
|
||||
Follow these steps to configure 1.1.1.1:
|
||||
|
||||
## IPv4
|
||||
|
||||
1. Go to **System Preferences**. You can find it by pressing <kbd>Command</kbd> + <kbd>Space</kbd> on your keyboard and typing `System Preferences`.
|
||||
|
||||
2. Click on the **Network** icon > **Advanced**.
|
||||
|
||||
3. Select the **DNS** tab. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
|
||||
4. Remove any DNS addresses that may be already listed and in their place add:
|
||||
|
||||
```txt
|
||||
1.1.1.1
|
||||
1.0.0.1
|
||||
```
|
||||
|
||||
5. Click **OK** > **Apply**.
|
||||
|
||||
6. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
## IPv6
|
||||
|
||||
1. Go to **System Preferences**. You can find it by pressing <kbd>Command</kbd> + <kbd>Space</kbd> on your keyboard and typing `System Preferences`.
|
||||
|
||||
2. Click on the **Network** icon > **Advanced**.
|
||||
|
||||
3. Select the **DNS** tab. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
|
||||
4. Remove any DNS addresses that may be already listed and in their place add:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1111
|
||||
2606:4700:4700::1001
|
||||
```
|
||||
|
||||
5. Click **OK** > **Apply**.
|
||||
|
||||
6. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
{{<render file="_captive-portals.md">}}
|
||||
|
||||
{{<render file="_encrypted.md">}}
|
||||
50
content/1.1.1.1/setup-1.1.1.1/router.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
title: Router
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 - Router
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 - Router
|
||||
|
||||
Follow these steps to configure 1.1.1.1:
|
||||
|
||||
1. Go to the **IP address** used to access your router's admin console in your browser.
|
||||
|
||||
- Linksys and Asus routers typically use `http://192.168.1.1` or `http://router.asus.com` (for ASUS).
|
||||
- Netgear routers typically use `http://192.168.1.1` or `http://routerlogin.net`.
|
||||
- D-Link routers typically use `http://192.168.0.1`.
|
||||
- Ubiquiti routers typically use `http://unifi.ubnt.com`.
|
||||
|
||||
2. Enter the router credentials. For consumer routers, the default credentials for the admin console are often found under or behind the device.
|
||||
|
||||
3. In the admin console, find the place where **DNS settings** are set. This may be contained within categories such as **WAN** and **IPv6** (Asus Routers) or **Internet** (Netgear Routers). Consult your router's documentation for details.
|
||||
|
||||
4. Take note of any DNS addresses that are currently set and save them in a safe place in case you need to use them later.
|
||||
|
||||
5. For **IPv4**, replace the existing addresses with:
|
||||
|
||||
```txt
|
||||
1.1.1.1
|
||||
1.0.0.1
|
||||
```
|
||||
|
||||
6. For **IPv6**, replace the existing addresses with:
|
||||
|
||||
```txt
|
||||
2606:4700:4700::1111
|
||||
2606:4700:4700::1001
|
||||
```
|
||||
|
||||
7. Save the updated settings.
|
||||
|
||||
8. Open a web browser in a device connected to your router and visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
## Using DNS-Over-TLS on OpenWRT
|
||||
|
||||
It is possible to encrypt DNS traffic out from your router using DNS-over-TLS if it is running OpenWRT. For more details, see our blog post on the topic: [Adding DNS-Over-TLS support to OpenWRT (LEDE) with Unbound](https://blog.cloudflare.com/dns-over-tls-for-openwrt/).
|
||||
|
||||
## FRITZ!Box
|
||||
|
||||
Starting with [FRITZ!OS 7.20](https://en.avm.de/press/press-releases/2020/07/fritzos-720-more-performance-convenience-security/), DNS over TLS is supported, see [Configuring different DNS servers in the FRITZ!Box](https://en.avm.de/service/knowledge-base/dok/FRITZ-Box-7590/165_Configuring-different-DNS-servers-in-the-FRITZ-Box/).
|
||||
46
content/1.1.1.1/setup-1.1.1.1/windows.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
title: Windows
|
||||
pcx-content-type: how-to
|
||||
weight: 0
|
||||
meta:
|
||||
title: Set up 1.1.1.1 - Windows
|
||||
---
|
||||
|
||||
# Set up 1.1.1.1 - Windows
|
||||
|
||||
## Windows 10
|
||||
|
||||
1. Click the **Start menu** > **Settings**.
|
||||
2. Select **Network and Internet** > **Change Adapter Options**.
|
||||
3. Right-click on the Ethernet or WiFi network you are connected to and click **Properties**.
|
||||
4. Select **Internet Protocol Version 4**.
|
||||
5. Click **Properties** > **Use the following DNS server addresses**.
|
||||
6. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
7. Remove any DNS addresses that may be already listed.
|
||||
8. Add `1.1.1.1` to the **Preferred DNS server** field, and `1.0.0.1` to the **Alternate DNS server** field.
|
||||
9. Click **OK**.
|
||||
10. Select **Internet Protocol Version 6**.
|
||||
11. Select **Properties** > **Use the following DNS server addresses**.
|
||||
12. Take note of any DNS addresses you might have and save them in a safe place in case you need to use them later.
|
||||
13. Remove any DNS addresses that may be already listed.
|
||||
14. Add `2606:4700:4700::1111` to the **Preferred DNS server** field, and `2606:4700:4700::1001` to the **Alternate DNS server** field.
|
||||
15. Click **OK**.
|
||||
16. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
## Windows 11
|
||||
|
||||
1. Click the **Start menu** > **Settings**.
|
||||
2. Select **Network and Internet**.
|
||||
3. Click the adapter you want to configure - like your Ethernet adapter or Wi-Fi card.
|
||||
4. Scroll to **DNS server assignment** and click **Edit**.
|
||||
5. Click the **Automatic (DHCP)** drop-down menu and select **Manual**.
|
||||
6. Click the **IPv4** toggle to turn it on.
|
||||
7. Add `1.1.1.1` to the **Preferred DNS** field, and `1.0.0.1` to the **Alternate DNS** field.
|
||||
8. Click the **IPv6** toggle.
|
||||
9. Add `2606:4700:4700::1111` to the **Preferred DNS** field, and `2606:4700:4700::1001` to the **Alternate DNS** field.
|
||||
10. Click **Save**.
|
||||
11. Visit [1.1.1.1/help](https://1.1.1.1/help) to make sure your system is connected to 1.1.1.1.
|
||||
|
||||
{{<render file="_captive-portals.md">}}
|
||||
|
||||
{{<render file="_encrypted.md">}}
|
||||
|
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
9
content/1.1.1.1/terms-of-use.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
pcx-content-type: reference
|
||||
title: Terms of Use
|
||||
weight: 10
|
||||
---
|
||||
|
||||
# Terms of Use
|
||||
|
||||
By using 1.1.1.1 Public DNS Resolver or 1.1.1.1 for Families, you consent to be bound by the [Cloudflare Website and Online Services Terms of Use](https://www.cloudflare.com/website-terms/).
|
||||
14
content/404.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
title: Not found
|
||||
private: true
|
||||
layout: home
|
||||
url: 404.html
|
||||
---
|
||||
|
||||
{{<center>}}
|
||||
# Not found
|
||||
|
||||
Unfortunately, the page you requested cannot be found.
|
||||
|
||||
[Go home](/)
|
||||
{{</center>}}
|
||||
2
content/_headers
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
https://:project.pages.dev/*
|
||||
X-Robots-Tag: noindex
|
||||
272
content/_index.html
Normal file
18
content/analytics/_index.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
pcx-content-type: overview
|
||||
title: Overview
|
||||
weight: 1
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
Cloudflare visualizes the metadata collected by our products in the Cloudflare dashboard. Refer to [Accessing the data Cloudflare collects](/fundamentals/data-products/accessing-cf-data) for more information about the various types of analytics and where they exist in the dashboard.
|
||||
|
||||
## Cloudflare Web Analytics
|
||||
|
||||
[Cloudflare Web Analytics](/analytics/web-analytics/) provides free, privacy-first analytics for your website without changing your DNS or using Cloudflare’s proxy.
|
||||
|
||||
## GraphQL Analytics API
|
||||
|
||||
With the [GraphQL Analytics API](/analytics/graphql-api/), all of your performance, security, and reliability data is available from one endpoint.
|
||||
And you can select exactly what you need, from one metric for a domain to multiple metrics aggregated for your account.
|
||||