D++ (DPP)
C++ Discord API Bot Library
Shardless Cluster: Events via Webhooks

What are shardless clusters?

D++ gives you two ways to handle Discord events: sharding via websockets (the default) and webhooks. Websocket shards connect to Discord, handle up to 2,500 servers each, and process events asynchronously via a REST API call. Webhooks, on the other hand, let Discord push events straight to your bot, skipping the extra API call and making responses instant. WebSockets are great for most bots, but webhooks are super efficient for massive bots, using fewer resources while handling tons of traffic. The recommended setup is to run Nginx or Apache as a reverse proxy in front of your D++ bot, ensuring security and scalability. Enabling webhooks is simple—just call a method in your bot to activate them. We’ll guide you through setting it up step by step.

A simple summary of this process and how it differs is shown below:

There are advantages and disadvantages to a shardless webhook bot, the main ones are:

Advantages Disadvantages
✅ Scales without restarts, any cluster can service any request
✅ Can be highly scalable on demand using a load balancer
✅ Can be scaled and proxied by cloudflare and other free services
✅ No need to keep shards connected, saving resources
❎ Only slash commands and other components interactions can be used as entry points to the bot. Other events do not fire.
❎ Special consideration needs to be given to request/response flow.
❎ Without shards you don't have cache, so must rely entirely on resolved data and API calls.

Creating the Discord bot

The first step is actually the easiest; enabling websocket event support in D++ is as simple as one method call, and specific parameters when initialising the cluster.bot

Please see the example below:

#include <dpp/dpp.h>
int main() {
/* We must use the special constant NO_SHARDS here */
dpp::cluster bot("TOKEN", 0, dpp::NO_SHARDS);
bot.on_ready([&](const dpp::ready_t& ready) {
/* Enable discord interactions endpoint on port 3000
* NOTE: PUT YOUR OWN PUBLIC KEY HERE FOR THE FIRST PARAMETER.
* You can find this on the same page where you entered the Discord Interaction URL.
* Do not use your Discord bot token in this field!
*/
bot.enable_webhook_server("f8032a386dc1903787be887cd66d126e83eb3d481455aca509a4b8cbc526cafe", "0.0.0.0", 3000);
/* Register a command */
bot.global_command_create(dpp::slashcommand("hello", "Greets you", bot.me.id));
});
bot.on_slashcommand([&](const dpp::slashcommand_t& event) {
event.reply("hello to you too");
});
bot.start(dpp::st_wait);
}
The cluster class represents a group of shards and a command queue for sending and receiving commands...
Definition: cluster.h:89
Represents an application command, created by your bot either globally, or on a guild.
Definition: appcommand.h:1397
std::function< void(const dpp::log_t &)> DPP_EXPORT cout_logger()
Get a default logger that outputs to std::cout. e.g.
constexpr uint32_t NO_SHARDS
Pass this value into the constructor of dpp::cluster for the shard count to create a cluster with no ...
Definition: cluster.h:61
@ st_wait
Wait forever on a condition variable. The cluster will spawn threads for each shard and start() will ...
Definition: cluster.h:72
Session ready.
Definition: dispatcher.h:1025
User has issued a slash command.
Definition: dispatcher.h:759

Note that you can get the public key from your application settings in the Discord Developer Portal. It is not your bot token!

Warning
It is important that if your bot works via webhook events, you do not delay in responding. You must respond as fast as possible to the request, with an event.reply(). You can always acknowledge the response with event.thinking() and edit the interaction later, but this must be done in a separate flow, NOT within the slashcommand event. This is because when you are in the event handler you are directly building a HTTP response that is directly sent back to Discord in an established HTTP request. You can follow up with other API calls if you wish later on. Each request is placed into D++'s thread pool, so you don't have to worry too much about blocking for a little while but remember users expect snappy responses and Discord have a 3 second hard limit on replies!

Setting Up a reverse proxy to route to your bot

Next, you should set up a reverse proxy using Nginx or Apache to forward requests from a public-facing HTTPS endpoint to a Discord bot listening on localhost:3000. Discord mandates that all webhook endpoints for interactions must be HTTPS with a valid non self-signed certificate.

We will use a free Let's Encrypt certificate for SSL on the proxy, while allowing the bot itself to run using plaintext or self-signed SSL.

Prerequisites

  • A Linux server
  • Nginx or Apache installed
  • A domain name (example.com) pointing to your server
  • A Discord bot running on port 3000
  • certbot installed for Let's Encrypt SSL

Option 1: Setting Up Nginx as a Reverse Proxy

Install Nginx

sudo apt update
sudo apt install nginx -y

Configure Nginx

Create a new configuration file:

sudo nano /etc/nginx/sites-available/discord_bot

Paste the following for plaintext (http) bot communication:

server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

If the bot uses self-signed SSL, modify proxy_pass:

