A lightweight, self-hosted blogging platform built with .NET 10 and Blazor Server.
- Markdown-based content: Write posts in Markdown with live preview
- Image management: Upload and manage images stored in the database
- Admin dashboard: Manage posts, images, and settings
- OpenTelemetry: Built-in observability with file-based telemetry export
- Cross-platform: Runs on Windows, Linux, and macOS
- CI/CD ready: GitHub Actions workflow for automated testing and deployment
- .NET 10 SDK or later
# Clone the repository
git clone https://github.com/yourusername/dotnetcms.git
cd dotnetcms/src
# Restore and run
dotnet restore MyBlog.slnx
cd MyBlog.Web
dotnet runThe application will start at http://localhost:5000 (or the next available port).
- Username:
admin - Password:
ChangeMe123!(or value ofMYBLOG_ADMIN_PASSWORDenvironment variable)
Important: The default password is only used when creating the initial admin user. Once the user exists, you must change the password through the website.
| Variable | Description | Default |
|---|---|---|
MYBLOG_ADMIN_PASSWORD |
Initial admin password (only used on first run) | ChangeMe123! |
ASPNETCORE_ENVIRONMENT |
Runtime environment | Production |
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=myblog.db"
},
"Authentication": {
"SessionTimeoutMinutes": 30,
"DefaultAdminPassword": "ChangeMe123!"
},
"Application": {
"Title": "MyBlog"
}
}The SQLite database is stored in a platform-specific location:
| Platform | Path |
|---|---|
| Linux | ~/.local/share/MyBlog/myblog.db |
| macOS | ~/Library/Application Support/MyBlog/myblog.db |
| Windows | %LOCALAPPDATA%\MyBlog\myblog.db |
The admin dashboard provides an overview of your blog with quick access to all management features.
- Create Post (
/admin/posts/new): Write a new blog post in Markdown - Edit Post (
/admin/posts/edit/{id}): Modify existing posts - Post List (
/admin/posts): View and manage all posts
- Upload Images (
/admin/images): Upload images to use in posts - Image Library: Browse and delete uploaded images
- Usage: Reference images in Markdown using
/api/images/{id}
Navigate to /admin/change-password to change your admin password:
- Enter your current password
- Enter your new password (minimum 8 characters)
- Confirm the new password
- Click "Change Password"
Note: The
MYBLOG_ADMIN_PASSWORDenvironment variable only affects the initial password when the admin user is first created. It does not override existing passwords.
The repository includes a GitHub Actions workflow that:
- Builds and tests on Windows, Linux, and macOS
- Deploys to your server via WebDeploy (on main/master/develop branches)
Set these in your repository settings under Settings > Secrets and variables > Actions:
| Secret | Description | Example |
|---|---|---|
WEBSITE_NAME |
IIS site name | MyBlog |
SERVER_COMPUTER_NAME |
Server hostname | myserver.example.com |
SERVER_USERNAME |
WebDeploy username | deploy-user |
SERVER_PASSWORD |
WebDeploy password | (your password) |
| Variable | Description | Example |
|---|---|---|
MYBLOG_ADMIN_PASSWORD |
Initial admin password | (strong password) |
Note:
MYBLOG_ADMIN_PASSWORDshould be set as a secret, not a variable, if you want it to remain hidden in logs.
# Publish for Windows
dotnet publish src/MyBlog.Web/MyBlog.Web.csproj -c Release -o ./publish -r win-x64
# Publish for Linux
dotnet publish src/MyBlog.Web/MyBlog.Web.csproj -c Release -o ./publish -r linux-x64Copy the contents of ./publish to your server.
- Install the .NET 10 Hosting Bundle
- Create a new IIS site pointing to your publish folder
- Set the Application Pool to "No Managed Code"
- Ensure the Application Pool identity has write access to the database directory
This occurs when the application is running and DLLs are locked.
Solution: The workflow now includes -enableRule:AppOffline which automatically:
- Creates
app_offline.htmto stop the application - Waits for the app to release file locks
- Deploys the new files
- Removes
app_offline.htmto restart the app
The environment variable only works when no users exist in the database.
To reset with a new password:
- Stop the application
- Delete the database file (see Database Location above)
- Set
MYBLOG_ADMIN_PASSWORDto your desired password - Start the application
Or, log in with the current password and use /admin/change-password.
SQLite can have locking issues with concurrent access.
Solutions:
- Ensure only one instance of the application is running
- Check that no database tools have the file open
- Verify file permissions on the database directory
cd src
dotnet test MyBlog.slnxsrc/
├── MyBlog.Core/ # Domain models and interfaces
├── MyBlog.Infrastructure/ # Data access, services
├── MyBlog.Web/ # Blazor Server application
└── MyBlog.Tests/ # xUnit test project
- Define interfaces in
MyBlog.Core/Interfaces - Implement in
MyBlog.Infrastructure/Services - Add UI in
MyBlog.Web/Components/Pages - Write tests in
MyBlog.Tests
| Endpoint | Method | Description |
|---|---|---|
/api/images/{id} |
GET | Retrieve an image by ID |
MIT License - see LICENSE for details.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request