A web server in your bot: webhooks, dashboards and your own domain

Updated

Most bots only connect out to Discord and never need this. If yours has to receive something (a vote webhook from a bot list, a GitHub webhook, a small status page), your server already has a public port for it.

Your address and port

Open Network in the panel. The address and port there are reachable from the internet. Your program gets the port as the SERVER_PORT environment variable, so it never needs typing into your code.

Listen on it

Listen on 0.0.0.0 (every interface) and SERVER_PORT. Not the address shown on the Network page: inside the server that address does not exist, and binding to it fails.

Python
# Python, aiohttp, next to a discord.py bot
import os
from aiohttp import web

async def vote(request):
    data = await request.json()
    print("vote from", data.get("user"))
    return web.Response(text="ok")

async def start_web():
    app = web.Application()
    app.router.add_post("/vote", vote)
    runner = web.AppRunner(app)
    await runner.setup()
    await web.TCPSite(runner, "0.0.0.0", int(os.environ["SERVER_PORT"])).start()

# call `await start_web()` from your bot's setup_hook
JavaScript
// JavaScript, Node's own http module, next to a discord.js bot
const http = require("node:http");

http.createServer((req, res) => {
  if (req.method === "POST" && req.url === "/vote") {
    let body = "";
    req.on("data", (chunk) => (body += chunk));
    req.on("end", () => { console.log("vote:", body); res.end("ok"); });
  } else {
    res.statusCode = 404;
    res.end();
  }
}).listen(Number(process.env.SERVER_PORT), "0.0.0.0");

Run the web server in the same process as the bot, as above. A second program in the same server needs your start script to launch both.

Then give the other service the address: http://, the address and port from the Network page, and your path, for example http://203.0.113.10:25570/vote.

Your own domain, with HTTPS

The Website tab puts what your server runs on one of its ports on a domain you own, with HTTPS (when the site is the main thing rather than part of a bot, a website plan gives it a server of its own): https://dash.example.com instead of an IP and a port. We get the certificate, renew it, and send visitors to your port. Up to three domains per server.

  1. Make your program answer on 0.0.0.0 and its port, as above. Check it at http://ADDRESS:PORT, using the address and port from the Network page, first.
  2. On the Website tab, type the domain (for example dash.example.com), pick the port and press Add domain.
  3. Where your domain's DNS is managed, add the two records the tab shows: a CNAME from your domain to sites.snowservers.com, and a TXT record named _snowservers. plus your domain, holding the code shown. The TXT record proves the domain is yours; without it nothing happens.
  4. Wait. The tab looks for the records every couple of minutes (Check now looks straight away), then gets the certificate. It usually takes a few minutes, and the tab says Live when it is done.

A bare domain like example.com can't have a CNAME at most DNS hosts: use an A record to the address the tab shows instead. If your domain is on Cloudflare, set both records to DNS only (grey cloud) until it is live; after that you can turn the orange cloud on, with SSL/TLS set to Full (strict).

Your program receives plain HTTP from us, with X-Forwarded-Proto: https and the visitor's address in X-Real-IP. WebSockets work. While your program is stopped, visitors see a short "not answering" page; while the server is suspended, a "paused" one.

Building a dashboard with "Sign in with Discord"? A Discord bot dashboard on your own domain covers the redirect URI, the proxy and the secrets.

More than one port

Every server can have up to five ports, free. On the Network page press Create Allocation (it is there while you have fewer than five), then restart the server so the new port opens.

Only the main port is handed to your program, as SERVER_PORT. For the others, copy the number from the Network page into your .env and read it from there.

What you do not get

  • HTTPS on the bare port. http:// address:port speaks whatever your program speaks, which is plain HTTP in the examples above. For HTTPS, use your own domain on the Website tab.
  • Ports 80 and 443 for your program. Ports come from our own range; the Network page shows yours. The Website tab is what answers on 443 for your domain and passes visitors on to your port.
  • A domain of ours. Websites use a domain you own; we don't hand out names under snowservers.com for them.

Check the sender

Anyone who finds the address can send requests to it. Bot lists and GitHub let you set a secret that is sent with each webhook: check it before trusting what arrived, and reply 401 when it does not match.

Press / or Ctrl K on any page to search.