diff --git a/Web/Phantom.Web.Components/Phantom.Web.Components.csproj b/Web/Phantom.Web.Components/Phantom.Web.Components.csproj
index 2282e63..5e9cc7d 100644
--- a/Web/Phantom.Web.Components/Phantom.Web.Components.csproj
+++ b/Web/Phantom.Web.Components/Phantom.Web.Components.csproj
@@ -13,4 +13,8 @@
     <PackageReference Include="Microsoft.AspNetCore.Components.Web" />
   </ItemGroup>
   
+  <ItemGroup>
+    <ProjectReference Include="..\Phantom.Web.Services\Phantom.Web.Services.csproj" />
+  </ItemGroup>
+  
 </Project>
diff --git a/Web/Phantom.Web/Base/PhantomComponent.cs b/Web/Phantom.Web.Components/PhantomComponent.cs
similarity index 97%
rename from Web/Phantom.Web/Base/PhantomComponent.cs
rename to Web/Phantom.Web.Components/PhantomComponent.cs
index 23eda1a..42f80f3 100644
--- a/Web/Phantom.Web/Base/PhantomComponent.cs
+++ b/Web/Phantom.Web.Components/PhantomComponent.cs
@@ -6,7 +6,7 @@ using Phantom.Web.Services.Authorization;
 using ILogger = Serilog.ILogger;
 using UserInfo = Phantom.Web.Services.Authentication.UserInfo;
 
