diff --git a/README.md b/README.md index 603fa83bbc..dd2c7379ea 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ Create an `appsettings.Production.json` file next to `appsettings.json`. This wi - `Logging:LogLevel:Default`: Can be one of `Trace`, `Debug`, `Information`, `Warning`, `Error`, or `Critical`. Restricts what is put into the log files. Currently `Debug` is reccommended for help with error reporting. +- `Kestrel:Endpoints:Http:Url`: The URL (i.e. interface and ports) your application should listen on. General use case should be `http://localhost:` for restricted local connections. See the Remote Access section for configuring public access to the World Wide Web. + - `Database:DatabaseType`: Can be one of `SqlServer`, `MariaDB`, or `MySql` - `Database:MySqlServerVersion`: The version of MySql/MariaDB the database resides on, can be left as null for attempted auto detection. Used by the MySQL/MariaDB provider for selection of [certain features](https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/blob/2.1.1/src/EFCore.MySql/Storage/Internal/ServerVersion.cs) ignore at your own risk. A string in the form `..` @@ -79,6 +81,41 @@ A breaking change from V3: tgstation-server 4 now REQUIRES the DMAPI to be integ The DMAPI is fully backwards compatible and should function with any tgstation-server version to date. Updates can be performed in the same manner. Using the `TGS_EXTERNAL_CONFIGURATION` is recommended in order to make the process as easy as replacing `tgs.dm` and the `tgs` folder with a new version +## Remote Access + +tgstation-server is an [ASP.Net Core](https://docs.microsoft.com/en-us/aspnet/core/) based on the Kestrel web server. This section is meant to serve as a general use case overview, but the entire Kestrel configuration can be modified to your liking with the configuration JSON. See [the official documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel) for details. + +Exposing the builtin kestrel server to the internet directly over HTTP is highly not reccommended due to the lack of security. The recommended way to expose tgstation-server to the internet is to host it through a reverse proxy with HTTPS support. Here are some step by step examples to achieve this for major web servers. + +System administrators will most likely have their own configuration plans, but here are some basic guides for beginners. + +Once complete, test that your configuration worked by visiting your proxy site from a different computer. You should recieve a 401 Unauthorized response. + +### IIS (Reccommended for Windows) + +1. Acquire an HTTPS certificate. The easiet free way for Windows is [win-acme](https://github.com/PKISharp/win-acme) (requires you to set up the website first) +2. Install the [Web Platform Installer](https://www.microsoft.com/web/downloads/platform.aspx) +3. Open the web platform installer in the IIS Manager and install the Application Request Routing 3.0 module +4. Create a new website, bind it to HTTPS only with your chosen certificate and exposed port. The physical path won't matter since it won't be used. Use `Require Server Name Indication` if you want to limit requests to a specific URL prefix. +5. Close and reopen the IIS Manager +5. Open the site and navigate to the `URL Rewrite` module +6. In the `Actions` Pane on the right click `Add Rule(s)...` +7. For the rule template, select `Reverse Proxy` under `Inbound and Outbound Rules` and click `OK` +8. You may get a prompt about enabling proxy functionality. Click `OK` +9. In the window that appears set the `Inbound Rules` textbox to the URL of your tgstation-server i.e. `http://localhost:5000`. Ensure `Enable SSL Offloading` is checked, then click `OK` + +### Nginx (Reccommended for Linux) + +TODO + +See https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ + +### Apache + +TODO + +See https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html + ## Usage tgstation-sever v4 is controlled via a RESTful HTTP json API. Documentation on this API can be found [here](https://tgstation.github.io/tgstation-server/api.html). This section serves to document the concepts of the server. diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs index cec17226f2..11c9b9a197 100644 --- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs +++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs @@ -154,7 +154,7 @@ namespace Tgstation.Server.Host.Components try { var sessionControllerFactory = new SessionControllerFactory(processExecutor, byond, byondTopicSender, cryptographySuite, application, gameIoManager, chat, loggerFactory, metadata.CloneMetadata()); - var reattachInfoHandler = new ReattachInfoHandler(databaseContextFactory, dmbFactory, metadata.CloneMetadata()); + var reattachInfoHandler = new ReattachInfoHandler(databaseContextFactory, dmbFactory, loggerFactory.CreateLogger(), metadata.CloneMetadata()); var watchdog = watchdogFactory.CreateWatchdog(chat, dmbFactory, reattachInfoHandler, configuration, sessionControllerFactory, metadata.CloneMetadata(), metadata.DreamDaemonSettings); eventConsumer.SetWatchdog(watchdog); commandFactory.SetWatchdog(watchdog); diff --git a/src/Tgstation.Server.Host/Components/ReattachInfoHandler.cs b/src/Tgstation.Server.Host/Components/ReattachInfoHandler.cs index 0aba902d06..8dc412f10a 100644 --- a/src/Tgstation.Server.Host/Components/ReattachInfoHandler.cs +++ b/src/Tgstation.Server.Host/Components/ReattachInfoHandler.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; using System; using System.Linq; using System.Threading; @@ -22,6 +23,11 @@ namespace Tgstation.Server.Host.Components /// readonly IDmbFactory dmbFactory; + /// + /// The for the + /// + readonly ILogger logger; + /// /// The for the /// @@ -32,17 +38,24 @@ namespace Tgstation.Server.Host.Components /// /// The value of /// The value of + /// The value of /// The value of - public ReattachInfoHandler(IDatabaseContextFactory databaseContextFactory, IDmbFactory dmbFactory, Api.Models.Instance metadata) + public ReattachInfoHandler(IDatabaseContextFactory databaseContextFactory, IDmbFactory dmbFactory, ILogger logger, Api.Models.Instance metadata) { this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.dmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory)); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); } /// public Task Save(WatchdogReattachInformation reattachInformation, CancellationToken cancellationToken) => databaseContextFactory.UseContext(async (db) => { + if (reattachInformation == null) + throw new ArgumentNullException(nameof(reattachInformation)); + + logger.LogDebug("Saving reattach information: {0}...", reattachInformation); + var instance = new Models.Instance { Id = metadata.Id }; db.Instances.Attach(instance); @@ -83,10 +96,15 @@ namespace Tgstation.Server.Host.Components ).ConfigureAwait(false); if (result == default) - throw new JobException("Unable to load reattach information!"); + { + logger.LogDebug("Reattach information not found!"); + return null; + } var bravoDmbTask = dmbFactory.FromCompileJob(result.Bravo.CompileJob, cancellationToken); - return new WatchdogReattachInformation(result, await dmbFactory.FromCompileJob(result.Alpha.CompileJob, cancellationToken).ConfigureAwait(false), await bravoDmbTask.ConfigureAwait(false)); + var info = new WatchdogReattachInformation(result, await dmbFactory.FromCompileJob(result.Alpha.CompileJob, cancellationToken).ConfigureAwait(false), await bravoDmbTask.ConfigureAwait(false)); + logger.LogDebug("Reattach information loaded: {0}", info); + return info; } } } diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogReattachInformation.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogReattachInformation.cs index f340a4cd8b..91ec990b55 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogReattachInformation.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogReattachInformation.cs @@ -1,4 +1,6 @@ -using Tgstation.Server.Host.Models; +using System; +using System.Globalization; +using Tgstation.Server.Host.Models; namespace Tgstation.Server.Host.Components.Watchdog { @@ -35,5 +37,8 @@ namespace Tgstation.Server.Host.Components.Watchdog if (copy.Bravo != null) Bravo = new ReattachInformation(copy.Bravo, dmbBravo); } + + /// + public override string ToString() => String.Format(CultureInfo.InvariantCulture, "Alpha: {0}, Bravo {1}", Alpha, Bravo); } } diff --git a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs index 3d808a7f96..115b0ae6fe 100644 --- a/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs +++ b/src/Tgstation.Server.Host/Models/ReattachInformationBase.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel.DataAnnotations; +using System.Globalization; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.Components.Watchdog; @@ -34,7 +35,6 @@ namespace Tgstation.Server.Host.Models /// /// The current DreamDaemon reboot state /// - [Required] public RebootState RebootState { get; set; } /// @@ -56,5 +56,8 @@ namespace Tgstation.Server.Host.Models ProcessId = copy.ProcessId; RebootState = copy.RebootState; } + + /// + public override string ToString() => String.Format(CultureInfo.InvariantCulture, "Process ID: {3}, Access Identifier {4}, Primary: {0}, RebootState: {1}, Port: {2}", IsPrimary, RebootState, Port, ProcessId, AccessIdentifier); } } diff --git a/src/Tgstation.Server.Host/appsettings.json b/src/Tgstation.Server.Host/appsettings.json index d16d0bb4f5..84f836f297 100644 --- a/src/Tgstation.Server.Host/appsettings.json +++ b/src/Tgstation.Server.Host/appsettings.json @@ -4,6 +4,13 @@ "DisableFileLogging": false, "MinimumPasswordLength": 15 }, + "Kestrel": { + "EndPoints": { + "Http": { + "Url": "http://0.0.0.0:5000" + } + } + }, "Logging": { "IncludeScopes": false, "Debug": { diff --git a/tests/Tgstation.Server.Tests/TestingServer.cs b/tests/Tgstation.Server.Tests/TestingServer.cs index 3e30fbfa06..e583fa5e93 100644 --- a/tests/Tgstation.Server.Tests/TestingServer.cs +++ b/tests/Tgstation.Server.Tests/TestingServer.cs @@ -37,8 +37,7 @@ namespace Tgstation.Server.Tests realServer = new ServerFactory().CreateServer(new string[] { - "--urls", - Url.ToString(), + String.Format(CultureInfo.InvariantCulture, "Kestrel:EndPoints:Http:Url={0}", Url), String.Format(CultureInfo.InvariantCulture, "Database:DatabaseType={0}", databaseType), String.Format(CultureInfo.InvariantCulture, "Database:ConnectionString={0}", connectionString), "Database:DropDatabase=true"