PHPackages                             nelexa/guzzle-doh-middleware - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. nelexa/guzzle-doh-middleware

ActiveLibrary[HTTP &amp; Networking](/categories/http)

nelexa/guzzle-doh-middleware
============================

A Dns over Https (DoH) middleware for Guzzle &gt;= 6.0

1.0.1(4y ago)1197↓75%MITPHPPHP ^7.1 | ^8.0

Since Mar 4Pushed 4y ago1 watchersCompare

[ Source](https://github.com/Ne-Lexa/guzzle-doh-middleware)[ Packagist](https://packagist.org/packages/nelexa/guzzle-doh-middleware)[ RSS](/packages/nelexa-guzzle-doh-middleware/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (1)Dependencies (9)Versions (4)Used By (0)

 [![nelexa/guzzle-doh-middleware](logo.svg)](logo.svg)guzzle-doh-middleware
=====================

[](#guzzle-doh-middleware)

 **A DNS over HTTPS (DoH) middleware for [Guzzle](https://github.com/guzzle/guzzle).**

[![Latest Stable Version](https://camo.githubusercontent.com/694f67cb9c842e24a0792f189326252756ade98697af111a693bbfcb30b8f0ec/68747470733a2f2f706f7365722e707567782e6f72672f6e656c6578612f67757a7a6c652d646f682d6d6964646c65776172652f76)](https://packagist.org/packages/nelexa/guzzle-doh-middleware)[![PHP Version Require](https://camo.githubusercontent.com/ed1192ac233a646d33deb8e913dbed3a6c4266c7167a91c85cc47cb0ea85a4a0/68747470733a2f2f706f7365722e707567782e6f72672f6e656c6578612f67757a7a6c652d646f682d6d6964646c65776172652f726571756972652f706870)](https://packagist.org/packages/nelexa/guzzle-doh-middleware)[![Tests](https://github.com/Ne-Lexa/guzzle-doh-middleware/actions/workflows/tests.yml/badge.svg)](https://github.com/Ne-Lexa/guzzle-doh-middleware/actions/workflows/tests.yml)[![Analysis](https://github.com/Ne-Lexa/guzzle-doh-middleware/actions/workflows/analysis.yml/badge.svg)](https://github.com/Ne-Lexa/guzzle-doh-middleware/actions/workflows/analysis.yml)[![Build Status](https://camo.githubusercontent.com/601b49c574f29e969bb366a40fa2e3c20162bbbe66f1362e04a6e29758e23ea6/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f4e652d4c6578612f67757a7a6c652d646f682d6d6964646c65776172652f6261646765732f6275696c642e706e673f623d6d61696e)](https://scrutinizer-ci.com/g/Ne-Lexa/guzzle-doh-middleware/build-status/main)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/38fead6d026c4c72ea03e76b5e8e93894a549ad4968926b43e211c8373f8d5c0/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f4e652d4c6578612f67757a7a6c652d646f682d6d6964646c65776172652f6261646765732f7175616c6974792d73636f72652e706e673f623d6d61696e)](https://scrutinizer-ci.com/g/Ne-Lexa/guzzle-doh-middleware/?branch=main)[![Code Coverage](https://camo.githubusercontent.com/55eb524b36b11f1df6b043307412c52e2564300eabf60aa3a9855b0fa489f83e/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f4e652d4c6578612f67757a7a6c652d646f682d6d6964646c65776172652f6261646765732f636f7665726167652e706e673f623d6d61696e)](https://scrutinizer-ci.com/g/Ne-Lexa/guzzle-doh-middleware/?branch=main)[![License](https://camo.githubusercontent.com/9a3d2a37ef8a65bc8f6dc01b03f84d2aafc086871c73aeb3f6b9e5b217ee5ca6/68747470733a2f2f706f7365722e707567782e6f72672f6e656c6578612f67757a7a6c652d646f682d6d6964646c65776172652f6c6963656e7365)](https://packagist.org/packages/nelexa/guzzle-doh-middleware)

Goals
-----

[](#goals)

- Resolving domains, via DoH before sending HTTP requests.
- Bypassing blocked sites, through DNS packet spoofing.
- Support for caching DNS responses, via [PSR-6](https://packagist.org/providers/psr/cache-implementation) and [PSR-16](https://packagist.org/providers/psr/simple-cache-implementation) compatible packages.
- Support for multiple DoH providers.

Install
-------

[](#install)

```
composer require nelexa/guzzle-doh-middleware
```

Usage
-----

[](#usage)

```
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use Nelexa\Doh\DohMiddleware;

// Create default HandlerStack
$stack = HandlerStack::create();

// Add this middleware to the top with `push`
$stack->push(DohMiddleware::create(), 'doh');

// Initialize the client with the handler option
$client = new Client(['handler' => $stack]);
```

### Setup cache

[](#setup-cache)

It is very important to configure caching of DNS requests, so that you do not have to contact a DNS server to resolve domains for every HTTP request.

Install a [PSR-6](https://packagist.org/providers/psr/cache-implementation) or [PSR-16](https://packagist.org/providers/psr/simple-cache-implementation) compatible caching package.

For example, you can install the popular [symfony/cache](https://symfony.com/doc/current/components/cache.html#cache-component-psr6-caching) package.

```
composer require symfony/cache
```

Example init PSR-6 redis cache

```
$cache = new \Symfony\Component\Cache\Adapter\RedisAdapter(
    \Symfony\Component\Cache\Adapter\RedisAdapter::createConnection()
);
```

Example init PSR-16 redis cache

```
$cache = new \Symfony\Component\Cache\Psr16Cache(
    new \Symfony\Component\Cache\Adapter\RedisAdapter(
        \Symfony\Component\Cache\Adapter\RedisAdapter::createConnection()
    )
);
```

You can pass the configured cache as the first argument when creating middleware.
If you don't pass the argument or pass `null`, the cache will only be stored for the lifetime of the PHP process.

```
$stack->push(DohMiddleware::create($cache), 'doh');
```

### Setup DoH Servers

[](#setup-doh-servers)

You can specify which DoH servers to use as a second argument when creating middleware. They will be chosen in random order.

The defaults are [Cloudflare (for Mozilla)](https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/encrypted-dns-browsers/) and [Google](https://developers.google.com/speed/public-dns/docs/doh).

Example:

```
$dohServers = [
    'https://mozilla.cloudflare-dns.com/dns-query',
    'https://dns.google/dns-query',
    'https://doh.cleanbrowsing.org/doh/security-filter',
    \Nelexa\Doh\DohServers::SERVER_ADGUARD_FAMILY,
    'https://doh.opendns.com/dns-query',
];
$stack->push(DohMiddleware::create($cache, $dohServers), 'doh');
```

### Setup Logger &amp; Debug

[](#setup-logger--debug)

You can add the [PSR-3 compatible Logger](https://packagist.org/providers/psr/log-implementation) as a 3rd argument when creating middleware.

```
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('doh');
$logger->pushHandler(new StreamHandler('path/to/doh.log', Logger::DEBUG));

$stack->push(DohMiddleware::create(
    cache: $cache,
    logger: $logger
), 'doh');
```

For debugging and console output of all DoH requests to servers, you can pass `true` as 4th parameter when creating middleware.

```
$stack->push(DohMiddleware::create(
    cache: $cache,
    debug: true,
), 'doh');
```

 Example debug info```
*   Trying 104.16.248.249:443...
* TCP_NODELAY set
* connect to 104.16.248.249 port 443 failed: Connection refused
*   Trying 104.16.249.249:443...
* TCP_NODELAY set
* Connected to mozilla.cloudflare-dns.com (104.16.249.249) port 443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: C=US; ST=California; L=San Francisco; O=Cloudflare, Inc.; CN=cloudflare-dns.com
*  start date: Oct 25 00:00:00 2021 GMT
*  expire date: Oct 25 23:59:59 2022 GMT
*  subjectAltName: host "mozilla.cloudflare-dns.com" matched cert's "*.cloudflare-dns.com"
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS Hybrid ECC SHA384 2020 CA1
*  SSL certificate verify ok.
> GET /dns-query?dns=q80BAAABAAAAAAAACmdvb2dsZW1haWwBbAZnb29nbGUDY29tAAABAAE HTTP/1.1
Host: mozilla.cloudflare-dns.com
Accept: application/dns-udpwireformat, application/dns-message
User-Agent: DoH-Client

* old SSL session ID is stale, removing
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: cloudflare
< Date: Thu, 03 Mar 2022 09:58:15 GMT
< Content-Type: application/dns-message
< Connection: keep-alive
< Access-Control-Allow-Origin: *
< Content-Length: 105
< CF-RAY: 6e6183398ec716f0-DME
<
* Connection #0 to host mozilla.cloudflare-dns.com left intact

```

Request options
---------------

[](#request-options)

You can configure requests created and transmitted by the client using request options.

### Option "doh"

[](#option-doh)

 Summary Set `false` to disable domain resolving, via DoH.

 Types - bool

  Default `true`

 Constant `\Nelexa\Doh\DohMiddleware::OPTION_DOH_ENABLED`

```
// Disable DoH for concrete request
$client->request('GET', 'https://...', [
    'doh' => false,
]);
```

To disable DoH middleware by default, pass `false` for the `doh` option when creating the HTTP client.

```
$stack = HandlerStack::create();
$stack->push(DohMiddleware::create($cache), 'doh');
$client = new Client([
    'handler' => $stack,
    'doh' => false,
]);
```

### Option "doh\_ttl"

[](#option-doh_ttl)

 Summary Forced setting of caching time for resolving results. If the option is not passed or `null` is passed, the caching time from the DNS server is used.

 Types - integer
- \\DateInterval
- null

  Default `null`

 Constant `\Nelexa\Doh\DohMiddleware::OPTION_DOH_TTL`

```
$client->request('GET', 'https://...', [
    'doh_ttl' => \DateInterval::createFromDateString('1 hour'),
]);
```

### Option "doh\_shuffle"

[](#option-doh_shuffle)

 Summary Set `true` to enable [shuffling of ip addresses](https://curl.se/libcurl/c/CURLOPT_DNS_SHUFFLE_ADDRESSES.html) in random order when more than one ip address has been received as a result of domain resolving.

 Types - bool

  Default `false`

 Constant `\Nelexa\Doh\DohMiddleware::OPTION_DOH_SHUFFLE`

```
// Enable shuffle ip addresses
$client->request('GET', 'https://...', [
    'doh_shuffle' => true,
]);
```

To enable ip mixing for all requests by default, pass `true` for the `ttl_shuffle` option when creating the HTTP client.

```
$stack = HandlerStack::create();
$stack->push(DohMiddleware::create($cache), 'doh');
$client = new Client([
    'handler' => $stack,
    'doh_shuffle' => true,
]);
```

Symfony config DI
-----------------

[](#symfony-config-di)

```
# config/services.yaml
parameters:

    doh.servers:
        - 'https://mozilla.cloudflare-dns.com/dns-query',
        - 'https://dns.google/dns-query',
        - 'https://doh.opendns.com/dns-query'

services:

    app.client.doh_middleware:
        factory: Nelexa\Doh\DohMiddleware::create
        class: Nelexa\Doh\DohMiddleware
        arguments:
            - '@cache.app'
            - '%doh.servers%'
            - '@logger'
            - '%kernel.debug%'

    app.client.handler_stack:
        factory: GuzzleHttp\HandlerStack::create
        class: GuzzleHttp\HandlerStack
        calls:
            - [ push, [ '@app.client.doh_middleware' ] ]

    app.client:
        class: GuzzleHttp\Client
        arguments:
            app.client:
            class: GuzzleHttp\Client
            arguments:
                - handler: '@app.client.handler_stack'
                  doh: true
                  # doh_ttl: 3600
                  # doh_shuffle: true

    # Aliases
    GuzzleHttp\Client: '@app.client'
```

Credits
-------

[](#credits)

- [Ne-Lexa](https://github.com/Ne-Lexa)
- [All contributors](https://github.com/Ne-Lexa/guzzle-doh-middleware/graphs/contributors)

Changelog
---------

[](#changelog)

Changes are documented in the [releases page](https://github.com/Ne-Lexa/guzzle-doh-middleware/releases).

License
-------

[](#license)

The MIT License (MIT). Please see [LICENSE](LICENSE) for more information.

###  Health Score

27

—

LowBetter than 49% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity13

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

1530d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/58ee2cf9c1aa935ef472b891a770bb2ce298a231af130f375cfcaa76d2a9a891?d=identicon)[Ne-Lexa](/maintainers/Ne-Lexa)

---

Top Contributors

[![Ne-Lexa](https://avatars.githubusercontent.com/u/17830391?v=4)](https://github.com/Ne-Lexa "Ne-Lexa (19 commits)")

---

Tags

middlewareGuzzlednsdns-over-httpsdoh

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/nelexa-guzzle-doh-middleware/health.svg)

```
[![Health](https://phpackages.com/badges/nelexa-guzzle-doh-middleware/health.svg)](https://phpackages.com/packages/nelexa-guzzle-doh-middleware)
```

###  Alternatives

[kevinrob/guzzle-cache-middleware

A HTTP/1.1 Cache for Guzzle 6. It's a simple Middleware to be added in the HandlerStack. (RFC 7234)

43117.4M104](/packages/kevinrob-guzzle-cache-middleware)[caseyamcl/guzzle_retry_middleware

Guzzle v6+ retry middleware that handles 429/503 status codes and connection timeouts

21610.7M64](/packages/caseyamcl-guzzle-retry-middleware)[rtheunissen/guzzle-log-middleware

Guzzle middleware to log requests and responses

842.3M17](/packages/rtheunissen-guzzle-log-middleware)[api-platform/metadata

API Resource-oriented metadata attributes and factories

223.5M96](/packages/api-platform-metadata)[eljam/guzzle-jwt-middleware

A jwt authentication middleware for guzzle 6

28722.5k3](/packages/eljam-guzzle-jwt-middleware)[rtheunissen/guzzle-rate-limiter

Guzzle 6 middleware used to delay requests dynamically

52177.2k1](/packages/rtheunissen-guzzle-rate-limiter)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
