Network Access for Spells¶
Spells can call web services with Http, and stay connected to one with WebSocket. As the owner of a server, you decide which hosts they reach. Until you list a host, spells reach nothing at all.
For example, to let spells ask Modrinth for the newest Wizards of Lua, list
its host in config/wizards-of-lua/net.luaconf:
Then this spell tells you when an update is out:
local response = Http:request({
url = "https://api.modrinth.com/v2/project/wizards-of-lua/version",
query = {
loaders = '["' .. WizardsOfLua.loader .. '"]',
game_versions = '["' .. spell.server.version .. '"]',
},
})
if response and response.status == 200 then
local newest = Json:decode(response.body)[1].version_number:match("^[%d.]+")
local installed = WizardsOfLua.version:match("^[%d.]+")
if newest ~= installed then
print("Wizards of Lua " .. newest .. " is out, you have " .. installed)
end
end
The host list¶
The list is in config/wizards-of-lua/net.luaconf. The file appears the first time a spell uses the
network, with an empty list. It looks like this when you have filled it in:
hosts = {
"discord.com", -- this name, at any port
"*.discord.gg", -- every name below this one, but not discord.gg itself
}
| Entry | Allows |
|---|---|
"example.org" |
This name, at any port, and nothing below it |
"*.example.org" |
Every name below this one, at any depth, but not example.org itself |
"*" |
Every host, including the server's own computer and its local network |
"127.0.0.1", "::1" |
This address. 127.0.0.1 is not the same as localhost |
A few things to know:
- A change applies to the next request. You don't need to restart the server.
- A broken file allows nothing. Spells then get the reason
config_error, and the server's log says what's wrong. An entry with a scheme, a port or a path counts as broken, as it would otherwise silently allow nothing. - The file is Lua, but it runs on its own. It knows nothing but
env("NAME"), the value of an environment variable. - Redirects aren't followed. A redirect reaches the spell as a normal response, so it can't lead a request to a host that isn't listed.
What the list protects¶
Spells can't read or change the file. So the list keeps spell code from reaching further than you want, like a spell someone downloaded, or a spell that was written for another server. Whatever a bad spell does, it stays inside your server and the hosts you listed. An update of Wizards of Lua doesn't open network access by itself either.
The list doesn't protect you from someone who can edit files on your server. And it can't stop a spell from sending anything it knows to a host that is listed.
Be careful with "*", which reaches the computer the server runs on, and your local network too. A
router's admin page or a database without a password is then in reach of every spell.
Where tokens belong¶
Many services want a token or a password. Keep it in a Lua file of its own that returns a table, in
config/wizards-of-lua/, and let the spell require it:
- Don't put it into the
examplesfolder./wol extract examples overwritereplaces that folder. - Don't write it into a command, and don't paste it into the chat: commands end up in logs.
- Keep the file out of git, and out of backups and worlds that you hand on.
Wizards of Lua leaves tokens out of what it writes itself: its error messages name a host at most, never a URL or the value of a header.
That protects a token from accidents, not from the people who run spells: every spell can require
that file. Whoever can use /lua can read the token. See
who you can trust with /lua.
Limits¶
- A request has 10 seconds by default, and the spell can change that.
- A response or a message may have up to 16 MB.
- Sockets close when their spell ends. A spell waiting in
Http:requestkeeps its events, which wait in its queue.
NeoForge and IPv6¶
Most servers never notice this. It matters in two cases, and only on NeoForge.
A program on the server's own computer¶
Say you run a small program next to your Minecraft server, at port 8080. Use the address 127.0.0.1
for it, not localhost, in the host list and in the spell:
On NeoForge, localhost can mean the IPv6 address ::1, and a program that only listens on
127.0.0.1 isn't found there.
A web service that fails only on NeoForge¶
This spell shows what happens when it calls the service:
local response, reason = Http:request({ url = "https://api.example.org/" })
print(response and response.status or reason)
If it prints connect_failed, although the service works on a Fabric server or in your browser, then
the service has an IPv6 address that your server can't reach. NeoForge tells Java to try the
addresses in the order your system gives, which can put IPv6 first, and Java tries only that one. To
make Java try IPv4 first:
- Stop the server.
- In your server folder, open
libraries/net/neoforged/neoforge/<version>/, where<version>is your NeoForge version, like26.3.0.83. - In
win_args.txt(on Windows) orunix_args.txt(on Linux and macOS), change the line-Djava.net.preferIPv6Addresses=systeminto-Djava.net.preferIPv6Addresses=false. - Start the server.
An update of NeoForge brings new files, so do this again after each update. The line doesn't work in
user_jvm_args.txt or in your start script: NeoForge's own line comes later, and the later one wins. If your server runs at
a hosting company and you can't open these files, ask their support to change that line for you.
An example¶
The Discord bridge connects the chat of your server with a Discord channel, in both directions. Its guide also shows how to create a webhook and a Discord bot.