Modern, SEO-first CMS built on Laravel 11 with a modular monolith architecture.
TestoCMS combines a modular monolith core with Content and Admin APIs, RBAC, block-based pages, a WYSIWYG editor, comprehensive SEO tools (sitemap, robots, canonicals), LLM draft generation, and full-page caching.
- Built on Laravel 11 (PHP 8.2+): Modern, secure, and fast.
- Modular Monolith: Extensible architecture (
app/Modules/*) for easy customization and decoupled features. - Content Model: Posts, Pages, Categories, and Assets with localizations.
- SEO Core: Canonical URLs, robots directives, slug history/redirects, XML sitemaps, and RSS feeds.
- Headless & Monolith APIs:
- Public Read-only Content API (
/api/content/v1/*) - Private Admin Write API (
/api/admin/v1/*)
- Public Read-only Content API (
- First-run Setup Wizard: Interactive installation experience via web or CLI.
- Auth & Security:
- Session auth for the
/admininterface - Sanctum Personal Access Tokens for API
- Spatie Roles & Permissions, Policies, and Audit Logs
- Strict HTML sanitization and CSP/security headers
- Session auth for the
- LLM Integration:
- Support for multiple providers (OpenAI, Anthropic) for draft generation.
- Operations:
- Publish scheduling (Cron or fallback via web requests)
- Content revisions and preview tokens
- OpenAPI: Baseline spec available in
openapi/openapi.yaml
TestoCMS supports shared hosting as the primary production path, Docker on VPS as a secondary production path, and separate local development tooling. The bundled local Docker stack is not the same thing as the production Docker/VPS profile.
Recommended production path for v1.
- Download the latest
testocms-vX.Y.Z-shared-hosting.zipfrom GitHub Releases. - Upload and unpack it above
public_htmlso the application lives in~/testocms. - Copy the contents of
html_public/intopublic_html/or makepublic_htmla symlink to~/testocms/html_public. - If the application directory is not named
testocms, updatepublic_html/bootstrap_path.phpwith the absolute app path. - Create an empty database and database user in your hosting control panel.
- Open the site in a browser and complete the setup wizard.
- Add a cron job for
php artisan schedule:run.
π For a full step-by-step generic guide including cron jobs and optimization, see docs/shared-hosting-deploy.md.
Production option for your own VPS with Docker Compose. This is separate from the local development stack.
- Prepare a production
.envfrom the VPS template:cp .env.vps.example .env
- Set your domain, secrets, and database password in
.env. - Start the VPS stack:
docker compose -f docker-compose.vps.yml up -d --build
- Complete installation through the web setup wizard or via CLI:
docker compose -f docker-compose.vps.yml exec app php artisan cms:setup docker compose -f docker-compose.vps.yml exec app php artisan storage:link docker compose -f docker-compose.vps.yml exec app php artisan config:cache docker compose -f docker-compose.vps.yml exec app php artisan route:cache docker compose -f docker-compose.vps.yml exec app php artisan view:cache
π Production Docker runbook: docs/docker-vps.md.
- Prepare your local Docker env:
cp .env.docker.example .env.docker
- Build and start the local stack:
docker compose up --build -d
- Open:
- Frontend:
http://localhost:8080 - Admin Login:
http://localhost:8080/admin/login
- Frontend:
π Local Docker guide: docs/docker.md.
- Install Composer and NPM dependencies:
composer install npm ci && npm run build - Start the local server:
php artisan serve
- Open your local site (e.g.,
http://127.0.0.1:8000). - The Setup Wizard will launch immediately to help you configure your local
.env, database, and admin account.CLI Alternative: You can run
php artisan cms:setupto run the interactive installer in your terminal instead of the browser.
The backend interface is accessible at /admin/login. Included admin UI sections:
- Dashboard
- Pages (CRUD, publishing, scheduling, previews)
- Posts (CRUD, categories, assets, publishing, scheduling, previews)
- Categories (CRUD)
- Assets (Upload, metadata, inline injection)
- Audit Log
# Interactive CMS Setup (Web wizard alternative)
php artisan cms:setup
# Run PHPUnit tests
php artisan test
# Rebuild DB with fresh migrations and seeds
php artisan migrate:fresh --seed
# Manually trigger the publish scheduler
php artisan cms:publish-due
# Create an API token (PAT) with granular scopes
php artisan cms:token:create <admin-email> integration --abilities=posts:write,pages:write,llm:generateGET /api/content/v1/postsGET /api/content/v1/posts/{slug}GET /api/content/v1/pagesGET /api/content/v1/categoriesGET /api/content/v1/assets
If CMS_CONTENT_API_KEY is set, authenticate by passing the key via the X-API-Key header or ?key= query param.
- CRUD endpoints for posts, pages, categories, and assets.
- Workflow operations:
publish,unpublish,schedule. - LLM generation:
POST /api/admin/v1/llm/generate-postPOST /api/admin/v1/llm/generate-pagePOST /api/admin/v1/llm/generate-seo
Requires a Sanctum bearer token belonging to a user with the corresponding RBAC permissions.
TestoCMS has a robust built-in OTA (Over-The-Air) update system located in the Admin Panel under Settings -> Updates.
To leverage this and avoid contradictions when self-hosting:
- When you push a new release tag (
v1.0.1) to your GitHub repository, the included GitHub Actions workflow (.github/workflows/release.yml) will automatically compile frontend assets, remove dev dependencies, and build a production-ready.ziparchive. - Download this
.zipfrom the GitHub Releases page. - In your TestoCMS Admin panel, go to Settings -> Updates -> Upload Manual Package.
- Upload the zip file. The CMS will safely back up your current state, apply the new files, run necessary migrations, and verify the installation.
If anything goes wrong, you can safely rollback from the same interface.
app/Modules/Core: Contracts, DTOs, and core baseline servicesapp/Modules/Content: Block renderers, slug resolvers, content domain logicapp/Modules/SEO: SEO resolving and structured JSON-LD data factoryapp/Modules/LLM: Model providers (openai,anthropic) and gatewayapp/Modules/Ops: System audit logging and scheduling tasksapp/Modules/Caching: Full-page caching mechanismapp/Modules/I18n: Locale resolution and content translation
- Current Laravel vendor config may emit PHP 8.5 deprecation notices for
PDO::MYSQL_ATTR_SSL_CA. This is an upstream behavior and does not block functionality. - Tests (and Github Actions) run predominantly on an SQLite in-memory database to verify framework integrity.
- Generate and store your own secrets:
APP_KEY,CMS_CONTENT_API_KEY, database credentials, admin password, mail credentials, and LLM keys. - Keep
CMS_SEED_DEMO_CONTENT=falseoutside local development. - Shared hosting baseline uses
QUEUE_CONNECTION=syncplus cron forschedule:run. - Docker/VPS baseline uses
QUEUE_CONNECTION=databaseplus a supervised queue worker. - Configure backups, monitoring, and log shipping before exposing the admin publicly.
- Treat
docker-compose.ymlas local-only. Usedocker-compose.vps.ymlonly for the Docker/VPS production path.
- Public bugs and feature requests: GitHub Issues
- Private / commercial / maintainer contact: me@ilindberg.ru
- Security reports: follow SECURITY.md and use private email disclosure, not public issues
TestoCMS source code is commercially usable under the Apache-2.0 license.
The TestoCMS name, logo, and branding are governed separately by TRADEMARKS.md. Public forks and redistributions should preserve attribution notices and use factual wording such as Based on TestoCMS rather than presenting themselves as the official TestoCMS product.
Official SVG brand assets used by this repository live in html_public/brand together with html_public/favicon.svg.