diff --git a/README.md b/README.md
index d4b681c60c..a1fbf02bee 100644
--- a/README.md
+++ b/README.md
@@ -119,7 +119,7 @@ Create an `appsettings.Production.yml` file next to `appsettings.yml`. This will
- `General:GitHubAccessToken`: Specify a GitHub personal access token with no scopes here to highly mitigate the possiblity of 429 response codes from GitHub requests
-- `General:SkipAddingByondFirewallException`: Set to false if you have Windows firewall disabled
+- `General:SkipAddingByondFirewallException`: Set to `true` if you have Windows firewall disabled
- `Session:HighPriorityLiveDreamDaemon`: Boolean controlling if live DreamDaemon instances get set to above normal priority processes.
@@ -143,6 +143,8 @@ Create an `appsettings.Production.yml` file next to `appsettings.yml`. This will
- `ControlPanel:AllowedOrigins`: Set the Access-Control-Allow-Origin headers to this list of origins for all responses (also enables all headers and methods). This is overridden by `ControlPanel:AllowAnyOrigin`
+- `ControlPanel:PublicPath`: URL from which the webpanel can be accessed, defaults to "/app/". Must be an absolute path (https://example.org/path/to/webpanel) or a path starting from root (/path/to/webpanel). Note that this option does not relocate the webpanel for you; you will need a reverse proxy to relocate the webpanel
+
- `Elasticsearch`: tgstation-server also supports automatically ingesting its logs to ElasticSearch. You can set this up in the setup wizard, or with the following configuration:
```yml
Elasticsearch:
diff --git a/build/Version.props b/build/Version.props
index 7c313bb4f2..7003a585d3 100644
--- a/build/Version.props
+++ b/build/Version.props
@@ -4,7 +4,7 @@
5.1.0
- 4.3.0
+ 4.4.0
9.6.0
10.0.0
11.0.0
diff --git a/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs b/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs
index b58747f24b..b54c471f65 100644
--- a/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs
+++ b/src/Tgstation.Server.Host/Configuration/ControlPanelConfiguration.cs
@@ -27,6 +27,11 @@ namespace Tgstation.Server.Host.Configuration
///
public string Channel { get; set; }
+ ///
+ /// The public path to the TGS control panel from a wider network.
+ ///
+ public string PublicPath { get; set; }
+
///
/// Origins allowed for CORS requests.
///
diff --git a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs
index 6daf1ca2d4..c30b9fb804 100644
--- a/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs
+++ b/src/Tgstation.Server.Host/Controllers/ControlPanelController.cs
@@ -1,9 +1,12 @@
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.Net.Mime;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
@@ -26,6 +29,11 @@ namespace Tgstation.Server.Host.Controllers
///
public const string ControlPanelRoute = "/app";
+ ///
+ /// Header for forcing channel.json to be fetched.
+ ///
+ const string FetchChannelVaryHeader = "X-Webpanel-Fetch-Channel";
+
///
/// The for the .
///
@@ -70,9 +78,28 @@ namespace Tgstation.Server.Host.Controllers
{
FormatVersion = 1,
Channel = controlPanelChannel,
+ controlPanelConfiguration.PublicPath,
});
}
+ ///
+ public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+ {
+ if (context == null)
+ throw new ArgumentNullException(nameof(context));
+
+ var newValues = new List { FetchChannelVaryHeader };
+ var headers = context.HttpContext.Response.Headers;
+ if (headers.TryGetValue(HeaderNames.Vary, out var oldValues))
+ headers.Remove(HeaderNames.Vary);
+
+ newValues.AddRange(oldValues);
+
+ headers.Add(HeaderNames.Vary, new StringValues(newValues.ToArray()));
+
+ return base.OnActionExecutionAsync(context, next);
+ }
+
///
/// Handle a GET request to the control panel route. Route to static files if they exist, otherwise index.html.
///
@@ -80,8 +107,11 @@ namespace Tgstation.Server.Host.Controllers
/// The to use.
[Route("{**appRoute}")]
[HttpGet]
- public VirtualFileResult Get([FromRoute] string appRoute)
+ public IActionResult Get([FromRoute] string appRoute)
{
+ if (Request.Headers.ContainsKey(FetchChannelVaryHeader))
+ return GetChannelJson();
+
var fileInfo = hostEnvironment.WebRootFileProvider.GetFileInfo(appRoute);
if (fileInfo.Exists)
{
diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml
index 3fb8ebb675..a94f7e0d47 100644
--- a/src/Tgstation.Server.Host/appsettings.yml
+++ b/src/Tgstation.Server.Host/appsettings.yml
@@ -35,6 +35,7 @@ ControlPanel:
Channel: https://tgstation.github.io/tgstation-server-webpanel/api/${Major}.${Minor}.${Patch}
AllowAnyOrigin: false
AllowedOrigins: []
+ PublicPath:
Updates:
GitHubRepositoryId: 92952846
GitTagPrefix: tgstation-server-v