Skip to content
Documentation

Everything you need to run Inkwell.

Guides, configuration reference, and deployment recipes — all in one place. Inkwell is simple by design; the docs stay short by policy.

Use Ctrl+F to search within this page

Overview

Inkwell is a free, open-source, self-hosted blogging platform built on .NET 8. It ships as a single ASP.NET Core binary — no Node, no PHP, no external build pipeline. Install it on any server you control, point a domain at it, and write.

Philosophy. Inkwell is deliberately small. It ships the things you actually need and almost nothing else. If a feature isn't here, that's usually intentional.

Core concepts

  • Tenants — one Inkwell install can host many blogs. Each tenant has its own domain, Layout, Preset, authors, and database schema.
  • Layouts — structural templates: Magazine, Journal, Notebook, Studio.
  • Presets — surface styles (colour + type): Cream, Ink, Linen, Paper.
  • Desk — the keyboard-first Markdown editor with live preview, autosave, footnotes, and pull quotes.

Requirements

RuntimeMinimum version
.NET8.0 or later
DatabasePostgreSQL 14+ or SQLite (dev only)
OSLinux, Windows Server, macOS
Reverse proxynginx, Caddy, Apache, or IIS (recommended)

Installation

1. Clone the repository

$ git clone https://github.com/marutisoftwaresolutions/blog
$ cd blog

2. Restore packages

$ dotnet restore

3. Configure (see Configuration)

Edit appsettings.json or use environment variables for secrets.

4. Run database migrations

$ dotnet ef database update

5. Run

$ dotnet run --configuration Release
First-run setup. On the first boot, Inkwell creates the default tenant and admin account. Visit /desk/setup to complete configuration.

Quick start

Prefer a fast path? These three commands get you to a running instance with SQLite and a default tenant:

$ git clone https://github.com/marutisoftwaresolutions/blog && cd blog
$ dotnet ef database update
$ dotnet run

Open http://localhost:5000 and sign in with the credentials printed to the console on first boot.

Configuration

All settings live in appsettings.json. Override any value with an environment variable using the double-underscore convention: Inkwell__Tenants__0__Host.

Root structure

{
  "Inkwell": {
    "Tenants": [ ... ],
    "Database": { ... },
    "Email": { ... }
  }
}

Multi-tenant setup

{
  "Inkwell": {
    "Tenants": [
      {
        "Host": "essays.example.com",
        "Layout": "Magazine",
        "Preset": "Cream"
      },
      {
        "Host": "notes.example.com",
        "Layout": "Notebook",
        "Preset": "Linen"
      }
    ]
  }
}

Database

KeyDefaultDescription
ProviderSqliteSqlite or Postgres
ConnectionStringin-memoryStandard ADO.NET connection string

Email (SMTP)

KeyDescription
Email:SmtpHostHostname of your SMTP server
Email:SmtpPortDefault 587 (STARTTLS)
Email:EnableSsltrue recommended
Email:SenderEmailFrom address
Email:RecipientEmailWhere inquiries are delivered
Email:UsernameSMTP auth username (leave blank if none)
Email:PasswordSMTP auth password — use a secret manager in production
Never commit credentials. Use dotnet user-secrets locally and environment variables or a vault in production.

Layouts & Presets

Inkwell separates structure (Layout) from surface (Preset). Pick one of each per tenant. Swap them without a rebuild or a migration.

Layouts

NameBest for
MagazineMulti-author publications with drop caps, bylines, departments
JournalSolo diarists — one voice, one column, dated entries
NotebookShort-form fragments, marginalia, public notes
StudioPortfolio-shaped blogs — visual first, long-form behind

Presets

NamePalette
CreamWarm off-white background, dark ink text
InkNear-black background, cream text — dark by default
LinenWarm linen, subtle texture, earthy tones
PaperPure white, high contrast, minimal

Custom themes

A Layout is a set of Razor partials in /Views/Layouts/{Name}/. A Preset is a CSS variable override block in /wwwroot/css/presets/{name}.css. Both are hot-reloaded in development. See the GitHub repository for a full theming guide.

Deployment: Linux / systemd

$ dotnet publish -c Release -o /opt/inkwell
$ sudo nano /etc/systemd/system/inkwell.service
[Unit]
Description=Inkwell Blog

[Service]
WorkingDirectory=/opt/inkwell
ExecStart=/opt/inkwell/Inkwell
Restart=always
RestartSec=10
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production

[Install]
WantedBy=multi-user.target
$ sudo systemctl enable --now inkwell

Deployment: Docker

A Dockerfile is included in the repository root. Build and run:

$ docker build -t inkwell .
$ docker run -d -p 8080:8080 \
    -e Inkwell__Database__ConnectionString="..." \
    --name inkwell inkwell

A docker-compose.yml with Postgres and Caddy (for automatic TLS) is available in /deploy/compose/.

Deployment: IIS

  1. Install the .NET 8 Hosting Bundle on the server.
  2. Publish: dotnet publish -c Release -o C:\inetpub\inkwell
  3. Create a new IIS site pointing to C:\inetpub\inkwell.
  4. Set the application pool to No Managed Code.
  5. Ensure the app pool identity has read/write access to the publish directory.

Reverse proxy (nginx)

server {
    listen 443 ssl;
    server_name essays.example.com;

    location / {
        proxy_pass         http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}