-namespace Phantom.Web.Base;
+namespace Phantom.Web.Components;
 
 public abstract class PhantomComponent : ComponentBase, IDisposable {
 	private static readonly ILogger Logger = PhantomLogger.Create<PhantomComponent>();
diff --git a/Web/Phantom.Web.Components/_Imports.razor b/Web/Phantom.Web.Components/_Imports.razor
index ce9ff7b..fe35002 100644
--- a/Web/Phantom.Web.Components/_Imports.razor
+++ b/Web/Phantom.Web.Components/_Imports.razor
@@ -1,5 +1,6 @@
 @using Microsoft.AspNetCore.Components.Forms
 @using Microsoft.AspNetCore.Components.Web
+@using Phantom.Web.Components
 @using Phantom.Web.Components.Forms
 @using Phantom.Web.Components.Forms.Base
 @using Phantom.Web.Components.Forms.Fields
diff --git a/Web/Phantom.Web.Services/ApplicationProperties.cs b/Web/Phantom.Web.Services/ApplicationProperties.cs
new file mode 100644
index 0000000..91e8d88
--- /dev/null
+++ b/Web/Phantom.Web.Services/ApplicationProperties.cs
@@ -0,0 +1,6 @@
+namespace Phantom.Web.Services;
+
+public sealed record ApplicationProperties(
+	string Version,
+	byte[] AdministratorToken
+);
diff --git a/Web/Phantom.Web.Services/Authentication/UserLoginManager.cs b/Web/Phantom.Web.Services/Authentication/UserLoginManager.cs
index b3c0e2f..3f6432a 100644
--- a/Web/Phantom.Web.Services/Authentication/UserLoginManager.cs
+++ b/Web/Phantom.Web.Services/Authentication/UserLoginManager.cs
@@ -9,13 +9,13 @@ namespace Phantom.Web.Services.Authentication;
 public sealed class UserLoginManager {
 	private static readonly ILogger Logger = PhantomLogger.Create<UserLoginManager>();
 
-	private readonly INavigation navigation;
+	private readonly Navigation navigation;
 	private readonly UserSessionManager sessionManager;
 	private readonly UserSessionBrowserStorage sessionBrowserStorage;
 	private readonly CustomAuthenticationStateProvider authenticationStateProvider;
 	private readonly ControllerConnection controllerConnection;
 
-	public UserLoginManager(INavigation navigation, UserSessionManager sessionManager, UserSessionBrowserStorage sessionBrowserStorage, CustomAuthenticationStateProvider authenticationStateProvider, ControllerConnection controllerConnection) {
+	public UserLoginManager(Navigation navigation, UserSessionManager sessionManager, UserSessionBrowserStorage sessionBrowserStorage, CustomAuthenticationStateProvider authenticationStateProvider, ControllerConnection controllerConnection) {
 		this.navigation = navigation;
 		this.sessionManager = sessionManager;
 		this.sessionBrowserStorage = sessionBrowserStorage;
diff --git a/Web/Phantom.Web.Services/INavigation.cs b/Web/Phantom.Web.Services/INavigation.cs
deleted file mode 100644
index f8aabee..0000000
--- a/Web/Phantom.Web.Services/INavigation.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-
-namespace Phantom.Web.Services;
-
-public interface INavigation {
-	string BasePath { get; }
-	bool GetQueryParameter(string key, [MaybeNullWhen(false)] out string value);
-	Task NavigateTo(string url, bool forceLoad = false);
-}
diff --git a/Web/Phantom.Web/Base/Navigation.cs b/Web/Phantom.Web.Services/Navigation.cs
similarity index 89%
rename from Web/Phantom.Web/Base/Navigation.cs
rename to Web/Phantom.Web.Services/Navigation.cs
index f7c704d..950f933 100644
--- a/Web/Phantom.Web/Base/Navigation.cs
+++ b/Web/Phantom.Web.Services/Navigation.cs
@@ -2,11 +2,10 @@
 using System.Web;
 using Microsoft.AspNetCore.Components;
 using Microsoft.AspNetCore.Components.Routing;
-using Phantom.Web.Services;
 
-namespace Phantom.Web.Base;
+namespace Phantom.Web.Services;
 
-sealed class Navigation : INavigation {
+public sealed class Navigation {
 	public static Func<IServiceProvider, Navigation> Create(string basePath) {
 		return provider => new Navigation(basePath, provider.GetRequiredService<NavigationManager>());
 	}
@@ -27,6 +26,10 @@ sealed class Navigation : INavigation {
 		value = query.Get(key);
 		return value != null;
 	}
+
+	public string CreateReturnUrl() {
+		return navigationManager.ToBaseRelativePath(navigationManager.Uri).TrimEnd('/');
+	}
 	
 	public async Task NavigateTo(string url, bool forceLoad = false) {
 		var newPath = BasePath + url;
diff --git a/Web/Phantom.Web/App.razor b/Web/Phantom.Web/App.razor
index 43fa75a..5b8ce65 100644
--- a/Web/Phantom.Web/App.razor
+++ b/Web/Phantom.Web/App.razor
@@ -1,6 +1,5 @@
 @using Phantom.Web.Services
-@inject INavigation Nav
-@inject NavigationManager NavigationManager
+@inject Navigation Navigation
 
 <CascadingAuthenticationState>
   <Router AppAssembly="@typeof(App).Assembly">
@@ -12,8 +11,7 @@
             <p role="alert">You do not have permission to visit this page.</p>
           }
           else {
-            var returnUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri).TrimEnd('/');
-            Nav.NavigateTo("login" + QueryString.Create("return", returnUrl), forceLoad: true);
+            Navigation.NavigateTo("login" + QueryString.Create("return", Navigation.CreateReturnUrl()), forceLoad: true);
           }
         </NotAuthorized>
       </AuthorizeRouteView>
diff --git a/Web/Phantom.Web/Configuration.cs b/Web/Phantom.Web/Configuration.cs
deleted file mode 100644
index 3ce1ceb..0000000
--- a/Web/Phantom.Web/Configuration.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-using ILogger = Serilog.ILogger;
-
-namespace Phantom.Web;
-
-sealed record Configuration(ILogger Logger, string Host, ushort Port, string BasePath, string DataProtectionKeyFolderPath, CancellationToken CancellationToken) {
-	public string HttpUrl => "http://" + Host + ":" + Port;
-}
diff --git a/Web/Phantom.Web/Layout/NavMenu.razor b/Web/Phantom.Web/Layout/NavMenu.razor
index 6d78ae4..5d0c4de 100644
--- a/Web/Phantom.Web/Layout/NavMenu.razor
+++ b/Web/Phantom.Web/Layout/NavMenu.razor
@@ -1,6 +1,7 @@
-@using Phantom.Web.Services.Authorization
+@using Phantom.Web.Services
+@using Phantom.Web.Services.Authorization
 @using Phantom.Common.Data.Web.Users
-@inject ServiceConfiguration Configuration
+@inject ApplicationProperties ApplicationProperties
 @inject PermissionManager PermissionManager
 
 <div class="navbar navbar-dark">
@@ -45,7 +46,7 @@
     </AuthorizeView>
   </nav>
   <footer>
-    Build @Configuration.Version
+    Build @ApplicationProperties.Version
   </footer>
 </div>
 
diff --git a/Web/Phantom.Web/Layout/_Error.cshtml b/Web/Phantom.Web/Layout/_Error.cshtml
index 1e6e42f..4129d1b 100644
--- a/Web/Phantom.Web/Layout/_Error.cshtml
+++ b/Web/Phantom.Web/Layout/_Error.cshtml
@@ -1,7 +1,7 @@
 @page
 @using Phantom.Web.Services
 @model Phantom.Web.Layout.ErrorModel
-@inject INavigation Navigation
+@inject Navigation Navigation
 
 <!DOCTYPE html>
 <html lang="en">
diff --git a/Web/Phantom.Web/Layout/_Layout.cshtml b/Web/Phantom.Web/Layout/_Layout.cshtml
index 6791c4d..4c398a6 100644
--- a/Web/Phantom.Web/Layout/_Layout.cshtml
+++ b/Web/Phantom.Web/Layout/_Layout.cshtml
@@ -1,7 +1,7 @@
 @using Phantom.Web.Services
 @namespace Phantom.Web.Layout
 @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
-@inject INavigation Navigation
+@inject Navigation Navigation
 
 <!DOCTYPE html>
 <html lang="en">
diff --git a/Web/Phantom.Web/Pages/Agents.razor b/Web/Phantom.Web/Pages/Agents.razor
index a5e80dc..03026cc 100644
--- a/Web/Phantom.Web/Pages/Agents.razor
+++ b/Web/Phantom.Web/Pages/Agents.razor
@@ -2,7 +2,7 @@
 @using Phantom.Common.Data.Web.Agent
 @using Phantom.Utils.Collections
 @using Phantom.Web.Services.Agents
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject AgentManager AgentManager
 
 <h1>Agents</h1>
diff --git a/Web/Phantom.Web/Pages/Audit.razor b/Web/Phantom.Web/Pages/Audit.razor
index e334fa0..20ce0f5 100644
--- a/Web/Phantom.Web/Pages/Audit.razor
+++ b/Web/Phantom.Web/Pages/Audit.razor
@@ -5,7 +5,7 @@
 @using Phantom.Common.Data.Web.Users
 @using Phantom.Web.Services.Users
 @using Phantom.Web.Services.Instances
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject AuditLogManager AuditLogManager
 @inject InstanceManager InstanceManager
 @inject UserManager UserManager
diff --git a/Web/Phantom.Web/Pages/Events.razor b/Web/Phantom.Web/Pages/Events.razor
index 41527b7..89cef9e 100644
--- a/Web/Phantom.Web/Pages/Events.razor
+++ b/Web/Phantom.Web/Pages/Events.razor
@@ -6,7 +6,7 @@
 @using Phantom.Web.Services.Agents
 @using Phantom.Web.Services.Events
 @using Phantom.Web.Services.Instances
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject AgentManager AgentManager
 @inject EventLogManager EventLogManager
 @inject InstanceManager InstanceManager
diff --git a/Web/Phantom.Web/Pages/InstanceDetail.razor b/Web/Phantom.Web/Pages/InstanceDetail.razor
index 23b5991..2256ea3 100644
--- a/Web/Phantom.Web/Pages/InstanceDetail.razor
+++ b/Web/Phantom.Web/Pages/InstanceDetail.razor
@@ -6,7 +6,7 @@
 @using Phantom.Common.Data.Web.Users
 @using Phantom.Web.Services.Instances
 @using Phantom.Web.Services.Authorization
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject InstanceManager InstanceManager
 
 @if (Instance == null) {
diff --git a/Web/Phantom.Web/Pages/InstanceEdit.razor b/Web/Phantom.Web/Pages/InstanceEdit.razor
index 270f25b..90a6aa4 100644
--- a/Web/Phantom.Web/Pages/InstanceEdit.razor
+++ b/Web/Phantom.Web/Pages/InstanceEdit.razor
@@ -3,7 +3,7 @@
 @using Phantom.Common.Data.Instance
 @using Phantom.Common.Data.Web.Users
 @using Phantom.Web.Services.Instances
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject InstanceManager InstanceManager
 
 @if (InstanceConfiguration == null) {
diff --git a/Web/Phantom.Web/Pages/Instances.razor b/Web/Phantom.Web/Pages/Instances.razor
index c4ad3c9..9c572b7 100644
--- a/Web/Phantom.Web/Pages/Instances.razor
+++ b/Web/Phantom.Web/Pages/Instances.razor
@@ -6,7 +6,7 @@
 @using Phantom.Web.Services.Agents
 @using Phantom.Web.Services.Authorization
 @using Phantom.Web.Services.Instances
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject AgentManager AgentManager
 @inject InstanceManager InstanceManager
 
diff --git a/Web/Phantom.Web/Pages/Login.razor b/Web/Phantom.Web/Pages/Login.razor
index 87001ed..1c9e7ba 100644
--- a/Web/Phantom.Web/Pages/Login.razor
+++ b/Web/Phantom.Web/Pages/Login.razor
@@ -3,7 +3,7 @@
 @using Phantom.Web.Services.Authentication
 @using System.ComponentModel.DataAnnotations
 @attribute [AllowAnonymous]
-@inject INavigation Navigation
+@inject Navigation Navigation
 @inject UserLoginManager LoginManager
 
 <h1>Login</h1>
diff --git a/Web/Phantom.Web/Pages/Setup.razor b/Web/Phantom.Web/Pages/Setup.razor
index de89aa6..a4a730c 100644
--- a/Web/Phantom.Web/Pages/Setup.razor
+++ b/Web/Phantom.Web/Pages/Setup.razor
@@ -1,5 +1,6 @@
 @page "/setup"
 @using Phantom.Utils.Tasks
+@using Phantom.Web.Services
 @using Phantom.Web.Services.Authentication
 @using Phantom.Web.Services.Rpc
 @using System.ComponentModel.DataAnnotations
@@ -9,7 +10,7 @@
 @using Phantom.Common.Data.Web.Users
 @using Phantom.Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults
 @attribute [AllowAnonymous]
-@inject ServiceConfiguration ServiceConfiguration
+@inject ApplicationProperties ApplicationProperties
 @inject UserLoginManager LoginManager
 @inject ControllerConnection ControllerConnection
 
@@ -83,7 +84,7 @@
       return false;
     }
 
-    return CryptographicOperations.FixedTimeEquals(formTokenBytes, ServiceConfiguration.AdministratorToken);
+    return CryptographicOperations.FixedTimeEquals(formTokenBytes, ApplicationProperties.AdministratorToken);
   }
 
   private async Task<Result<string>> CreateOrUpdateAdministrator() {
diff --git a/Web/Phantom.Web/Pages/Users.razor b/Web/Phantom.Web/Pages/Users.razor
index 45f59bc..28618fc 100644
--- a/Web/Phantom.Web/Pages/Users.razor
+++ b/Web/Phantom.Web/Pages/Users.razor
@@ -4,7 +4,7 @@
 @using Phantom.Common.Data.Web.Users
 @using Phantom.Web.Services.Users
 @using Phantom.Web.Services.Authorization
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject UserManager UserManager
 @inject RoleManager RoleManager
 @inject UserRoleManager UserRoleManager
diff --git a/Web/Phantom.Web/Program.cs b/Web/Phantom.Web/Program.cs
index 6662931..1ae9ab5 100644
--- a/Web/Phantom.Web/Program.cs
+++ b/Web/Phantom.Web/Program.cs
@@ -10,6 +10,7 @@ using Phantom.Utils.Rpc.Sockets;
 using Phantom.Utils.Runtime;
 using Phantom.Utils.Tasks;
 using Phantom.Web;
+using Phantom.Web.Services;
 using Phantom.Web.Services.Rpc;
 
 var shutdownCancellationTokenSource = new CancellationTokenSource();
@@ -48,15 +49,15 @@ try {
 
 	var (controllerCertificate, webToken) = webKey.Value;
 	
+	var administratorToken = TokenGenerator.Create(60);
+	var applicationProperties = new ApplicationProperties(fullVersion, TokenGenerator.GetBytesOrThrow(administratorToken));
+	
 	var rpcConfiguration = new RpcConfiguration("Rpc", controllerHost, controllerPort, controllerCertificate);
 	var rpcSocket = RpcClientSocket.Connect(rpcConfiguration, WebMessageRegistries.Definitions, new RegisterWebMessage(webToken));
-	
-	var configuration = new Configuration(PhantomLogger.Create("Web"), webServerHost, webServerPort, webBasePath, dataProtectionKeysPath, shutdownCancellationToken);
-	var administratorToken = TokenGenerator.Create(60);
 
+	var webConfiguration = new WebLauncher.Configuration(PhantomLogger.Create("Web"), webServerHost, webServerPort, webBasePath, dataProtectionKeysPath, shutdownCancellationToken);
 	var taskManager = new TaskManager(PhantomLogger.Create<TaskManager>("Web"));
-	var serviceConfiguration = new ServiceConfiguration(fullVersion, TokenGenerator.GetBytesOrThrow(administratorToken), shutdownCancellationToken);
-	var webApplication = WebLauncher.CreateApplication(configuration, taskManager, serviceConfiguration, rpcSocket.Connection);
+	var webApplication = WebLauncher.CreateApplication(webConfiguration, taskManager, applicationProperties, rpcSocket.Connection);
 
 	MessageListener messageListener;
 	await using (var scope = webApplication.Services.CreateAsyncScope()) {
@@ -77,9 +78,9 @@ try {
 		
 		PhantomLogger.Root.InformationHeading("Launching Phantom Panel web...");
 		PhantomLogger.Root.Information("Your administrator token is: {AdministratorToken}", administratorToken);
-		PhantomLogger.Root.Information("For administrator setup, visit: {HttpUrl}{SetupPath}", configuration.HttpUrl, configuration.BasePath + "setup");
+		PhantomLogger.Root.Information("For administrator setup, visit: {HttpUrl}{SetupPath}", webConfiguration.HttpUrl, webConfiguration.BasePath + "setup");
 		
-		await WebLauncher.Launch(configuration, webApplication);
+		await WebLauncher.Launch(webConfiguration, webApplication);
 	} finally {
 		shutdownCancellationTokenSource.Cancel();
 		await taskManager.Stop();
diff --git a/Web/Phantom.Web/ServiceConfiguration.cs b/Web/Phantom.Web/ServiceConfiguration.cs
deleted file mode 100644
index 10221ca..0000000
--- a/Web/Phantom.Web/ServiceConfiguration.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Phantom.Web;
-
-public sealed record ServiceConfiguration(
-	string Version,
-	byte[] AdministratorToken,
-	CancellationToken CancellationToken
-);
diff --git a/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor b/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor
index 2ae7d6c..60494df 100644
--- a/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor
+++ b/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor
@@ -15,8 +15,8 @@
 @using Phantom.Web.Services.Agents
 @using Phantom.Web.Services.Instances
 @using Phantom.Web.Services.Rpc
-@inherits PhantomComponent
-@inject INavigation Nav
+@inherits Phantom.Web.Components.PhantomComponent
+@inject Navigation Navigation
 @inject ControllerConnection ControllerConnection
 @inject AgentManager AgentManager
 @inject InstanceManager InstanceManager
@@ -342,7 +342,7 @@
 
     var result = await InstanceManager.CreateOrUpdateInstance(loggedInUserGuid.Value, instance, CancellationToken);
     if (result.Is(CreateOrUpdateInstanceResult.Success)) {
-      await Nav.NavigateTo("instances/" + instance.InstanceGuid);
+      await Navigation.NavigateTo("instances/" + instance.InstanceGuid);
     }
     else {
       form.SubmitModel.StopSubmitting(result.ToSentence(CreateOrUpdateInstanceResultExtensions.ToSentence));
diff --git a/Web/Phantom.Web/Shared/InstanceCommandInput.razor b/Web/Phantom.Web/Shared/InstanceCommandInput.razor
index 4303fa7..091cfa8 100644
--- a/Web/Phantom.Web/Shared/InstanceCommandInput.razor
+++ b/Web/Phantom.Web/Shared/InstanceCommandInput.razor
@@ -1,7 +1,7 @@
 @using Phantom.Web.Services.Instances
 @using Phantom.Common.Data.Web.Users
 @using Phantom.Common.Data.Replies
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject InstanceManager InstanceManager
 
 <Form Model="form" OnSubmit="ExecuteCommand">
diff --git a/Web/Phantom.Web/Shared/InstanceLog.razor b/Web/Phantom.Web/Shared/InstanceLog.razor
index 69ba35b..11345f5 100644
--- a/Web/Phantom.Web/Shared/InstanceLog.razor
+++ b/Web/Phantom.Web/Shared/InstanceLog.razor
@@ -3,7 +3,7 @@
 @using System.Diagnostics
 @using Phantom.Web.Services.Instances
 @using Phantom.Common.Data.Web.Users
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject IJSRuntime Js;
 @inject InstanceLogManager InstanceLogManager;
 
diff --git a/Web/Phantom.Web/Shared/InstanceStopDialog.razor b/Web/Phantom.Web/Shared/InstanceStopDialog.razor
index 336f6f7..9beb10b 100644
--- a/Web/Phantom.Web/Shared/InstanceStopDialog.razor
+++ b/Web/Phantom.Web/Shared/InstanceStopDialog.razor
@@ -3,7 +3,7 @@
 @using Phantom.Common.Data.Web.Users
 @using Phantom.Common.Data.Minecraft
 @using Phantom.Common.Data.Replies
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject IJSRuntime Js;
 @inject InstanceManager InstanceManager;
 
diff --git a/Web/Phantom.Web/Shared/UserAddDialog.razor b/Web/Phantom.Web/Shared/UserAddDialog.razor
index dcc7bc5..264b678 100644
--- a/Web/Phantom.Web/Shared/UserAddDialog.razor
+++ b/Web/Phantom.Web/Shared/UserAddDialog.razor
@@ -2,7 +2,7 @@
 @using Phantom.Common.Data.Web.Users.CreateUserResults
 @using Phantom.Web.Services.Users
 @using System.ComponentModel.DataAnnotations
-@inherits PhantomComponent
+@inherits Phantom.Web.Components.PhantomComponent
 @inject IJSRuntime Js;
 @inject UserManager UserManager;
 
diff --git a/Web/Phantom.Web/Shared/UserEditDialogBase.cs b/Web/Phantom.Web/Shared/UserEditDialogBase.cs
index 481fb7d..be676f2 100644
--- a/Web/Phantom.Web/Shared/UserEditDialogBase.cs
+++ b/Web/Phantom.Web/Shared/UserEditDialogBase.cs
@@ -1,7 +1,7 @@
 using Microsoft.AspNetCore.Components;
 using Microsoft.JSInterop;
 using Phantom.Common.Data.Web.Users;
-using Phantom.Web.Base;
+using Phantom.Web.Components;
 using Phantom.Web.Components.Forms;
 
 namespace Phantom.Web.Shared;
diff --git a/Web/Phantom.Web/WebLauncher.cs b/Web/Phantom.Web/WebLauncher.cs
index 2217e35..b4a534c 100644
--- a/Web/Phantom.Web/WebLauncher.cs
+++ b/Web/Phantom.Web/WebLauncher.cs
@@ -2,14 +2,18 @@
 using Phantom.Common.Messages.Web;
 using Phantom.Utils.Rpc.Runtime;
 using Phantom.Utils.Tasks;
-using Phantom.Web.Base;
 using Phantom.Web.Services;
 using Serilog;
+using ILogger = Serilog.ILogger;
 
 namespace Phantom.Web;
 
 static class WebLauncher {
-	public static WebApplication CreateApplication(Configuration config, TaskManager taskManager, ServiceConfiguration serviceConfiguration, RpcConnectionToServer<IMessageToControllerListener> controllerConnection) {
+	internal sealed record Configuration(ILogger Logger, string Host, ushort Port, string BasePath, string DataProtectionKeyFolderPath, CancellationToken CancellationToken) {
+		public string HttpUrl => "http://" + Host + ":" + Port;
+	}
+	
+	internal static WebApplication CreateApplication(Configuration config, TaskManager taskManager, ApplicationProperties applicationProperties, RpcConnectionToServer<IMessageToControllerListener> controllerConnection) {
 		var assembly = typeof(WebLauncher).Assembly;
 		var builder = WebApplication.CreateBuilder(new WebApplicationOptions {
 			ApplicationName = assembly.GetName().Name,
@@ -26,12 +30,12 @@ static class WebLauncher {
 		}
 
 		builder.Services.AddSingleton(taskManager);
-		builder.Services.AddSingleton(serviceConfiguration);
+		builder.Services.AddSingleton(applicationProperties);
 		builder.Services.AddSingleton(controllerConnection);
 		builder.Services.AddPhantomServices();
 
 		builder.Services.AddSingleton<IHostLifetime>(new NullLifetime());
-		builder.Services.AddScoped<INavigation>(Navigation.Create(config.BasePath));
+		builder.Services.AddScoped(Navigation.Create(config.BasePath));
 
 		builder.Services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(config.DataProtectionKeyFolderPath));
 
@@ -41,7 +45,7 @@ static class WebLauncher {
 		return builder.Build();
 	}
 
-	public static Task Launch(Configuration config, WebApplication application) {
+	internal static Task Launch(Configuration config, WebApplication application) {
 		var logger = config.Logger;
 
 		application.UseSerilogRequestLogging();
diff --git a/Web/Phantom.Web/_Imports.razor b/Web/Phantom.Web/_Imports.razor
index 338c09a..22dae24 100644
--- a/Web/Phantom.Web/_Imports.razor
+++ b/Web/Phantom.Web/_Imports.razor
@@ -6,8 +6,7 @@
 @using Microsoft.AspNetCore.Components.Web
 @using Microsoft.AspNetCore.Components.Web.Virtualization
 @using Microsoft.JSInterop
-@using Phantom.Web
-@using Phantom.Web.Base
+@using Phantom.Web.Components
 @using Phantom.Web.Components.Dialogs
 @using Phantom.Web.Components.Forms
 @using Phantom.Web.Components.Graphics