location / {
proxy_pass https://localhost:3000;
proxy_ssl_verify off;
}

Enable the site and restart Nginx:

sudo ln -s /etc/nginx/sites-available/discord_bot /etc/nginx/sites-enabled/
sudo systemctl restart nginx

Enable Let's Encrypt SSL

sudo certbot --nginx -d example.com

Certbot will automatically update the Nginx configuration for HTTPS.

Option 2: Setting Up Apache as a Reverse Proxy

Install Apache and Modules

sudo apt update
sudo apt install apache2 -y
sudo a2enmod proxy proxy_http ssl
sudo systemctl restart apache2

Configure Apache Virtual Host

sudo nano /etc/apache2/sites-available/discord_bot.conf

Paste the following for plaintext (http) bot communication:

<VirtualHost *:80>
ServerName example.com
ProxyPass "/" "http://localhost:3000/"
ProxyPassReverse "/" "http://localhost:3000/"
</VirtualHost>

If the bot uses self-signed SSL, update it as follows:

<VirtualHost *:80>
ServerName example.com
ProxyPass "/" "https://localhost:3000/"
ProxyPassReverse "/" "https://localhost:3000/"
SSLProxyEngine on
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
</VirtualHost>

Enable the site and restart Apache:

sudo a2ensite discord_bot.conf
sudo systemctl restart apache2

Enable Let's Encrypt SSL

sudo certbot --apache -d example.com

Configuring Your Public URL in the Discord Developer Portal

Finally, to enable your Discord bot to receive interactions such as slash commands, you need to update Discord with the URL you set up above.

This involves configuring the Interactions Endpoint URL in your Discord application's settings.

Steps to Configure the Interactions Endpoint URL

  1. Access the Discord Developer Portal:
  2. Select Your Application:
    • In the Applications section, click on your bot's application to open its settings.
  3. Navigate to the "General Information" Tab:
    • On the left sidebar, select General Information.
  4. Set the Interactions Endpoint URL:
    • Locate the Interactions Endpoint URL field.
    • Enter your public URL (e.g., https://example.com/interactions).
    • Ensure this URL points to the endpoint you've set up to handle Discord's interaction payloads.
    • Take note of the public key for use in your bot
  5. Save Changes:
    • Scroll to the bottom of the page and click Save Changes.

Important Considerations

  • Public Accessibility: Ensure that the URL you provide is publicly accessible over the internet. Discord needs to reach this endpoint to send interaction events.
  • SSL/TLS Encryption: As outlined above in the section on setting up your reverse proxy, the URL must use HTTPS, meaning you need a valid SSL/TLS certificate for your domain. If you followed the guide properly, this should be working.
  • Endpoint Validation: Upon setting the Interactions Endpoint URL, Discord will send a PING request to verify the endpoint. D++ will ensure your bot replies appropriately.

You can find even more information on Discord's official documentation on Setting Up an Interaction Endpoint.

Further reading/Related pages

D++ Library version 10.1.1D++ Library version 10.1.0D++ Library version 10.0.35D++ Library version 10.0.34D++ Library version 10.0.33D++ Library version 10.0.32D++ Library version 10.0.31D++ Library version 10.0.30D++ Library version 10.0.29D++ Library version 10.0.28D++ Library version 10.0.27D++ Library version 10.0.26D++ Library version 10.0.25D++ Library version 10.0.24D++ Library version 10.0.23D++ Library version 10.0.22D++ Library version 10.0.21D++ Library version 10.0.20D++ Library version 10.0.19D++ Library version 10.0.18D++ Library version 10.0.17D++ Library version 10.0.16D++ Library version 10.0.15D++ Library version 10.0.14D++ Library version 10.0.13D++ Library version 10.0.12D++ Library version 10.0.11D++ Library version 10.0.10D++ Library version 10.0.9D++ Library version 10.0.8D++ Library version 10.0.7D++ Library version 10.0.6D++ Library version 10.0.5D++ Library version 10.0.4D++ Library version 10.0.3D++ Library version 10.0.2D++ Library version 10.0.1D++ Library version 10.0.0D++ Library version 9.0.19D++ Library version 9.0.18D++ Library version 9.0.17D++ Library version 9.0.16D++ Library version 9.0.15D++ Library version 9.0.14D++ Library version 9.0.13D++ Library version 9.0.12D++ Library version 9.0.11D++ Library version 9.0.10D++ Library version 9.0.9D++ Library version 9.0.8D++ Library version 9.0.7D++ Library version 9.0.6D++ Library version 9.0.5D++ Library version 9.0.4D++ Library version 9.0.3D++ Library version 9.0.2D++ Library version 9.0.1D++ Library version 9.0.0D++ Library version 1.0.2D++ Library version 1.0.1D++ Library version 1.0.0