Discord CDN Proxy

5 min read • May 14, 2024 (August 23, 2024)

Table of contents

  1. Host your images and videos on Discord CDN
  2. Create a Proxy for Discord CDN
  3. Deploy Google App Engine
    1. Debugging locally
  4. Deploy Cloudflare Worker
    1. Debugging locally
    2. Refreshing Discord links using an R2 bucket for caching
  5. Conclusion

Host your images and videos on Discord CDN

Suppose you want to take advantage of the free Discord CDN to host your images or videos. With the simple script below, you can upload your assets to a desired Discord channel:

curl -X POST "https://discord.com/api/v10/channels/<Discord channel>/messages" \
-H "Authorization: <Discord token>" \
-F 'payload_json={"content":"Here is your file!","attachments":[{"id":0,"filename":"<file name>"}]}' \
-F 'files[0]=@<path to file name>'

Example:

curl -X POST "https://discord.com/api/v10/channels/123456789/messages" \
-H "Authorization: ABc.your.discord.token.xYZ" \
-F 'payload_json={"content":"Here is your file!","attachments":[{"id":0,"filename":"source.jpg"}]}' \
-F 'files[0]=@./source.jpg'

Please refer to our guide on how to obtain your Discord token and set up a private channel. Omit the Midjourney setup steps if you do not plan to use it.

Response JSON will contain attachments[0].url with Discord CDN attachment link.

Create a Proxy for Discord CDN

Starting December 2023 all Discord CDN attachment links have following format:
https://cdn.discordapp.com/attachments/channel/message/filename.ext?ex=EXPIRES&is=ISSUED&hm=CODE
Query parameters values EXPIRES and ISSUED are timestamps in unix/epoch hex format, CODE is encoded checksum used to verify EXPIRES and ISSUED values.
Attempt to retrieve Discord CDN attachments URL without above query parameters or with EXPIRES past current time will result in 404 This content is no longer available. response, see example.
In practical terms this means that you can no longer link attachments from Discord on your website, share them on Reddit, Facebook.

This article provides you with effective solution to continue sharing your Discord CDN content publicly without incurring any costs.

The Discord CND proxy especially handy for users of Midjourney API, Pika API or InsightFaceSwap API.

Once your public proxy deployed you can use public image links using https://your-discord-cdn-proxy-url/?https://cdn.discordapp.com/attachments/channel/message/filename.ext format.
These links can be shared publicly, published on your website, etc.
The proxy will refresh the links provided after the ? and redirect the browser to the refreshed Discord CDN link.
You can include original Discord attachment link query parameters as well ?ex=EXPIRES&is=ISSUED&hm=CODE, the proxy will check if the link has expired, and may return the original URL immediately if it is not expired.

When responding with HTTP 302 the proxy will set response headers Expires with link expiration time.
Custom response header x-discord-cdn-proxy will be set to one of following values:

  • original - provided link query parameters ?ex=EXPIRES&is=ISSUED&hm=CODE indicate that link is still “fresh”
  • refreshed - call to https://discord.com/api/v9/attachments/refresh-urls Discord API was made to retrieve refreshed link
  • memory - refreshed link returned from the memory cache
  • bucket - refreshed link returned from the R2 bucket cache (optional for Cloudflare Worker deployment)

Diagram

Original Discord CDN link open (404: This content is no longer available.)
Discord CDN link using proxy open
Discord CDN link using proxy (without query parameters) open

Two deployment options covered in the article:

  • Google App Engine instructions.
    F1 instance is free to run 24/7/365 link.
    Google asks for a credit card or other payment method when you sign up for the Free Trial/Free Tier link.
  • Cloudflare Worker instructions.
    100K requests per day are included in the free tier account link.
    Cloudflare does not require the entering of payment information.

You can choose either option based on your preferences.

The source code for Google App Engine is a standard Node.js Express server.
You can deploy it in any compatible environment, see the instructions below:

Deploy Google App Engine

Assuming you have Google Cloud account and installed gcloud CLI.

Clone git repository discord-cdn-proxy.
Navigate to ./google-app-engine folder and install npm packages:

npm install

You can follow along the official Google App Engine deployment steps for Node.js.

