Skip to content
Open source · AGPL

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.

Star on GitHubgit clone github.com/tryharbor/harbor
The license

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.

You can
  • 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
If you host a modified Harbor for others
  • 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.

Self-host guide

From clone to first post.

Sandbox first, so you can see everything working before you touch a developer console.

  1. 01

    Clone the repo

    You need Node 22.12 or newer and pnpm 10.

    ~
    git clone https://github.com/tryharbor/harbor
    cd harbor
  2. 02

    Install

    One install for the whole monorepo: the web app, the API and the shared packages.

    ~/harbor
    pnpm install
  3. 03

    Run it in sandbox mode

    With no .env at 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:demo plus pnpm dev:web starts two demo brands with six weeks of posts and growth curves, on a separate database.

    ~/harbor
    pnpm dev
    
    # API  http://localhost:4800
    #      pglite; publishing: sandbox; model: simulated
    # Web  http://localhost:4801
  4. 04

    Fill in .env when you go live

    Copy the example file. The keys that matter first:

    • HARBOR_PUBLISH_MODE=live to post for real.
    • HARBOR_SECRET_KEY encrypts every account token. Generate it with openssl rand -base64 32 and keep it: lose it and you reconnect every account.
    • HARBOR_API_URL is the API’s public HTTPS address. Redirect URLs are built from it.
    • One client ID and secret per platform: X_, LINKEDIN_, INSTAGRAM_, THREADS_.
    .env
    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=
  5. 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 as HARBOR_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
  6. 06

    Use Postgres in production

    With DATABASE_URL unset, the API uses PGlite, an embedded Postgres stored under apps/api/.pglite. Good for a laptop; it lives in one process.

    For a server, set DATABASE_URL to any postgres:// URL, for example Supabase (transaction poolers work). Same SQL either way, and migrations run when the API starts.

    .env
    # Unset: embedded PGlite under apps/api/.pglite
    DATABASE_URL=postgres://user:pass@host:5432/harbor
Architecture

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.

fetch /v1publish · metrics · OAuthYouA browserlocalhost:4801AgentsMCP clientsClaude Code over HTTPClaude Desktop over thestdio bridgeapps/webNext.js appApp Router · :4801Studio, Hub, Approvalsapps/apiHono API · :4800/v1REST APIwhat the web app callsIn processWorkerpublishes, snapshots,runs automations/mcpMCP serverStreamable HTTPBearer hbr_ keys/mediaPublic cropsInstagram and Threadsdownload from herePlatform APIsYour own appsXLinkedInInstagramThreadsDATABASE_URLPostgresor embedded PGlitewhen unsetYouA browser:4801AgentsMCP clientsHTTP or stdioapps/webNext.js appApp Routerapps/apiHono API · :4800/v1REST APIwhat the web app calls/mcpMCP serverStreamable HTTP · hbr_ keysIn processWorkerpublishes, snapshots, automations/mediaPublic cropsfor Instagram and ThreadsDATABASE_URLPostgresor PGlitePlatform APIsYour own appsXLinkedInInstagramThreads
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.
Harbor Cloud · coming soon

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.

HostingWe run the API, the worker and the web app, and keep them updated.
BackupsDatabase and media library backed up, so a lost laptop isn’t a lost history.
No developer appsConnect accounts through Harbor’s own platform apps. No consoles, tunnels or tester invites.
Opening soonCloud needs platform app review before it can open. Early pricing is on the pricing page.
Contributing

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.

01Open an issue firstFor anything bigger than a typo, describe the problem in a GitHub issue before writing code, so we can agree on the shape.
02Keep the sandbox workingEverything must run with no keys and no network. New platform features need a sandbox version and tests with mocked HTTP.
03Read the decisionsdocs/decisions explains the rules that won’t change, like publishing directly and agents never posting on their own.
04Check before you pushRun pnpm test and pnpm typecheck. UI follows docs/design/DESIGN.md: square controls, no colored edge accents, no native dropdowns.

Found a security issue? Please email hello@useharbor.io instead of opening a public issue.

Get started

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.