diff --git a/Agent/Phantom.Agent/Program.cs b/Agent/Phantom.Agent/Program.cs
index aba4733..5d09bf5 100644
--- a/Agent/Phantom.Agent/Program.cs
+++ b/Agent/Phantom.Agent/Program.cs
@@ -1,4 +1,5 @@
-using Phantom.Agent;
+using System.Reflection;
+using Phantom.Agent;
 using Phantom.Agent.Rpc;
 using Phantom.Agent.Services;
 using Phantom.Agent.Services.Rpc;
@@ -19,6 +20,7 @@ PosixSignals.RegisterCancellation(cancellationTokenSource, static () => {
 
 try {
 	PhantomLogger.Root.InformationHeading("Initializing Phantom Panel agent...");
+	PhantomLogger.Root.Information("Agent version: {Version}", AssemblyAttributes.GetFullVersion(Assembly.GetExecutingAssembly()));
 
 	var (serverHost, serverPort, javaSearchPath, authToken, authTokenFilePath, agentName, maxInstances, maxMemory, allowedServerPorts, allowedRconPorts) = Variables.LoadOrExit();
 	
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..51cd062
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,5 @@
+<Project>
+  <PropertyGroup>
+    <Version>0.0.1</Version>
+  </PropertyGroup>
+</Project>
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 762e699..3272e22 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -1,3 +1,11 @@
 <Project>
+  
   <Sdk Name="Microsoft.Build.CentralPackageVersions" Version="2.1.3" />
+  
+  <Target Name="SetSourceRevisionId" BeforeTargets="InitializeSourceControlInformation">
+    <Exec Command="git describe --always --abbrev=8" ConsoleToMSBuild="True" IgnoreExitCode="False">
+      <Output PropertyName="SourceRevisionId" TaskParameter="ConsoleOutput" />
+    </Exec>
+  </Target>
+
 </Project>
diff --git a/Server/Phantom.Server.Services/ServiceConfiguration.cs b/Server/Phantom.Server.Services/ServiceConfiguration.cs
index 6b31b82..ce6129b 100644
--- a/Server/Phantom.Server.Services/ServiceConfiguration.cs
+++ b/Server/Phantom.Server.Services/ServiceConfiguration.cs
@@ -1,6 +1,7 @@
 namespace Phantom.Server.Services;
 
 public sealed record ServiceConfiguration(
+	string Version,
 	byte[] AdministratorToken,
 	CancellationToken CancellationToken
 );
diff --git a/Server/Phantom.Server.Web/Layout/NavMenu.razor b/Server/Phantom.Server.Web/Layout/NavMenu.razor
index f2a2d41..4862fd4 100644
--- a/Server/Phantom.Server.Web/Layout/NavMenu.razor
+++ b/Server/Phantom.Server.Web/Layout/NavMenu.razor
@@ -1,4 +1,7 @@
-<div class="navbar navbar-dark">
+@using Phantom.Server.Services
+@inject ServiceConfiguration Configuration
+
+<div class="navbar navbar-dark">
   <div class="container-fluid">
     <a class="navbar-brand" href="">Phantom Panel</a>
     <button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
@@ -7,8 +10,8 @@
   </div>
 </div>
 
-<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
-  <nav class="flex-column">
+<div class="navbar-menu @NavMenuCssClass" @onclick="ToggleNavMenu">
+  <nav>
     <NavMenuItem Label="Home" Icon="home" Match="NavLinkMatch.All" />
     <AuthorizeView>
       <NotAuthorized>
@@ -21,6 +24,9 @@
       </Authorized>
     </AuthorizeView>
   </nav>
+  <footer>
+    Build @Configuration.Version
+  </footer>
 </div>
 
 @code {
diff --git a/Server/Phantom.Server.Web/Layout/NavMenu.razor.css b/Server/Phantom.Server.Web/Layout/NavMenu.razor.css
index aa77ca5..587e76e 100644
--- a/Server/Phantom.Server.Web/Layout/NavMenu.razor.css
+++ b/Server/Phantom.Server.Web/Layout/NavMenu.razor.css
@@ -7,13 +7,34 @@
   background-color: rgba(255, 255, 255, 0.15);
 }
 
+footer {
+  margin: 0 0.75rem 0.5rem;
+  font-size: 0.9rem;
+  text-align: right;
+  color: #d9d9d9;
+}
+
 @media (min-width: 960px) {
   .navbar-toggler {
     display: none;
   }
   
-  .collapse {
+  .navbar-menu {
+    display: flex;
+    flex-direction: column;
+  }
+  
+  .navbar-menu, nav {
+    flex: 1 0 auto;
+  }
+  
+  .navbar-menu.collapse {
     /* Never collapse the sidebar for wide screens */
-    display: block;
+    display: flex;
+  }
+  
+  footer {
+    margin: 0.25rem 0;
+    text-align: center;
   }
 }
diff --git a/Server/Phantom.Server.Web/wwwroot/css/site.css b/Server/Phantom.Server.Web/wwwroot/css/site.css
index 68fdc85..a231d8f 100644
--- a/Server/Phantom.Server.Web/wwwroot/css/site.css
+++ b/Server/Phantom.Server.Web/wwwroot/css/site.css
@@ -18,10 +18,12 @@
   }
   
   .sidebar {
+    display: flex;
+    flex-direction: column;
     position: sticky;
     top: 0;
     width: 250px;
-    height: 100vh;
+    min-height: 100vh;
   }
 }
 
diff --git a/Server/Phantom.Server/Program.cs b/Server/Phantom.Server/Program.cs
index 7646b6b..3cb4b74 100644
--- a/Server/Phantom.Server/Program.cs
+++ b/Server/Phantom.Server/Program.cs
@@ -1,4 +1,5 @@
-using Microsoft.EntityFrameworkCore;
+using System.Reflection;
+using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.DependencyInjection;
 using Phantom.Common.Logging;
 using Phantom.Server;
@@ -22,7 +23,10 @@ PosixSignals.RegisterCancellation(cancellationTokenSource, static () => {
 });
 
 try {
+	var fullVersion = AssemblyAttributes.GetFullVersion(Assembly.GetExecutingAssembly());
+	
 	PhantomLogger.Root.InformationHeading("Initializing Phantom Panel server...");
+	PhantomLogger.Root.Information("Server version: {Version}", fullVersion);
 	
 	var (webServerHost, webServerPort, webBasePath, rpcServerHost, rpcServerPort, sqlConnectionString) = Variables.LoadOrExit();
 
@@ -55,7 +59,7 @@ try {
 	PhantomLogger.Root.Information("Your administrator token is: {AdministratorToken}", administratorToken);
 	PhantomLogger.Root.Information("For administrator setup, visit: {HttpUrl}{SetupPath}", webConfiguration.HttpUrl, webConfiguration.BasePath + "setup");
 
-	var serviceConfiguration = new ServiceConfiguration(TokenGenerator.GetBytesOrThrow(administratorToken), cancellationTokenSource.Token);
+	var serviceConfiguration = new ServiceConfiguration(fullVersion, TokenGenerator.GetBytesOrThrow(administratorToken), cancellationTokenSource.Token);
 	var webConfigurator = new WebConfigurator(serviceConfiguration, taskManager, agentToken);
 	var webApplication = await WebLauncher.CreateApplication(webConfiguration, webConfigurator, options => options.UseNpgsql(sqlConnectionString, static options => {
 		options.CommandTimeout(10).MigrationsAssembly(typeof(ApplicationDbContextDesignFactory).Assembly.FullName);
diff --git a/Utils/Phantom.Utils.Runtime/AssemblyAttributes.cs b/Utils/Phantom.Utils.Runtime/AssemblyAttributes.cs
new file mode 100644
index 0000000..db1794f
--- /dev/null
+++ b/Utils/Phantom.Utils.Runtime/AssemblyAttributes.cs
@@ -0,0 +1,9 @@
+using System.Reflection;
+
+namespace Phantom.Utils.Runtime; 
+
+public static class AssemblyAttributes {
+	public static string GetFullVersion(Assembly assembly) {
+		return assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion.Replace('+', '/') ?? string.Empty;
+	}
+}