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/inkwell
$ cd inkwell

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/inkwell && cd inkwell
$ 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;
    }
}
Common questions

Frequently asked about setup.

What .NET version does Inkwell require?
Inkwell requires .NET 8.0 or later. The SDK is needed for building and publishing; the runtime alone is sufficient for hosting. Any server running .NET 8+ on Linux, Windows Server, or macOS can host Inkwell without additional dependencies.
Which databases does Inkwell support?
Inkwell supports PostgreSQL 14 or later, which is recommended for production, and SQLite, which is ideal for development and single-author setups. The database provider is set via the standard Entity Framework Core connection string in appsettings.json. Each tenant in a multi-tenant install uses an isolated database schema.
How do I upgrade Inkwell to a newer version?
Pull the latest source from GitHub, run dotnet ef database update to apply any new migrations, then rebuild with dotnet publish and redeploy the output. The migration step is safe to run while the previous version is still serving traffic. Always read the changelog entry for breaking-change notes before upgrading across a major version boundary.
How do I add a second blog to an existing Inkwell install?
Inkwell is multi-tenant by default — one install serves unlimited publications. In the admin panel, create a new tenant and map a domain or subdomain to it. Each tenant gets its own isolated database schema, layout, preset, and author list. No second deployment is required.
Can I deploy Inkwell with Docker?
Yes. The repository includes a Dockerfile and a docker-compose.yml with Caddy as a reverse proxy and PostgreSQL as the database. Copy .env.example to .env, set your domain and secrets, then run docker compose up -d from the project root. Compose handles TLS via Caddy's automatic HTTPS.
How do I configure email (SMTP) in Inkwell?
Add your SMTP credentials to the Email section of appsettings.json — Host, Port, Username, Password, and FromAddress. Inkwell uses the .NET MailKit library and supports TLS and STARTTLS. For local development, any SMTP relay or a free Mailtrap.io account works without additional setup.