Deployment Configuration and Script
- Front End Cleanup
This commit is contained in:
@@ -2,6 +2,7 @@ using DeepDrftContent;
|
|||||||
using DeepDrftContent.FileDatabase.Services;
|
using DeepDrftContent.FileDatabase.Services;
|
||||||
using DeepDrftContent.Middleware;
|
using DeepDrftContent.Middleware;
|
||||||
using DeepDrftContent.Models;
|
using DeepDrftContent.Models;
|
||||||
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
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>();
|
var apiKeySettings = builder.Configuration.GetSection(nameof(ApiKeySettings)).Get<ApiKeySettings>();
|
||||||
if (apiKeySettings is null) { throw new Exception("API key settings are not configured"); }
|
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();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
|
// Use forwarded headers before other middleware
|
||||||
|
app.UseForwardedHeaders();
|
||||||
|
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.MapOpenApi();
|
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.UseCors("ContentApiPolicy");
|
||||||
app.UseApiKeyAuthentication(apiKeySettings.ApiKey);
|
app.UseApiKeyAuthentication(apiKeySettings.ApiKey);
|
||||||
|
|||||||
@@ -7,6 +7,13 @@
|
|||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"CorsSettings": {
|
"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)
|
public async Task<TrackMediaResponse> GetTrackMedia(string trackId)
|
||||||
{
|
{
|
||||||
var response = await _http.GetAsync($"api/track/{trackId}");
|
var response = await _http.GetAsync($"track/{trackId}");
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
var contentLength = response.Content.Headers.ContentLength ?? 0;
|
var contentLength = response.Content.Headers.ContentLength ?? 0;
|
||||||
|
|||||||
@@ -13,14 +13,12 @@
|
|||||||
SelectedTrack="_selectedTrack"
|
SelectedTrack="_selectedTrack"
|
||||||
SelectedTrackChanged="@PlayTrack"/>
|
SelectedTrackChanged="@PlayTrack"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="tracks-footer">
|
<div class="tracks-footer py-4">
|
||||||
<div class="py-4">
|
<MudPagination Count="@ViewModel.Page.TotalPages"
|
||||||
<MudPagination Count="@ViewModel.Page.TotalPages"
|
Selected="@ViewModel.Page.Page"
|
||||||
Selected="@ViewModel.Page.Page"
|
SelectedChanged="@SetPage"
|
||||||
SelectedChanged="@SetPage"
|
BoundaryCount="2"
|
||||||
BoundaryCount="2"
|
MiddleCount="3"/>
|
||||||
MiddleCount="3"/>
|
|
||||||
</div>
|
|
||||||
<AudioPlayerBar AudioPlaybackEngine="AudioPlaybackEngine" />
|
<AudioPlayerBar AudioPlaybackEngine="AudioPlaybackEngine" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,5 +24,8 @@
|
|||||||
.tracks-footer {
|
.tracks-footer {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
justify-items: center;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
}
|
}
|
||||||
@@ -4,5 +4,8 @@
|
|||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ApiUrls": {
|
||||||
|
"ContentApi": "https://localhost:54493/api"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ApiUrls": {
|
"ApiUrls": {
|
||||||
"ContentApi": "https://localhost:54493"
|
"ContentApi": "https://media.deepdrft.com/api"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,26 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<Folder Include="wwwroot\js\" />
|
<Folder Include="wwwroot\js\" />
|
||||||
<Content Update="Interop\webaudio.js">
|
</ItemGroup>
|
||||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<ItemGroup>
|
||||||
</Content>
|
<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>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
+20
-1
@@ -2,6 +2,7 @@ using DeepDrftWeb;
|
|||||||
using DeepDrftWeb.Client.Services;
|
using DeepDrftWeb.Client.Services;
|
||||||
using MudBlazor.Services;
|
using MudBlazor.Services;
|
||||||
using DeepDrftWeb.Components;
|
using DeepDrftWeb.Components;
|
||||||
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
@@ -27,9 +28,21 @@ builder.Services.AddRazorComponents()
|
|||||||
.AddInteractiveServerComponents()
|
.AddInteractiveServerComponents()
|
||||||
.AddInteractiveWebAssemblyComponents();
|
.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();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
|
// Use forwarded headers before other middleware
|
||||||
|
app.UseForwardedHeaders();
|
||||||
|
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.UseWebAssemblyDebugging();
|
app.UseWebAssemblyDebugging();
|
||||||
@@ -39,7 +52,13 @@ else
|
|||||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
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.
|
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||||
app.UseHsts();
|
app.UseHsts();
|
||||||
app.UseHttpsRedirection();
|
|
||||||
|
// Only use HTTPS redirection if not behind a reverse proxy
|
||||||
|
var disableHttpsRedirection = app.Configuration.GetValue<bool>("ForwardedHeaders:DisableHttpsRedirection");
|
||||||
|
if (!disableHttpsRedirection)
|
||||||
|
{
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseAntiforgery();
|
app.UseAntiforgery();
|
||||||
|
|||||||
@@ -5,5 +5,8 @@
|
|||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"DetailedErrors": true
|
"DetailedErrors": true,
|
||||||
|
"ApiUrls": {
|
||||||
|
"ContentApi": "https://localhost:54493/api"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
"DefaultConnection": "Data Source=../Database/deepdrft.db"
|
"DefaultConnection": "Data Source=../Database/deepdrft.db"
|
||||||
},
|
},
|
||||||
"ApiUrls": {
|
"ApiUrls": {
|
||||||
"ContentApi": "https://localhost:54493"
|
"ContentApi": "https://localhost:12777/api"
|
||||||
|
},
|
||||||
|
"ForwardedHeaders": {
|
||||||
|
"DisableHttpsRedirection": "true"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,11 @@
|
|||||||
"outDir": "wwwroot/js"
|
"outDir": "wwwroot/js"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"Interop/**/*"
|
"**/*.ts"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules"
|
"node_modules",
|
||||||
|
"bin/**/*",
|
||||||
|
"obj/**/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user