Serving Static Files
Expose folders of files (HTML, CSS, JS, images, etc.) over HTTP using the static files service.
Prerequisites: see Introduction.
Full source
File: pwsh/tutorial/examples/3.1-Static-Routes.ps1
<#
Sample Kestrun Server on how to use static routes.
These examples demonstrate how to configure static routes in a Kestrun server.
FileName: 3.1-Static-Routes.ps1
#>
param(
[int]$Port = 5000,
[IPAddress]$IPAddress = [IPAddress]::Loopback
)
# Initialize Kestrun root directory
# the default value is $PWD
# This is recommended in order to use relative paths without issues
Initialize-KrRoot -Path $PSScriptRoot
# Create a new Kestrun server
New-KrServer -Name "Simple Server"
# Add a listener on the configured port and IP address
Add-KrEndpoint -Port $Port -IPAddress $IPAddress
# Add a static files service
Add-KrStaticFilesMiddleware -RequestPath '/assets' -RootPath '.\Assets\wwwroot' -ServeUnknownFileTypes
# Enable Kestrun configuration
Enable-KrConfiguration
# Start the server asynchronously
Start-KrServer
Step-by-step
- Install & initialize:
Initialize-KrRoot -Path $PSScriptRootsets a stable root so relative paths (like./Assets/wwwroot) resolve even when the script is launched from a different working directory.
- Create the server and listener (
New-KrServer,Add-KrEndpoint) on127.0.0.1:5000. - Register the static file service with
Add-KrStaticFilesService:-RequestPath '/assets'makes files available under that URL prefix.-RootPath '.\Assets\wwwroot'points to a folder (relative to the initialized root) that contains the files to serve.-ServeUnknownFileTypesallows files with extensions not in the default MIME map to be served (they’ll use a defaultapplication/octet-streamunless overridden). Use cautiously; omit in production unless you need it.
- Enable configuration (
Enable-KrConfiguration) so registered services/routes are materialized. - Start processing requests asynchronously with
Start-KrServer.
Folder layout (example)
Create a simple set of files to verify hosting:
examples/PowerShell/Tutorial/Assets/wwwroot/
index.html
css/site.css
images/logo.png
docs/readme.txt
Sample contents:
index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Kestrun Static Sample</title>
<link rel="stylesheet" href="/assets/css/site.css" />
</head>
<body>
<h1>Hello from static hosting</h1>
<p>Served by Kestrun.</p>
</body>
</html>
css/site.css
body { font-family: system-ui, Arial, sans-serif; margin: 2rem; }
h1 { color: #0d6efd; }
Try it
Save the sample locally so it’s easy to run. Copy the contents of pwsh/tutorial/examples/3.1-Static-Routes.ps1 into a new file in an empty working folder (for example, static-routes.ps1), then run:
# From your working folder
pwsh .\static-routes.ps1
curl http://127.0.0.1:5000/assets/index.html
curl http://127.0.0.1:5000/assets/css/site.css
Open in a browser: http://127.0.0.1:5000/assets/index.html
PowerShell requests:
Invoke-WebRequest -Uri 'http://127.0.0.1:5000/assets/index.html' | Select-Object -ExpandProperty Content
Invoke-WebRequest -Uri 'http://127.0.0.1:5000/assets/css/site.css' | Select-Object -ExpandProperty Content
Customizing behavior
Add-KrStaticFilesService supports additional parameters (see cmdlet help) you can use to:
- Change the request path prefix.
- Point to multiple folders (register the service multiple times with different roots/prefixes).
- Control caching headers (when supported) for performance.
- Allow serving of unknown extensions with
-ServeUnknownFileTypes(development / controlled scenarios). Prefer adding a proper content type mapping instead when possible.
Best practices
- Always call
Initialize-KrRootwhen your script relies on relative paths; this avoids surprises when running from another directory. - Keep static assets outside script roots if you plan to containerize; mount or copy them during build.
- Set far-future cache headers for versioned assets (e.g.,
/assets/app.123abc.js). - Consider a separate listener/port if you want to partition static + dynamic traffic (optional).
- Avoid
-ServeUnknownFileTypesin production unless absolutely required; limit exposed file types to reduce risk of unintentionally serving sensitive artifacts.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| 404 Not Found for /assets file | Path or filename mismatch | Verify the physical file exists under the specified RootPath and spelling matches (case sensitivity depends on OS). |
| 404 for all /assets requests | Wrong relative path root | Confirm Initialize-KrRoot points to a parent of Assets or use an absolute -RootPath. |
| Styles/images not loading in HTML | Incorrect relative URLs | Use absolute URLs beginning with /assets/... or correct relative pathing from the HTML file. |
| Changes not reflected | Browser caching | Hard refresh (Ctrl+F5) or add a cache-busting query string ?v=1. |
| Access denied errors | File permissions | Ensure read permissions for the process account on the asset files. |
References
- Initialize-KrRoot
- Add-KrStaticFilesService
- New-KrServer
- Add-KrEndpoint
- Enable-KrConfiguration
- Start-KrServer
Previous / Next
Go back to Route Groups or continue to File Server & Directory Browsing.