DEV Community

useapi.net
useapi.net

Posted on • Originally published at useapi.net

Discord CDN Proxy

Introduction

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
Enter fullscreen mode Exit fullscreen mode

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

Log in to your Google Cloud account:

gcloud auth login
Enter fullscreen mode Exit fullscreen mode

Create new project:

gcloud projects create discord-cdn-proxy
Enter fullscreen mode Exit fullscreen mode

Select created project:

gcloud config set project discord-cdn-proxy
Enter fullscreen mode Exit fullscreen mode

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

Create App Engine project:

gcloud app create
Enter fullscreen mode Exit fullscreen mode

Create .env.yaml file with following yaml:

env_variables:
  DISCORD_TOKEN: "discord token"
  CHANNELS: "['channel id', 'another channel id', 'channel id etc']"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

Deploy App Engine project with updated configuration:

gcloud app deploy
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

Execute script with npm:

npm run debug
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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']"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

Run local development using .dev.var secrets:

wrangler dev  
Enter fullscreen mode Exit fullscreen mode

Refreshing Discord links using an R2 bucket for caching

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
Enter fullscreen mode Exit fullscreen mode

Uncomment r2_buckets configuration in wrangler.toml file.

Redeploy Worker:

wrangler deploy --keep-vars 
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (6)

Collapse
 
heyeasley profile image
heyeasley 🍓🥭

I have some questions, can a guy build his own CDN ?

Collapse
 
useapi profile image
useapi.net

Sure, why not?
What exactly you're looking to build?

Collapse
 
heyeasley profile image
heyeasley 🍓🥭 • Edited

I want to build such like one worlwide cloud where people can store things like new type of chatbots which will be available on. Is it possible ?

Thread Thread
 
useapi profile image
useapi.net

Of course, your best best would be using Cloudflare R2 storage cloudflare.com/developer-platform/r2/ and Cloudflare Workers developers.cloudflare.com/workers/ for API
Do you have any specifics in mind, like what type of API you're looking to implement for your CDN?

Thread Thread
 
heyeasley profile image
heyeasley 🍓🥭

No, sorry, I would implement it in future. I will think about it next time. Thank you too much.

Collapse
 
heyeasley profile image
heyeasley 🍓🥭

Please, I have an another question. I subscribe to free plan Cloudflare. My website is pending because i don't know where i'll put on servernames cloudflares references. Yesterday I waste 2 hours to find it. Do you know how can I solve issues ? How should I master it ?