FoundryVTT Permalinks
TL;DR: When you open a window that can have a permalink generated, the window's URL is replaced with the link. Clicking the "Copy document id" link (top left of windows) or the button (depending on configuration) copies the permalink to the clipboard if possible, rather than the ID.
Supported versions: Requires Foundry 10 to work.
License: Version 1.1.1 and above is released under the MIT License.
Developed for Meadiocrity Mead (https://www.meadiocritymead.com/) and Battlemage Brewery (https://www.battlemagebrewing.com/)
Known issues
- Important note: For permalinks to work when a user isn't logged in, a reverse proxy change is necessary so 302 replies for Foundry login redirects include query parameters. See the bottom of this document for more details. An issue has been opened: https://github.com/foundryvtt/foundryvtt/issues/8512
- Links to particular pages of journal entries may not work.
Workaround if you're using nginx
If you're running a reverse proxy in front of Foundry, we can make it work. The essence of the config is the following:
location / {
proxy_pass http://localhost:30000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location /game {
proxy_pass http://localhost:30000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# If we're returning a 302 auth redirect from /game, pass the args
proxy_intercept_errors on;
error_page 302 = @join_redirect;
}
location @join_redirect {
return 302 /join$is_args$args;
}
Or, a full NixOS (https://nixos.org) config that requests a certificate via Let's Encrypt:
services.nginx.virtualHosts."foundry.example.com" = {
http2 = true;
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:30000";
proxyWebsockets = true;
};
locations."/game" = {
proxyPass = "http://127.0.0.1:30000";
proxyWebsockets = true;
extraConfig = ''
# If we're returning a 302 auth redirect from /game, pass the args
proxy_intercept_errors on;
error_page 302 = @join_redirect;
'';
};
extraConfig = ''
location @join_redirect {
return 302 /join$is_args$args;
}
'';
};