**TL;DR**: When upgrading from `Bitcoin Core 0.20.1` to `Bitcoin Core 0.21.0`, a downstream application using the HTTP JSON-RPC API started getting HTTP 403 "Forbidden".

Turns out it is because I have `rpcallowip=::/0` in `bitcoin.conf` which used to work but does not anymore.
As a workaround, `rpcallowip=0.0.0.0/0` works.

-----

I run bitcoind in docker container1, and some application using the HTTP JSON-RPC API of bitcoind is in docker container2. They are on the same "docker network".

In `bitcoin.conf` I have:
```
rpcauth=<...>
rpcbind=0.0.0.0:8332
rpcallowip=::/0
```
(bitcoind RPC is not actually exposed to the public internet; it is up to the docker layer and above to ensure this.)

The application in container2 is connecting through HTTP accessing an URL such as `http://user:pass@172.19.1.10:8332/`.

This setup used to work when running `Bitcoin Core 0.20.1` in container1.

It no longer works with `Bitcoin Core 0.21.0`.

-----

If I change my `bitcoin.conf` as below, it starts working again using 0.21:
```
rpcauth=<...>
rpcbind=0.0.0.0:8332
rpcallowip=0.0.0.0/0
```

So `rpcallowip=::/0` used to work but does not anymore; `rpcallowip=0.0.0.0/0` works.

-----

Easy way to test:
`curl --data-binary '{"jsonrpc":"1.0","id":"curltext","method":"getblockchaininfo","params":[]}' -H 'content-type:text/plain;' http://user:pass@172.19.1.10:8332/`
*node.mempool, peerman_opts);
    RegisterValidationInterface(node.peerman.get());
     ***
    if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
        auto result{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))};
        if (!result) {
            return InitError(util::ErrorString(result));
        }
        g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, fReindex);
        node.indexes.emplace_back(g_txindex.get());
    }
    for (const auto& filter_type : g_enabled_filter_types) {
        InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, fReindex);
        node.indexes.emplace_back(GetBlockFilterIndex(filter_type));
    }
    if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
        g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), *cachse, fReindex);
        node.indexes.emplace_back(g_coin_stats_index.get());
    }
     Init indexes
    for (auto index : node.indexes) if (!index->Init()) return false;
     ********************************************************* Step 9: load wallet
    for (const auto& client : node.chain_clients) {
        if (!client->load()) {
            return false;
        }
    }
     ***
     if pruning, perform the initial blockstore prune
     after any wallet rescanning has taken place.