Deployment Configuration and Script

- Front End Cleanup
This commit is contained in:
daniel-c-harvey
2025-09-06 18:40:32 -04:00
parent 0951514778
commit a5b7ab041e
13 changed files with 169 additions and 21 deletions
+22
View File
@@ -2,6 +2,7 @@ using DeepDrftContent;
using DeepDrftContent.FileDatabase.Services;
using DeepDrftContent.Middleware;
using DeepDrftContent.Models;
using Microsoft.AspNetCore.HttpOverrides;
var builder = WebApplication.CreateBuilder(args);
@@ -35,13 +36,34 @@ builder.Configuration.AddJsonFile("environment/apikey.json", optional: false, re
var apiKeySettings = builder.Configuration.GetSection(nameof(ApiKeySettings)).Get<ApiKeySettings>();
if (apiKeySettings is null) { throw new Exception("API key settings are not configured"); }
// Configure forwarded headers for reverse proxy support
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
// Trust any proxy (nginx) - in production, specify known proxy networks
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
var app = builder.Build();
// Configure the HTTP request pipeline.
// Use forwarded headers before other middleware
app.UseForwardedHeaders();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
else
{
// Only use HTTPS redirection if not behind a reverse proxy
var forwardedProto = app.Services.GetService<IConfiguration>()?["ForwardedHeaders:DisableHttpsRedirection"];
if (string.IsNullOrEmpty(forwardedProto) || !bool.Parse(forwardedProto))
{
app.UseHttpsRedirection();
}
}
app.UseCors("ContentApiPolicy");
app.UseApiKeyAuthentication(apiKeySettings.ApiKey);
+8 -1
View File
@@ -7,6 +7,13 @@
},
"AllowedHosts": "*",
"CorsSettings": {
"AllowedOrigins": []
"AllowedOrigins": [
"https://localhost:12778",
"https://deepdrft.com",
"https://www.deepdrft.com"
]
},
"ForwardedHeaders": {
"DisableHttpsRedirection": "true"
}
}
@@ -25,7 +25,7 @@ public class TrackMediaClient
public async Task<TrackMediaResponse> GetTrackMedia(string trackId)
{
var response = await _http.GetAsync($"api/track/{trackId}");
var response = await _http.GetAsync($"track/{trackId}");
response.EnsureSuccessStatusCode();
var contentLength = response.Content.Headers.ContentLength ?? 0;
+1 -3
View File
@@ -13,14 +13,12 @@
SelectedTrack="_selectedTrack"
SelectedTrackChanged="@PlayTrack"/>
</div>
<div class="tracks-footer">
<div class="py-4">
<div class="tracks-footer py-4">
<MudPagination Count="@ViewModel.Page.TotalPages"
Selected="@ViewModel.Page.Page"
SelectedChanged="@SetPage"
BoundaryCount="2"
MiddleCount="3"/>
</div>
<AudioPlayerBar AudioPlaybackEngine="AudioPlaybackEngine" />
</div>
}
@@ -24,5 +24,8 @@
.tracks-footer {
flex: 0 0 auto;
padding: 8px 0;
justify-items: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}
@@ -4,5 +4,8 @@
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ApiUrls": {
"ContentApi": "https://localhost:54493/api"
}
}
+1 -1
View File
@@ -6,6 +6,6 @@
}
},
"ApiUrls": {
"ContentApi": "https://localhost:54493"
"ContentApi": "https://media.deepdrft.com/api"
}
}
+20 -4
View File
@@ -30,10 +30,26 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<Folder Include="wwwroot\js\" />
<Content Update="Interop\webaudio.js">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<TypeScriptCompile Include="Interop\webaudio.ts">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</TypeScriptCompile>
</ItemGroup>
<!-- Prevent TypeScript compilation issues during publish -->
<PropertyGroup>
<TypeScriptCompileOnSaveEnabled>false</TypeScriptCompileOnSaveEnabled>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
</PropertyGroup>
<!-- Only copy tsconfig.json to root output, not nested publish folders -->
<ItemGroup>
<None Update="tsconfig.json">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
+19
View File
@@ -2,6 +2,7 @@ using DeepDrftWeb;
using DeepDrftWeb.Client.Services;
using MudBlazor.Services;
using DeepDrftWeb.Components;
using Microsoft.AspNetCore.HttpOverrides;
var builder = WebApplication.CreateBuilder(args);
@@ -27,9 +28,21 @@ builder.Services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddInteractiveWebAssemblyComponents();
// Configure forwarded headers for reverse proxy support
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
// Trust any proxy (nginx) - in production, specify known proxy networks
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
var app = builder.Build();
// Configure the HTTP request pipeline.
// Use forwarded headers before other middleware
app.UseForwardedHeaders();
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
@@ -39,7 +52,13 @@ else
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
// Only use HTTPS redirection if not behind a reverse proxy
var disableHttpsRedirection = app.Configuration.GetValue<bool>("ForwardedHeaders:DisableHttpsRedirection");
if (!disableHttpsRedirection)
{
app.UseHttpsRedirection();
}
}
app.UseAntiforgery();
+4 -1
View File
@@ -5,5 +5,8 @@
"Microsoft.AspNetCore": "Warning"
}
},
"DetailedErrors": true
"DetailedErrors": true,
"ApiUrls": {
"ContentApi": "https://localhost:54493/api"
}
}
+4 -1
View File
@@ -10,6 +10,9 @@
"DefaultConnection": "Data Source=../Database/deepdrft.db"
},
"ApiUrls": {
"ContentApi": "https://localhost:54493"
"ContentApi": "https://localhost:12777/api"
},
"ForwardedHeaders": {
"DisableHttpsRedirection": "true"
}
}
+4 -2
View File
@@ -10,9 +10,11 @@
"outDir": "wwwroot/js"
},
"include": [
"Interop/**/*"
"**/*.ts"
],
"exclude": [
"node_modules"
"node_modules",
"bin/**/*",
"obj/**/*"
]
}
+72
View File
@@ -0,0 +1,72 @@
# start SSH agent and add key
eval $(ssh-agent -s)
ssh-add /c/.ssh/deepdrft_ed25519
CONTENT_PROJ="DeepDrftContent"
WEB_PROJ="DeepDrftWeb"
CONTENT_APP="deepdrft-content.tar.gz"
WEB_APP="deepdrft-web.tar.gz"
# Restore and Publish
dotnet publish $CONTENT_PROJ -c Release -f net9.0 -o $CONTENT_PROJ/publish -r linux-x64 -p:Platform="Any CPU" --verbosity normal
dotnet publish $WEB_PROJ -c Release -f net9.0 -o $WEB_PROJ/publish -r linux-x64 -p:Platform="Any CPU" --verbosity normal
# Check if migrations are needed
WEB_MIG="deepdrft-migrations.sql"
REMOTE="deepdrft@dch5.snailbird.net"
WEB_APPROOT="/deepdrft/web"
LATEST_MIGRATION=$(dotnet ef migrations list --project $WEB_PROJ --context DeepDrftContext --no-build | tail -1)
REMOTE_MIGRATION=$(ssh $REMOTE "sqlite3 $WEB_APPROOT/Database/deepdrft.db 'SELECT MigrationId FROM __EFMigrationsHistory ORDER BY MigrationId DESC LIMIT 1;'" 2>/dev/null || echo "")
if [ "$LATEST_MIGRATION" != "$REMOTE_MIGRATION" ]; then
echo "Generating migration script from $REMOTE_MIGRATION to $LATEST_MIGRATION..."
if [ -z "$REMOTE_MIGRATION" ]; then
dotnet ef migrations script --project $WEB_PROJ --context DeepDrftContext --output $WEB_MIG --verbose --no-build
else
dotnet ef migrations script $REMOTE_MIGRATION --project $WEB_PROJ --context DeepDrftContext --output $WEB_MIG --verbose --no-build
fi
APPLY_MIGRATIONS=true
else
echo "Database is up to date."
APPLY_MIGRATIONS=false
fi
# Compress published files
tar -czf $CONTENT_APP -C $CONTENT_PROJ/publish .
tar -czf $WEB_APP -C $WEB_PROJ/publish .
# Deploy
CONTENT_APPROOT="/deepdrft/api/content"
ssh $REMOTE "rm -rf $CONTENT_APPROOT/bin/*"
ssh $REMOTE "rm -rf $WEB_APPROOT/bin/*"
scp $CONTENT_APP $REMOTE:$CONTENT_APPROOT/$CONTENT_APP
if [ "$APPLY_MIGRATIONS" = true ]; then
scp $WEB_MIG $REMOTE:$WEB_APPROOT/$WEB_MIG
fi
scp $WEB_APP $REMOTE:$WEB_APPROOT/$WEB_APP
ssh $REMOTE "tar -xzf $CONTENT_APPROOT/$CONTENT_APP -C $CONTENT_APPROOT/bin && rm $CONTENT_APPROOT/$CONTENT_APP"
ssh $REMOTE "tar -xzf $WEB_APPROOT/$WEB_APP -C $WEB_APPROOT/bin && rm $WEB_APPROOT/$WEB_APP"
# Apply Local Environment
ssh $REMOTE "cp $CONTENT_APPROOT/environment/* $CONTENT_APPROOT/bin/environment"
# Apply database migrations on server
if [ "$APPLY_MIGRATIONS" = true ]; then
ssh $REMOTE "sqlite3 $WEB_APPROOT/Database/deepdrft.db < $WEB_APPROOT/$WEB_MIG && rm $WEB_APPROOT/$WEB_MIG"
fi
# Restart the service
ssh $REMOTE "$CONTENT_APPROOT/restart.sh"
ssh $REMOTE "$WEB_APPROOT/restart.sh"
# Clean up
rm -rf ./$CONTENT_PROJ/publish
rm -f ./$CONTENT_APP
rm -rf ./$WEB_PROJ/publish
rm -f ./$WEB_APP
if [ "$APPLY_MIGRATIONS" = true ]; then
rm -f ./$WEB_MIG
fi
ssh-agent -k