Log in to your Google Cloud account:

gcloud auth login

Create new project:

gcloud projects create discord-cdn-proxy

Select created project:

gcloud config set project discord-cdn-proxy

Find created project on your Google Cloud Dashboard and link billing account to the project.

Create App Engine project:

gcloud app create

Create .env.yaml file with following yaml:

env_variables:
  DISCORD_TOKEN: "discord token"
  CHANNELS: "['channel id', 'another channel id', 'channel id etc']"

How to extract discord token.
Optional array CHANNELS defines which Discord channels should be proxied.
You can remove it but it is strongly not recommended for public proxies.

Deploy App Engine project:

gcloud app deploy

You may have to run the above command a few times, as it often fails on the first run.

Notice the name of the deployed service, which will look like: Deployed service [default] to [https://discord-cdn-proxy.it.r.appspot.com]

Update .env.yaml file and add DISCORD_CDN_PROXY_URL with value from deployed service:

env_variables:
  DISCORD_TOKEN: "discord token"
  CHANNELS: "['channel id', 'another channel id', 'channel id etc']"
  DISCORD_CDN_PROXY_URL: "https://discord-cdn-proxy.it.r.appspot.com"

Deploy App Engine project with updated configuration:

gcloud app deploy

Now you can test deployed proxy.
Example (adjust to include actual values): https://discord-cdn-proxy.it.r.appspot.com/?https://cdn.discordapp.com/attachments/channel/message/filename.ext

Debugging locally

Update DISCORD_TOKEN value in your package.json file:

{
  "name": "discord-cdn-proxy",
  "version": "1.0.0",
  "description": "Discord CDN proxy",
  "main": "server.js",
  "type": "module",
  "scripts": {
    "start": "node server.js",
    "debug": "DISCORD_TOKEN='discord token' DISCORD_CDN_PROXY_URL='http://localhost:8090/' node server.js"
  },
  "author": "useapi.net",
  "license": "ISC",
  "dependencies": {
    "express": "^4.19.2"
  }
}

Execute script with npm:

npm run debug

Deploy Cloudflare Worker

Assuming you have free Cloudflare account setup completed and installed Wrangler CLI.

Clone git repository discord-cdn-proxy.
Navigate to ./cloudflare-web-worker folder and install npm packages:

npm install

If you are familiar with Cloudflare Workers, you can adjust the deployment configuration in the wrangler.toml file.
You can fine-tune it later at any time once you have acquired some initial experience.

Deploy Worker:

wrangler deploy --keep-vars 

Notice deployment url which will look like https://discord-cdn-proxy.your-user-name.workers.dev
You can use that url to test by adding Discord link at the end after ?
Example: https://your-discord-cdn-proxy-url/?https://cdn.discordapp.com/attachments/channel/message/filename.ext

Create .secrets file with following JSON:

{
    "DISCORD_TOKEN": "discord token",
    "CHANNELS": "['channel id', 'another channel id', 'channel id etc']"
}

How to extract discord token.
Optional array CHANNELS defines which Discord channels should be proxied.
You can remove it but it is strongly not recommended for public proxies.

Deploy secrets from local file .secrets:

wrangler secret:bulk .secrets

Now you can test deployed proxy.
Example (adjust to include actual values): https://your-discord-cdn-proxy-url/?https://cdn.discordapp.com/attachments/channel/message/filename.ext

Debugging locally

Create .dev.vars file with following text:

DISCORD_TOKEN="discord token"
CHANNELS=["channel id", "another channel id", "channel id etc"]

Run local development using .dev.var secrets:

wrangler dev  

This allows you to store refreshed Discord links in a Cloudflare R2 bucket to minimize the number of calls to the Discord API.

To create an R2 bucket, execute:

wrangler r2 bucket create discord-cdn-proxy-cache
wrangler r2 bucket list

Uncomment r2_buckets configuration in wrangler.toml file.

Redeploy Worker:

wrangler deploy --keep-vars 

Conclusion

Visit our Discord Server or Telegram Channel for any support questions and concerns.

We regularly post guides and tutorials on the YouTube Channel.

Check our GitHub repo with code examples.

Cross posted