OpenPost: a self-hostable social scheduling suite with an AGPL twist
Create, adapt, schedule, and track social posts. Open-source, hosted or self-hosted.
At a glance
- What is it?
- OpenPost is an open-source social media suite that covers writing, per-platform adaptation, scheduling, media editing, workflows, analytics and an inbox, and it can be self-hosted from a container image or used hosted. It suits teams that want to own their posting stack, and the AGPL-3.0 licence is the first thing a company will have to think about.
- Who is it for?
- OpenPost is a serious candidate for a team that has outgrown a single social scheduling tool and wants scheduling, media editing, workflows, an inbox and analytics in one self-hosted application, because the feature list covers the whole loop from a GitHub release to a published post and the container deployment is a single compose file.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One application for the whole posting loop, not just a queue
OpenPost presents itself as an open-source alternative to Buffer, Canva and CapCut, and the ambition is visible in the feature list. It is described as a place to write posts, design images and carousels, edit videos, and schedule content in one app, with a choice between self-hosting and OpenPost Hosted.
The features are grouped by the job they do rather than by technical layer. Accounts are connected into one workspace, with each provider keeping its own capabilities and publishing limits, which is the acknowledgement that no two networks behave alike. Composition is per platform: write posts and threads, adjust text and media for each account, preview each version, and save account groups as Social Sets for reuse.
Scheduling has a calendar and a queue, where you pick a publishing time or the next free slot, stagger publishing across accounts, and get reminders when the queue runs low. The media library keeps reusable images, videos, fonts and brand assets, organised with tags, collections and favorites, so an asset can be attached without being uploaded again, and there is a meme maker built on the same library. The inbox reads and replies to supported comments and direct messages without switching apps, and analytics compares post results across accounts and can seed a new draft from a previous post.
Two features stand out as less common in this category. Workflows turn GitHub releases, RSS feeds and scheduled prompts into drafts, with steps connected on a visual canvas, AI or conditions added, a review step before scheduling, and each run inspectable. And auto repost sets delays and engagement rules for native reposts on supported networks, with per-post overrides.
Automation reaches the stack through an SDK, a CLI, MCP and n8n
The automation story is the one that separates a hosted tool from a platform. The project documents an API, an SDK, a CLI, MCP and n8n support, letting you create drafts, schedule posts and check publishing results from your scripts, your agents or n8n workflows. Both a TypeScript SDK and a CLI are published on npm, as @getopenpost/sdk and @getopenpost/cli, and the API reference documents the endpoints.
That combination is what makes the self-hosted version usable in a real organisation. A scheduled release in a repository becomes a draft through a workflow, a script reviews the result, and the post goes out through the same scheduler a human would use. The readme also lists AI writing and ideas, where you generate ideas, compare draft directions and adapt posts for selected platforms, with a review step before publishing, and notes that the AI writing is optional.
The topics on the repository include mcp-server, which fits the pattern: exposing the posting API to an agent is a natural extension once the API is stable and documented. The readme links a self-hosted AI setup page, which is how a deployment that wants local model inference rather than a hosted provider would be configured.
Self-hosting is one compose file and one volume
The deployment is straightforward. The repository ships a docker-compose.yml that runs the published container image and keeps all state in a named volume:
services:
openpost:
image: ghcr.io/getopenpost/openpost:latest
container_name: openpost
restart: unless-stopped
stop_grace_period: 15s
env_file:
- .env
ports:
- "8080:8080"
volumes:
- openpost_data:/dataThe state lives under /data on the volume, and the environment section makes that explicit by pointing the database and the media store into it:
environment:
# These can be overridden by .env file
- OPENPOST_PORT=8080
- OPENPOST_DATABASE_PATH=/data/db/openpost.db
- OPENPOST_MEDIA_PATH=/data/mediaSo the database is a single file, openpost.db, under the data volume, alongside a media directory. That has a practical consequence: a backup is a volume snapshot, and moving to a different host is a copy of that directory.
The compose file also carries a healthcheck with an explicit caveat, and the comment is worth quoting because it is a good practice made visible. It says the healthcheck is for process liveness only, and that traffic and rollouts should be gated on /api/v1/ready rather than on the health endpoint. The check itself runs wget with --spider against http://localhost:8080/api/v1/health every 30 seconds, with a 3 second timeout, 3 retries and a 10 second start period.
OPENPOST_APP_URL is the setting that breaks everything if you get it wrong
The example environment file is the most instructive document in the repository, because it explains the failure modes rather than just listing variables. Its very first instruction is to set OPENPOST_APP_URL before the first run, and it says most other settings, including OAuth callback URLs, the WebAuthn RPID, CORS and the public media URL, are derived from it automatically.
The file then enumerates what happens if you leave the placeholder value in place. Every provider OAuth callback round-trip fails with a redirect_uri_mismatch the first time a user tries to connect an X, LinkedIn or Threads account. WebAuthn passkey registration fails silently, because the RPID becomes localhost or openpost.example.com. And Threads media uploads return a 403 if your public host does not match the URL the binary advertises.
The comment adds that the example value is the binary's default, that in the devenv shell the value is overridden by devenv.nix to the same, and that you should override it with the URL you actually serve OpenPost from in production.
Two more configuration patterns are documented. Most variables can also use a sibling _FILE variant for Docker, Podman, Kubernetes and NixOS secrets, for example OPENPOST_JWT_SECRET_FILE pointing at a mounted secret, with direct values taking precedence over file values. And instance admins can manage optional account, email, authentication, image editor, feedback and provider settings in the application itself under Settings, then Instance.
A monorepo with Bun, Turbo, Playwright and Nix, and a very fast release train
The repository layout explains how a product of this size gets built. The root package.json is private and declares workspaces of apps/web, apps/docs, apps/marketing and packages/*, and the whole toolchain runs on Bun with Turbo for task orchestration. The scripts are wrappers around a single task runner, so the commands are the same shape whether you are building, linting, formatting or checking.
The interesting parts are the automation scripts. Capturing the product demos and the product screenshots are Playwright runs against the app on dedicated ports, with a worker count of one for the demos, followed by an encoding step and an image optimisation step that also syncs the assets. A changed-files check script runs the checks only on what moved, and there is a dev-doctor script for environment diagnosis. Formatting and linting go through the same task runner, and a policy check exists as a standalone target.
The environment layer is unusual for a web product: devenv.nix, devenv.yaml and devenv.lock sit in the tree, so a contributor can bring up a reproducible development environment, and the release script runs inside a devenv shell. Playwright is used both for testing and for producing the screenshots and demo videos that appear in the readme, which is a neat trick: the marketing assets are regenerated from the running product rather than maintained by hand.
The release cadence is fast. The tags v7.22.2, v7.22.4 and v7.22.9 were all published on 2026-10-16 and 2026-10-17, and the last push to the repository was on 2026-10-20. The topics also list golang, svelte and sveltekit alongside the TypeScript primary language, and the configuration file refers to the binary's default, which is consistent with a compiled server alongside a SvelteKit front end.
The AGPL-3.0 licence is the constraint to think about first
OpenPost is licensed AGPL-3.0, and for a self-hostable service that is a decision with consequences beyond the repository. The AGPL's distinguishing condition is on network use: if you modify the program and then let users interact with it over a network, the source of your modified version has to be offered to those users. For an internal marketing team running its own instance, that condition is mostly out of the way. For an agency that hosts the tool for clients, it is not.
The rest of the repository supports that this is a serious product rather than a hobby project. There is a licenses/ directory in the tree alongside a .gitleaks.toml configuration, a DESIGN.md, a PRODUCT.md, a CHANGELOG.md, an AGENTS.md and a changes/ directory, and a .envrc plus .env.example for configuration. The Docker image is published under ghcr.io, which is a registry hosting rather than a personal account.
A commercial hosted option also exists, OpenPost Hosted, and the readme is clear that both editors are free to use without an account or watermark, with links to try the image editor and the video editor in the hosted app. So the self-hosted and hosted paths share a feature set, and the decision is about who runs the infrastructure and under which licence.
Where OpenPost is the wrong tool
The first case is a small team that should not be running a service. A single social account for a product launch does not need a container, a volume, a domain, an OAuth app registered with every provider, and an AGPL review. The hosted option exists for that reason.
The second case is an organisation that needs isolation between clients. Workspaces exist and let you keep brands and clients separate with control over who can edit them, but a self-hosted instance shares one database and one media store across all of them. A consultancy that must guarantee data separation between clients would need separate instances, which means separate volumes, separate configuration and separate backup plans, and that changes the cost model entirely.
The third case is a team that does not want to own account recovery. Connecting an account means an OAuth round-trip with the provider, and the configuration file is blunt about how that fails when the app URL is wrong. A self-hosted instance also carries the obligation of keeping the JWT secret, the passkey RPID and the provider app registrations correct, and of renewing whatever the providers require.
The fourth is a compliance requirement for a permissive licence. A company with a policy against deploying AGPL software has to turn this down regardless of how well the features fit. And the fifth is stability appetite: with tags landing on the same day, the project is moving fast, and a team that wants a versioned, self-paced upgrade path should pin a tag and read the changelog rather than tracking the latest tag.
Editorial conclusion
OpenPost is a serious candidate for a team that has outgrown a single social scheduling tool and wants scheduling, media editing, workflows, an inbox and analytics in one self-hosted application, because the feature list covers the whole loop from a GitHub release to a published post and the container deployment is a single compose file. It is the wrong choice for a company that cannot accept a copyleft licence on a service it modifies, and it is the wrong choice for a two-person team that would rather pay for a hosted tool than run one. Before you commit, check the three things that decide the outcome: that OPENPOST_APP_URL is set to the URL you actually serve from before the first run, because the configuration file states that provider OAuth callbacks, passkey registration and media uploads all derive from it and fail without it; that the AGPL-3.0 licence is acceptable to your organisation, since it reaches beyond the repository boundary to network use; and that the moving release train, with v7.22.9 published on 2026-10-17, is something you can pin and update on your own schedule rather than track upstream.
Frequently asked questions
How do I self-host OpenPost?
The repository ships a docker-compose.yml that runs the ghcr.io/getopenpost/openpost:latest image with an env_file of .env, publishes port 8080 and keeps all state in a named volume mounted at /data. The environment variables OPENPOST_DATABASE_PATH and OPENPOST_MEDIA_PATH place the database file and the media store inside that volume.
What must be configured before the first run of OpenPost?
OPENPOST_APP_URL has to be set to the URL you actually serve from. The example environment file states that OAuth callback URLs, the WebAuthn RPID, CORS and the public media URL are derived from it, and that leaving the placeholder causes OAuth redirect_uri_mismatch errors, silent passkey registration failures and 403 responses on Threads media uploads.
Can I automate OpenPost from scripts or agents?
Yes. The project documents an API, an SDK, a CLI, MCP and n8n support for creating drafts, scheduling posts and checking publishing results, with the TypeScript SDK published on npm as @getopenpost/sdk and the CLI as @getopenpost/cli, and an API reference listing the endpoints.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/getopenpost-openpost)Was this useful?