| 1 | # Gateway |
| 2 | |
| 3 | An IPFS Gateway acts as a bridge between traditional web browsers and IPFS. |
| 4 | Through the gateway, users can browse files and websites stored in IPFS as if |
| 5 | they were stored in a traditional web server. |
| 6 | |
| 7 | [More about Gateways](https://docs.ipfs.tech/concepts/ipfs-gateway/) and [addressing IPFS on the web](https://docs.ipfs.tech/how-to/address-ipfs-on-web/). |
| 8 | |
| 9 | Kubo's Gateway implementation follows [IPFS Gateway Specifications](https://specs.ipfs.tech/http-gateways/) and is tested with [Gateway Conformance Test Suite](https://github.com/ipfs/gateway-conformance). |
| 10 | |
| 11 | ### Local gateway |
| 12 | |
| 13 | By default, Kubo nodes run |
| 14 | a [path gateway](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#path-gateway) at `http://127.0.0.1:8080/` |
| 15 | and a [subdomain gateway](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#subdomain-gateway) at `http://localhost:8080/`. |
| 16 | |
| 17 | > [!CAUTION] |
| 18 | > **For browsing websites, web apps, and dapps in a browser, use the subdomain |
| 19 | > gateway** (`localhost`). Each content root gets its own |
| 20 | > [web origin](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy), |
| 21 | > isolating localStorage, cookies, and session data between sites. |
| 22 | > |
| 23 | > **For file retrieval, use the path gateway** (`127.0.0.1`). Path gateways are |
| 24 | > suited for downloading files or fetching [verifiable](https://docs.ipfs.tech/reference/http/gateway/#trustless-verifiable-retrieval) |
| 25 | > content, but lack origin isolation (all content shares the same origin). |
| 26 | |
| 27 | Additional listening addresses and gateway behaviors can be set in the [config](#configuration) file. |
| 28 | |
| 29 | ### Public gateways |
| 30 | |
| 31 | IPFS Foundation [provides public gateways](https://docs.ipfs.tech/concepts/public-utilities/) at |
| 32 | `https://ipfs.io` ([path](https://specs.ipfs.tech/http-gateways/path-gateway/)), |
| 33 | `https://dweb.link` ([subdomain](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#subdomain-gateway)), |
| 34 | and `https://trustless-gateway.link` ([trustless](https://specs.ipfs.tech/http-gateways/trustless-gateway/) only). |
| 35 | If you've ever seen a link in the form `https://ipfs.io/ipfs/Qm...`, that's being served from a *public goods* gateway. |
| 36 | |
| 37 | There is a list of third-party public gateways provided by the IPFS community at https://ipfs.github.io/public-gateway-checker/ |
| 38 | |
| 39 | ## Configuration |
| 40 | |
| 41 | The `Gateway.*` configuration options are (briefly) described in the |
| 42 | [config](https://github.com/ipfs/kubo/blob/master/docs/config.md#gateway) |
| 43 | documentation, including a list of common [gateway recipes](https://github.com/ipfs/kubo/blob/master/docs/config.md#gateway-recipes). |
| 44 | |
| 45 | ### Debug |
| 46 | The gateway's log level can be changed with this command: |
| 47 | ``` |
| 48 | > ipfs log level core/server debug |
| 49 | ``` |
| 50 | |
| 51 | ## Running in Production |
| 52 | |
| 53 | When deploying Kubo's gateway in production, be aware of these important considerations: |
| 54 | |
| 55 | <a id="reverse-proxy"></a> |
| 56 | > [!IMPORTANT] |
| 57 | > **Reverse Proxy:** When running Kubo behind a reverse proxy (such as nginx), |
| 58 | > the original `Host` header **must** be forwarded to Kubo for |
| 59 | > [`Gateway.PublicGateways`](config.md#gatewaypublicgateways) to work. |
| 60 | > Kubo uses the `Host` header to match configured hostnames and detect |
| 61 | > subdomain gateway patterns like `{cid}.ipfs.example.org` or DNSLink hostnames. |
| 62 | > |
| 63 | > If the `Host` header is not forwarded correctly, Kubo will not recognize |
| 64 | > the configured gateway hostnames and requests may be handled incorrectly. |
| 65 | > |
| 66 | > If `X-Forwarded-Proto` is not set, redirects over HTTPS will use wrong protocol |
| 67 | > and DNSLink names will not be inlined for subdomain gateways. |
| 68 | > |
| 69 | > Example: minimal nginx configuration for `example.org` |
| 70 | > |
| 71 | > ```nginx |
| 72 | > server { |
| 73 | > listen 80; |
| 74 | > listen [::]:80; |
| 75 | > |
| 76 | > # IMPORTANT: Include wildcard to match subdomain gateway requests. |
| 77 | > # The dot prefix matches both apex domain and all subdomains. |
| 78 | > server_name .example.org; |
| 79 | > |
| 80 | > location / { |
| 81 | > proxy_pass http://127.0.0.1:8080; |
| 82 | > |
| 83 | > # IMPORTANT: Forward the original Host header to Kubo. |
| 84 | > # Without this, PublicGateways configuration will not work. |
| 85 | > proxy_set_header Host $host; |
| 86 | > |
| 87 | > # IMPORTANT: X-Forwarded-Proto is required for correct behavior: |
| 88 | > # - Redirects will use https:// URLs when set to "https" |
| 89 | > # - DNSLink names will be inlined for subdomain gateways |
| 90 | > # (e.g., /ipns/en.wikipedia-on-ipfs.org → en-wikipedia--on--ipfs-org.ipns.example.org) |
| 91 | > proxy_set_header X-Forwarded-Proto $scheme; |
| 92 | > proxy_set_header X-Forwarded-Host $host; |
| 93 | > } |
| 94 | > } |
| 95 | > ``` |
| 96 | > |
| 97 | > Common mistakes to avoid: |
| 98 | > |
| 99 | > - **Missing wildcard in `server_name`:** Using only `server_name example.org;` |
| 100 | > will not match subdomain requests like `{cid}.ipfs.example.org`. Always |
| 101 | > include `*.example.org` or use the dot prefix `.example.org`. |
| 102 | > |
| 103 | > - **Wrong `Host` header value:** Using `proxy_set_header Host $proxy_host;` |
| 104 | > sends the backend's hostname (e.g., `127.0.0.1:8080`) instead of the |
| 105 | > original `Host` header. Always use `$host` or `$http_host`. |
| 106 | > |
| 107 | > - **Missing `Host` header entirely:** If `proxy_set_header Host` is not |
| 108 | > specified, nginx defaults to `$proxy_host`, which breaks gateway routing. |
| 109 | |
| 110 | > [!IMPORTANT] |
| 111 | > **Timeouts:** Configure [`Gateway.RetrievalTimeout`](config.md#gatewayretrievaltimeout) |
| 112 | > to terminate stalled transfers (resets on each data write, catches unresponsive operations), |
| 113 | > and [`Gateway.MaxRequestDuration`](config.md#gatewaymaxrequestduration) as a fallback |
| 114 | > deadline (default: 1 hour, catches cases when other timeouts are misconfigured or fail to fire). |
| 115 | |
| 116 | > [!IMPORTANT] |
| 117 | > **Rate Limiting:** Use [`Gateway.MaxConcurrentRequests`](config.md#gatewaymaxconcurrentrequests) |
| 118 | > to protect against traffic spikes. |
| 119 | |
| 120 | > [!IMPORTANT] |
| 121 | > **CDN/Cloudflare:** If using Cloudflare or other CDNs with |
| 122 | > [deserialized responses](config.md#gatewaydeserializedresponses) enabled, review |
| 123 | > [`Gateway.MaxRangeRequestFileSize`](config.md#gatewaymaxrangerequestfilesize) to avoid |
| 124 | > excess bandwidth billing from range request bugs. Cloudflare users may need additional |
| 125 | > protection via [Cloudflare Snippets](https://github.com/ipfs/boxo/issues/856#issuecomment-3523944976). |
| 126 | |
| 127 | ## Directories |
| 128 | |
| 129 | For convenience, the gateway (mostly) acts like a normal web-server when serving |
| 130 | a directory: |
| 131 | |
| 132 | 1. If the directory contains an `index.html` file: |
| 133 | 1. If the path does not end in a `/`, append a `/` and redirect. This helps |
| 134 | avoid serving duplicate content from different paths.<sup>†</sup> |
| 135 | 2. Otherwise, serve the `index.html` file. |
| 136 | 2. Dynamically build and serve a listing of the contents of the directory. |
| 137 | |
| 138 | <sub><sup>†</sup>This redirect is skipped if the query string contains a |
| 139 | `go-get=1` parameter. See [PR#3963](https://github.com/ipfs/kubo/pull/3963) |
| 140 | for details</sub> |
| 141 | |
| 142 | ## Static Websites |
| 143 | |
| 144 | You can use an IPFS gateway to serve static websites at a custom domain using |
| 145 | [DNSLink](https://docs.ipfs.tech/concepts/glossary/#dnslink). See [Example: IPFS |
| 146 | Gateway](https://dnslink.dev/#example-ipfs-gateway) for instructions. |
| 147 | |
| 148 | ## Filenames |
| 149 | |
| 150 | When downloading files, browsers will usually guess a file's filename by looking |
| 151 | at the last component of the path. Unfortunately, when linking *directly* to a |
| 152 | file (with no containing directory), the final component is just a CID |
| 153 | (`bafy..` or `Qm...`). This isn't exactly user-friendly. |
| 154 | |
| 155 | To work around this issue, you can add a `filename=some_filename` parameter to |
| 156 | your query string to explicitly specify the filename. For example: |
| 157 | |
| 158 | > https://ipfs.io/ipfs/QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG?filename=hello_world.txt |
| 159 | |
| 160 | When you try to save above page, you browser will use passed `filename` instead of a CID. |
| 161 | |
| 162 | ## Downloads |
| 163 | |
| 164 | It is possible to skip browser rendering of supported filetypes (plain text, |
| 165 | images, audio, video, PDF) and trigger immediate "save as" dialog by appending |
| 166 | `&download=true`: |
| 167 | |
| 168 | > https://ipfs.io/ipfs/QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG?filename=hello_world.txt&download=true |
| 169 | |
| 170 | ## Response Format |
| 171 | |
| 172 | An explicit response format can be requested using `?format=raw|car|..` URL parameter, |
| 173 | or by sending `Accept: application/vnd.ipld.{format}` HTTP header with one of supported content types. |
| 174 | |
| 175 | ## Content-Types |
| 176 | |
| 177 | Majority of resources can be retrieved trustlessly by requesting specific content type via `Accept` header or `?format=raw|car|ipns-record` URL query parameter. |
| 178 | |
| 179 | See [trustless gateway specification](https://specs.ipfs.tech/http-gateways/trustless-gateway/) |
| 180 | and [verifiable retrieval documentation](https://docs.ipfs.tech/reference/http/gateway/#trustless-verifiable-retrieval) for more details. |
| 181 | |
| 182 | ### `application/vnd.ipld.raw` |
| 183 | |
| 184 | Returns a byte array for a single `raw` block. |
| 185 | |
| 186 | Sending such requests for `/ipfs/{cid}` allows for efficient fetch of blocks with data |
| 187 | encoded in custom format, without the need for deserialization and traversal on the gateway. |
| 188 | |
| 189 | This is equivalent of `ipfs block get`. |
| 190 | |
| 191 | ### `application/vnd.ipld.car` |
| 192 | |
| 193 | Returns a [CAR](https://ipld.io/specs/transport/car/) stream for a DAG or a subset of it. |
| 194 | |
| 195 | The `dag-scope` parameter controls which blocks are included: `all` (default, entire DAG), |
| 196 | `entity` (logical unit like a file), or `block` (single block). For [UnixFS](https://specs.ipfs.tech/unixfs/) files, |
| 197 | `entity-bytes` enables byte range requests. See [IPIP-402](https://specs.ipfs.tech/ipips/ipip-0402/) |
| 198 | for details. |
| 199 | |
| 200 | This is a rough equivalent of `ipfs dag export`. |
| 201 | |
| 202 | ### `application/vnd.ipfs.ipns-record` |
| 203 | |
| 204 | Only works on `/ipns/{ipns-name}` content paths that use cryptographically signed [IPNS Records](https://specs.ipfs.tech/ipns/ipns-record/). |
| 205 | |
| 206 | Returns [IPNS Record in Protobuf Serialization Format](https://specs.ipfs.tech/ipns/ipns-record/#record-serialization-format) |
| 207 | which can be verified on end client, without trusting gateway. |