{"id":29143935,"url":"https://github.com/useapi/discord-cdn-proxy","last_synced_at":"2025-06-30T20:39:48.166Z","repository":{"id":301481353,"uuid":"799683017","full_name":"useapi/discord-cdn-proxy","owner":"useapi","description":"Discord CDN Proxy","archived":false,"fork":false,"pushed_at":"2025-04-29T02:24:21.000Z","size":78,"stargazers_count":35,"open_issues_count":0,"forks_count":7,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-27T05:07:02.237Z","etag":null,"topics":["app","cdn","cloudflare","cloudflare-worker","cloudflare-workers","discord","engine","express","free","free-tier","google","google-app-engine","google-appengine","midjourney","nodejs","pika","proxy"],"latest_commit_sha":null,"homepage":"https://useapi.net","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/useapi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-05-12T21:17:10.000Z","updated_at":"2025-06-23T18:06:19.000Z","dependencies_parsed_at":"2025-06-27T05:07:05.084Z","dependency_job_id":"fbfe4e83-1548-4bfc-a6fc-c5a3342855de","html_url":"https://github.com/useapi/discord-cdn-proxy","commit_stats":null,"previous_names":["useapi/discord-cdn-proxy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/useapi/discord-cdn-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/useapi%2Fdiscord-cdn-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/useapi%2Fdiscord-cdn-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/useapi%2Fdiscord-cdn-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/useapi%2Fdiscord-cdn-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/useapi","download_url":"https://codeload.github.com/useapi/discord-cdn-proxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/useapi%2Fdiscord-cdn-proxy/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262847782,"owners_count":23374086,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["app","cdn","cloudflare","cloudflare-worker","cloudflare-workers","discord","engine","express","free","free-tier","google","google-app-engine","google-appengine","midjourney","nodejs","pika","proxy"],"created_at":"2025-06-30T20:39:45.662Z","updated_at":"2025-06-30T20:39:48.143Z","avatar_url":"https://github.com/useapi.png","language":"TypeScript","readme":"# Discord CDN Proxy\n\nStarting December 2023 all Discord CDN attachment links have following format:  \n`https://cdn.discordapp.com/attachments/channel/message/filename.ext?ex=EXPIRES\u0026is=ISSUED\u0026hm=CODE`  \nQuery parameters values `EXPIRES` and `ISSUED` are timestamps in [unix/epoch hex format](https://www.epochconverter.io/hex-timestamp-converter), `CODE` is encoded checksum used to verify `EXPIRES` and `ISSUED` values.  \nAttempt 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](https://cdn.discordapp.com/attachments/1239264794394234985/1239266735992078447/vault_boy.png).  \nIn practical terms this means that you can no longer link attachments from Discord on your website, share them on Reddit, Facebook.  \n\nThis article provides you with effective solution to continue sharing your Discord CDN content publicly without incurring any costs.  \n\nThe Discord CND proxy especially handy for users of [Midjourney API](https://useapi.net/docs/api-v2), [Pika API](https://useapi.net/docs/api-pika-v1) or [InsightFaceSwap API](https://useapi.net/docs/api-faceswap-v1).\n\nOnce 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.   \nThese links can be shared publicly, published on your website, etc.  \nThe proxy will refresh the links provided after the `?` and redirect the browser to the refreshed Discord CDN link.  \nYou can include original Discord attachment link query parameters as well `?ex=EXPIRES\u0026is=ISSUED\u0026hm=CODE`, the proxy will check if the link has expired, and may return the original URL immediately if it is not expired.  \n\nWhen responding with [HTTP 302](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302) the proxy will set response headers [Expires](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires) with link expiration time.  \nCustom response header `x-discord-cdn-proxy` will be set to one of following values:\n* `original` - provided link query parameters `?ex=EXPIRES\u0026is=ISSUED\u0026hm=CODE` indicate that link is still \"fresh\"\n* `refreshed` - call to `https://discord.com/api/v9/attachments/refresh-urls` Discord API was made to retrieve refreshed link\n* `memory` - refreshed link returned from the memory cache\n* `bucket` - refreshed link returned from the R2 bucket cache (optional for Cloudflare Worker deployment)\n\n[Diagram](https://useapi.net/assets/images/articles/discord-cdn-proxy.svg)  \n![](https://useapi.net/assets/images/articles/discord-cdn-proxy.svg)\n\nOriginal Discord CDN link [open](https://cdn.discordapp.com/attachments/1239264794394234985/1239266735992078447/vault_boy.png?ex=66424c96\u0026is=6640fb16\u0026hm=0b3d3210b4ea0916d5c8c0b2d998a4f4b64f5b95b79cdb9b58ff96b8287dace4\u0026) (`404: This content is no longer available.`)  \nDiscord CDN link using proxy [open](https://demo.useapi.net/discord-cdn-proxy/?https://cdn.discordapp.com/attachments/1239264794394234985/1239266735992078447/vault_boy.png?ex=66424c96\u0026is=6640fb16\u0026hm=0b3d3210b4ea0916d5c8c0b2d998a4f4b64f5b95b79cdb9b58ff96b8287dace4\u0026)   \nDiscord CDN link using proxy (without query parameters) [open](https://demo.useapi.net/discord-cdn-proxy/?https://cdn.discordapp.com/attachments/1239264794394234985/1239266735992078447/vault_boy.png)  \n\nTwo deployment options covered in the article: \n- Google App Engine [instructions](#deploy-google-app-engine).    \n  F1 instance is free to run 24/7/365 [link](https://cloud.google.com/appengine/docs/standard/quotas#Instances).    \n  Google **asks** for a credit card or other payment method when you sign up for the Free Trial/Free Tier [link](https://cloud.google.com/free/docs/free-cloud-features#why-credit-card).\n- Cloudflare Worker [instructions](#deploy-cloudflare-worker).  \n  100K requests per day are included in the free tier account [link](https://developers.cloudflare.com/workers/platform/pricing/).  \n  Cloudflare **does not** require the entering of payment information.    \n\nYou can choose either option based on your preferences.  \n\nThe [source code](https://github.com/useapi/discord-cdn-proxy/blob/main/google-app-engine/server.js) for Google App Engine is a standard Node.js Express server.  \nYou can deploy it in any compatible environment, see the instructions below:  \n* [Vercel](https://vercel.com/guides/using-express-with-vercel)\n* [Heroku](https://devcenter.heroku.com/articles/deploying-nodejs)\n* [Glitch](https://glitch.com/~hello-express)\n* [Microsoft Azure](https://learn.microsoft.com/en-us/azure/cloud-services/cloud-services-nodejs-develop-deploy-express-app)\n* [Amazon AWS](https://docs.aws.amazon.com/amplify/latest/userguide/deploy-express-server.html)\n* [Oracle Cloud](https://docs.oracle.com/en-us/iaas/developer-tutorials/tutorials/node-on-ol/01oci-ol-node-summary.htm)\n\n## Deploy Google App Engine\n\nAssuming you have Google Cloud [account](https://cloud.google.com/) and installed [gcloud CLI](https://cloud.google.com/sdk/docs/install).\n\nClone git repository [discord-cdn-proxy](https://github.com/useapi/discord-cdn-proxy?tab=readme-ov-file).  \nNavigate to `./google-app-engine` folder and install npm packages:\n```bash\nnpm install\n```\n\nYou can follow along the official Google App Engine deployment steps for [Node.js](https://cloud.google.com/appengine/docs/standard).\n\nLog in to your Google Cloud account:\n```bash\ngcloud auth login\n```\n\nCreate new project:\n```bash\ngcloud projects create discord-cdn-proxy\n```\n\nSelect created project:\n```bash\ngcloud config set project discord-cdn-proxy\n```\n\nFind created project on your Google Cloud Dashboard and link billing account to the project.  \n\nCreate App Engine project:\n```bash\ngcloud app create\n```\n\nCreate `.env.yaml` file with following yaml: \n```yaml\nenv_variables:\n  DISCORD_TOKEN: \"discord token\"\n  CHANNELS: \"['channel id', 'another channel id', 'channel id etc']\"\n```\nHow to [extract discord token](https://useapi.net/docs/start-here/setup-midjourney#obtain-discord-token).  \nOptional array `CHANNELS` defines which Discord channels should be proxied.  \nYou can remove it but it is strongly not recommended for public proxies.  \n\nDeploy App Engine project:\n```bash\ngcloud app deploy\n```\nYou may have to run the above command a few times, as it often fails on the first run.\n\nNotice the name of the deployed service, which will look like:\n`Deployed service [default] to [https://discord-cdn-proxy.it.r.appspot.com]` \n\nUpdate `.env.yaml` file and add DISCORD_CDN_PROXY_URL with value from deployed service: \n```yaml\nenv_variables:\n  DISCORD_TOKEN: \"discord token\"\n  CHANNELS: \"['channel id', 'another channel id', 'channel id etc']\"\n  DISCORD_CDN_PROXY_URL: \"https://discord-cdn-proxy.it.r.appspot.com\"\n```\n\nDeploy App Engine project with updated configuration:\n```bash\ngcloud app deploy\n```\n\nNow you can test deployed proxy.  \nExample (adjust to include actual values): `https://discord-cdn-proxy.it.r.appspot.com/?https://cdn.discordapp.com/attachments/channel/message/filename.ext`    \n\n### Debugging locally\n\nUpdate DISCORD_TOKEN value in your `package.json` file: \n```json\n{\n  \"name\": \"discord-cdn-proxy\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Discord CDN proxy\",\n  \"main\": \"server.js\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"start\": \"node server.js\",\n    \"debug\": \"DISCORD_TOKEN='discord token' DISCORD_CDN_PROXY_URL='http://localhost:8090/' node server.js\"\n  },\n  \"author\": \"useapi.net\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"express\": \"^4.19.2\"\n  }\n}\n```\n\nExecute script with npm:\n```bash\nnpm run debug\n```\n\n## Deploy Cloudflare Worker\n\nAssuming you have free Cloudflare account [setup](https://developers.cloudflare.com/fundamentals/setup/account/create-account/) completed  and installed [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/).\n\nClone git repository [discord-cdn-proxy](https://github.com/useapi/discord-cdn-proxy?tab=readme-ov-file).  \nNavigate to `./cloudflare-web-worker` folder and install npm packages:\n```bash\nnpm install\n```\n\nIf you are familiar with Cloudflare Workers, you can adjust the deployment configuration in the `wrangler.toml` file.   \nYou can fine-tune it later at any time once you have acquired some initial experience.  \n\nDeploy Worker: \n```bash\nwrangler deploy --keep-vars \n```\n\nNotice deployment url which will look like `https://discord-cdn-proxy.your-user-name.workers.dev`    \nYou can use that url to test by adding Discord link at the end after  `?`  \nExample: `https://your-discord-cdn-proxy-url/?https://cdn.discordapp.com/attachments/channel/message/filename.ext`    \n\nCreate `.secrets` file with following JSON: \n```json\n{\n    \"DISCORD_TOKEN\": \"discord token\",\n    \"CHANNELS\": \"['channel id', 'another channel id', 'channel id etc']\"\n}\n```\nHow to [extract discord token](https://useapi.net/docs/start-here/setup-midjourney#obtain-discord-token).  \nOptional array `CHANNELS` defines which Discord channels should be proxied.  \nYou can remove it but it is strongly not recommended for public proxies.  \n\nDeploy secrets from local file `.secrets`: \n```bash\nwrangler secret:bulk .secrets\n```\n\nNow you can test deployed proxy.  \nExample (adjust to include actual values): `https://your-discord-cdn-proxy-url/?https://cdn.discordapp.com/attachments/channel/message/filename.ext`  \n\n### Debugging locally\n\nCreate `.dev.vars` file with following text: \n```javascript\nDISCORD_TOKEN=\"discord token\"\nCHANNELS=[\"channel id\", \"another channel id\", \"channel id etc\"]\n```\n\nRun local development using `.dev.var` secrets:\n```bash\nwrangler dev  \n```\n\n### Refreshing Discord links using an R2 bucket for caching\n\nThis allows you to store refreshed Discord links in a Cloudflare R2 bucket to minimize the number of calls to the Discord API. \n\nTo create an R2 bucket, execute:\n```bash\nwrangler r2 bucket create discord-cdn-proxy-cache\nwrangler r2 bucket list\n```\n\nUncomment `r2_buckets` configuration in `wrangler.toml` file.\n\nRedeploy Worker:\n```bash\nwrangler deploy --keep-vars \n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuseapi%2Fdiscord-cdn-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuseapi%2Fdiscord-cdn-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuseapi%2Fdiscord-cdn-proxy/lists"}