A simple, lightweight, single-origin, self-hosted CDN server with a Discord bot for managing files — all in a single binary.
- Add unlimited domains to organize your CDN
- Organize files into categories within each domain
- Upload and manage files directly from Discord
- Automatic file uploads when mentioning the bot
- Set default values or channel-specific configurations (for automatic file uploads without mentioning the bot)
- List and delete files through Discord commands
- Randomly generates filenames to prevent guessing file URLs
- Static file serving with caching headers
- Support for CORS requests
More aren't planned but feel free to add them yourself.
This project consists of a web server and a Discord bot that work together to provide a simple, domain-based file hosting and CDN system.
The web server runs on port 8080 and serves files through HTTP. It organizes files by domains and categories. When you request a file, the server checks the domain from the host header, finds the category and filename from the URL path, then returns the file with proper headers for caching.
The server supports:
- GET and HEAD requests
- CORS headers for cross-origin requests
- ETag for cache validation
- Long cache times (1 year) for static files
Files are stored in the local filesystem and organized as storage/domain/category/filename.
The Discord bot lets you manage files without using HTTP requests. It connects to your Discord server using a bot token and responds to slash commands and mentions.
You can:
- Upload files to the CDN
- Delete files from the CDN
- List files in a category
- Manage domains and categories
- Set default values for uploads
- Configure channels for automatic uploads
The bot has three upload modes:
- Use the
/uploadslash command to upload a file with specific domain and category - Mention the bot in a message with an attachment to auto-upload (requires defaults or channel config)
- Send files to a channel and bot automatically uploads them (requires channel configuration (use
/set-channel))
| Command | Description | Arguments |
|---|---|---|
/upload |
Upload a file to the CDN | file (required), category (optional), domain (optional) |
/delete |
Delete a file from the CDN | url (required) |
/list |
List all files in a category | domain (required), category (required) |
/default |
Set default domain and category for uploads | domain (required), category (required) |
/set-channel |
Set auto-upload config for channel | domain (required), category (required) |
/view-channel-default |
View the auto-upload settings for channel | none |
/reset-channel |
Remove the auto-upload configuration for channel | none |
/add-domain |
Add a new CDN domain | domain-fqdn (required), display-name (required), folder-name (required) |
/remove-domain |
Remove a CDN domain | domain-name (required) |
/add-category |
Add a new category | category-name (required), folder-name (required) |
/remove-category |
Remove a category | category-name (required) |
This is the actual domain name used in URLs. When someone accesses your CDN, they use this domain in their browser or application. For example, if your domain-fqdn is shadowarcanist.com, the file URL would be https://shadowarcanist.com/images/filename.ext.
This is the internal folder name used in the storage system. It cannot contain spaces and should use dashes instead. This name is used for organizing files on the server filesystem. For example, a domain with folder-name main-cdn would store files in storage/main-cdn/.
A category is a folder within a domain that groups related files together. Each category has a display name (shown in Discord) and a folder-name (used for storage). For example, a category with display name "Images" and folder-name "images" would store files in storage/domain-name/images/.
The complete file structure on disk is: storage/domain-folder-name/category-folder-name/filename.ext
The complete URL structure is: https://domain-fqdn/category-folder-name/filename.ext
The maximum file size you can upload depends on your Discord account subscription level and Discord server boost level:
- Account: free users: 10MB
- Account: Nitro Basic users: 50MB
- Account: Nitro users: 500MB
- Server: boosting level 0: 10MB
- Server: boosting level 1: 10MB
- Server: boosting level 2: 50MB
- Server: boosting level 3: 100MB
These limits are enforced by Discord, not by this application.
You can deploy this application using the provided Docker Compose file or through Coolify.
Deploy Using Docker Compose
- Create a
docker-compose.yamlfile on your server and paste the contents of thedocker-compose.yamlfrom this repo. - Update the volume paths in the compose file if needed.
- Enter value for
BOT_TOKENvariable on compose file. - Run
docker compose up.
Note: You will need to set up a reverse proxy in front of this application to forward requests to the CDN domain you are using. I haven’t configured this myself, so I’m not including step-by-step instructions here. You can use your preferred AI tool for guidance on setting this up.
Deploy Using Coolify
- Add a new resource in Coolify → "Docker Compose Empty."
- Paste the contents of the
coolify-compose.yamlfrom the repo into the input field. - Update the volume paths in the compose file if needed.
- On the Coolify General page, click the Settings option for the service. Then enter the domain you want to use for the CDN, making sure to append port
:8080.- Example (single domain):
https://storage.shadowarcanist.com:8080 - Example (multiple domains):
https://storage.shadowarcanist.com:8080,https://sub.domain2.com:8080,https://test.domain3.com:8080 - Make sure all domains are separated by commas and include port
:8080.
- Example (single domain):
- Go to "Environment Variables" page on Coolify and enter value for
BOT_TOKENvariable - Click "Deploy!"
- Install Go 1.23 or later
- Copy
.env.exampleto a file named.envand set yourBOT_TOKEN - Run the application:
go run cmd/main.go- The server will start on port 8080
BOT_TOKEN(required): Your Discord bot token from the Discord Developer PortalPORT(optional): The port for the web server (default: 8080)
Files are stored in the storage directory, organized by domain and category. The configs directory contains configuration files for domains, categories, and settings.
- Go to the Discord Developer Portal at https://discord.com/developers/applications
- Create a new application
- Go to the "Bot" section and click "Add Bot"
- Copy the token under "Token" section (Discord won't show token by default so you have to click on
reset tokenbutton to get token) - Enable the following bot intents under the "Privileged Gateway Intents" section:
- Message Content Intent
- Under "OAuth2" > "URL Generator", select
botscope, and selectSend Messagepermission - Select "Guild Install" as Integration Type
- Use the generated URL to invite the bot to your server
- This project was entirely created using AI, but the application has been thoroughly tested.
- It is inspired by Sapphire Images.
- This project was built primarily for my personal use, so I will not be merging pull requests or adding new features unless I need them myself. If you want to make changes or add features, feel free to fork this repository. It’s open-sourced so others can learn from it, use it as a base for their own projects, or even run the application as-is.
