Docs Getting Started

Getting Started

Get Contento CMS up and running in under five minutes.

Contento is an open-source content management system built on .NET 10 and PostgreSQL. It ships as a traditional server-rendered admin panel and a fully featured headless JSON API, so you can power any front end — a Next.js app, a static site generator, a mobile app, or the built-in themed blog.

Key highlights:

  • Markdown-first editor with live preview and autosave
  • Full REST API with public content delivery and authenticated management endpoints
  • Theme system with CSS variables and 8 built-in themes
  • Plugin system powered by a sandboxed JavaScript engine (Jint)
  • WordPress and Markdown import/export
  • Full-text search with PostgreSQL ts_vector
  • Threaded comments with honeypot spam protection
  • Media library with image, PDF, and video support
  • Hierarchical categories and tag-based taxonomy
  • Audit log for tracking all content changes
  • Newsletter management with subscriber signup and campaign editor
  • Stripe-powered membership with plans, content gating, and billing portal
  • Multi-site support with domain-based routing
  • Task scheduler with cron-based automation
  • Custom post types with JSON field schemas
  • SEO service with JSON-LD structured data and sitemap generation
  • AI-powered content generation and SEO analysis
  • Automatic responsive image variants (640w, 1024w, 1536w WebP)
  • Spam protection with AI scoring and configurable auto-approve threshold

Prerequisites

Dependency Version Required
.NET SDK 10.0 or later Yes
PostgreSQL 14 or later Yes
Redis 7.x Optional (caching)
Node.js 18+ (for Tailwind CSS build) Optional (development)

Installation

1. Clone the repository

# Clone via HTTPS
git clone https://github.com/plsft/contento.git
cd contento

2. Restore dependencies

dotnet restore

3. Configure connection strings

Create an appsettings.Development.json file in the src/Contento.Web directory (or set environment variables):

{
  "ConnectionStrings": {
    "DefaultConnection": "Host=localhost;Port=5432;Database=contento;Username=postgres;Password=yourpassword"
  },
  "Contento": {
    "ApiSigningKey": "your-secret-key-at-least-32-characters-long"
  },
  "Redis": {
    "ConnectionString": "localhost:6379"
  },
  "Stripe": {
    "SecretKey": "sk_test_...",
    "PublishableKey": "pk_test_...",
    "WebhookSecret": "whsec_..."
  },
  "Email": {
    "SmtpHost": "smtp.example.com",
    "SmtpPort": "587",
    "FromAddress": "noreply@yourdomain.com"
  }
}
Important: In production, always set Contento:ApiSigningKey to a strong, unique secret. The default fallback key is insecure and should never be used in production.

4. Initialize the database

Contento uses Bowtie for automatic schema management. On first run, it creates all tables and seeds default data automatically:

cd src/Contento.Web
dotnet run

The application starts at https://localhost:5001 (or http://localhost:5000).

Tip: The database schema is managed automatically via Bowtie. You do not need to run any migration commands. On first startup, Contento creates all 21 tables and seeds the default site, admin user, and built-in themes.

First Steps

1. Log in to the admin panel

Navigate to https://localhost:5001/admin and log in with the default credentials:

Field Value
Email admin@contento.local
Password Admin1234
Change this password immediately. Navigate to the Users section in admin and update the default admin account credentials before deploying to production.

2. Create your first post

  1. Click Posts in the sidebar, then click New Post.
  2. Enter a title and write your content in Markdown. The live preview updates as you type.
  3. Add tags, choose a category, and optionally upload a cover image.
  4. Click Publish to make the post live.

3. Configure site settings

Go to Settings in the admin sidebar to configure:

  • Site name — Displayed in the header, feeds, and metadata
  • Tagline — A short description of your site
  • Locale — e.g., en-US, ja-JP
  • Timezone — e.g., UTC, America/New_York, Asia/Tokyo

4. Choose a theme

Navigate to Themes and activate one of the 8 built-in themes. Each theme sets CSS variables that control fonts, colors, and spacing across the public site.

5. Configure Stripe (optional)

If you want to enable paid memberships, configure your Stripe keys in the environment variables or appsettings.json. Then navigate to Membership in the admin sidebar to create your first plan.

Project Structure

contento/
|-- src/
|   |-- Contento.Core/            # Domain models, interfaces
|   |   |-- Models/                # 17 entity models (Post, User, Theme, Subscriber, ...)
|   |   |-- Interfaces/            # 22 service interfaces
|   |
|   |-- Contento.Services/        # Service implementations (23 files)
|   |
|   |-- Contento.Plugins/         # Jint-based plugin host
|   |
|   |-- Contento.Web/             # ASP.NET 10 web application
|   |   |-- Controllers/          # 21 API controllers (113 endpoints)
|   |   |-- Pages/Admin/          # 21+ Razor admin pages
|   |   |-- Styles/app.css        # CSS design system
|   |
|   |-- Contento.Tests/           # 428 tests (NUnit + Moq + Bogus)
|
|-- marketing/                    # Marketing site and docs

Environment Variables

Contento reads configuration from appsettings.json, environment variables, and user secrets. Environment variables follow the __ (double underscore) convention for nested keys.

Variable Description Default
ConnectionStrings__DefaultConnection PostgreSQL connection string Required
Contento__ApiSigningKey HMAC-SHA256 signing key for API tokens Insecure default
Redis__ConnectionString Redis connection string for caching Empty (disabled)
ASPNETCORE_ENVIRONMENT Runtime environment Production
ASPNETCORE_URLS Listening URLs http://+:5000
Serilog__MinimumLevel__Default Log level: Verbose, Debug, Information, Warning, Error, Fatal Information
Contento__MaxUploadSizeMb Maximum media upload size 10
Contento__AllowedOrigins Comma-separated CORS origins for headless mode *
Stripe__SecretKey Stripe API secret key for server-side operations Empty (disabled)
Stripe__PublishableKey Stripe publishable key for client-side checkout Empty (disabled)
Stripe__WebhookSecret Stripe webhook signing secret for event verification Empty
Email__SmtpHost SMTP server hostname for newsletter delivery Empty (disabled)
Email__SmtpPort SMTP server port 587
Email__FromAddress Sender email address for newsletters Empty

Next Steps