Your server, your data, your Harbor.
Every feature of Harbor is in the public repo. Run it on your laptop in sandbox mode in a few minutes, then connect your own accounts when you’re ready.
The AGPL, in plain words.
Harbor is licensed under the GNU Affero General Public License v3. Most people never need to think about it. Here’s when you do.
- Use Harbor for anything, including commercial work and clients’ brands
- Run it on your own server, for as many brands as you like, for free
- Read, change and fork the code
- Charge for setting it up, hosting it or supporting it
- Keep private changes private when only you and your own team use them
- Offer the people using it the complete source of your modified version, for example with a link in the app
- License your changes under the AGPL too
- Keep the copyright and license notices
- Say that you changed it, and roughly when
“Others” means people outside your organization who use it over the network: clients logging in, or a hosted service you sell.
A plain summary, not legal advice. The LICENSE file is what counts. Why the AGPL: if someone turns Harbor into a hosted service, the improvements come back to everyone, including you.
From clone to first post.
Sandbox first, so you can see everything working before you touch a developer console.
- 01
Clone the repo
You need Node 22.12 or newer and pnpm 10.
git clone https://github.com/tryharbor/harbor cd harbor - 02
Install
One install for the whole monorepo: the web app, the API and the shared packages.
pnpm install - 03
Run it in sandbox mode
With no
.envat all, Harbor runs fully offline. Publishing is simulated per platform with each platform’s real limits, and drafting uses a deterministic simulated model. No keys, no network calls, no spend.Want sample data?
pnpm --filter @harbor/api dev:demopluspnpm dev:webstarts two demo brands with six weeks of posts and growth curves, on a separate database.pnpm dev # API http://localhost:4800 # pglite; publishing: sandbox; model: simulated # Web http://localhost:4801 - 04
Fill in .env when you go live
Copy the example file. The keys that matter first:
HARBOR_PUBLISH_MODE=liveto post for real.HARBOR_SECRET_KEYencrypts every account token. Generate it withopenssl rand -base64 32and keep it: lose it and you reconnect every account.HARBOR_API_URLis the API’s public HTTPS address. Redirect URLs are built from it.- One client ID and secret per platform:
X_,LINKEDIN_,INSTAGRAM_,THREADS_.
cp .env.example .env HARBOR_PUBLISH_MODE=live HARBOR_SECRET_KEY= # openssl rand -base64 32 HARBOR_API_URL=https://your-name.ngrok-free.app X_CLIENT_ID= X_CLIENT_SECRET= LINKEDIN_CLIENT_ID= LINKEDIN_CLIENT_SECRET= INSTAGRAM_APP_ID= INSTAGRAM_APP_SECRET= THREADS_APP_ID= THREADS_APP_SECRET= - 05
Connect your platform apps
Harbor publishes through developer apps you register yourself, one per platform. For your own accounts none of them need app review: you only connect accounts that hold a role on the app. Allow about an hour for all four.
Meta only accepts HTTPS redirect URLs, so while developing, point a tunnel with a stable address at
localhost:4800(an ngrok static domain or a Cloudflare named tunnel) and use it asHARBOR_API_URL. Each platform’s redirect URL is{HARBOR_API_URL}/v1/channels/{platform}/callback.X- OAuth 2.0 Web App (confidential client), read and write
- Pay-per-use: add credits and set a spending limit
- Images work; video isn’t supported yet
LinkedIn- Add “Share on LinkedIn” and “Sign In with LinkedIn using OpenID Connect”, both self-serve
- Needs a Company Page to own the app; it still posts as you
- Tokens last 60 days; post metrics need partner approval, so they show n/a
Instagram- Instagram API with Instagram Login; a Business or Creator account, no Facebook Page
- Add yourself as an Instagram tester and keep the app in development mode
- Every post needs an image or video at a public URL
Threads- Add the Threads API use case to a Meta app
- Add your profile as a Threads tester and accept the invite
- 500 characters a post; tokens refresh on their own
Full platform setup guidedocs/setup/platform-apps.md in the repo, with every scope and dashboard step - 06
Use Postgres in production
With
DATABASE_URLunset, the API uses PGlite, an embedded Postgres stored underapps/api/.pglite. Good for a laptop; it lives in one process.For a server, set
DATABASE_URLto anypostgres://URL, for example Supabase (transaction poolers work). Same SQL either way, and migrations run when the API starts.# Unset: embedded PGlite under apps/api/.pglite DATABASE_URL=postgres://user:pass@host:5432/harbor
Two apps and a database.
A Next.js app for people, a Hono API for everything else. The API’s worker runs in the same process, and its state lives in Postgres rows, so PGlite works too.
packages/coreDomain types and schemas, normalized metrics per platform, and the publishing interface with its failure policy.packages/providersOne adapter per platform for OAuth, publishing, threads, metrics and replies, plus a sandbox for each.packages/aiThe content model interface, with the simulated model as the default.Same Harbor, without the server.
Cloud runs the same open-source code. It’s for people who would rather not run infrastructure or register four developer apps.
Built in public. Help welcome.
Harbor is early, and the most useful contributions right now are bug reports from real use and fixes for the platforms you post to.
Found a security issue? Please email hello@useharbor.io instead of opening a public issue.
Run Harbor on your own machine today.
Self-host Harbor free, or get early access to Harbor Cloud. Either way, nothing posts until you say so.