social media crossposting tool. 3rd time's the charm
mastodon misskey crossposting bluesky

XPost documentation#

Installation#

The recommended approach is to use the official container image from ghcr.io/zenfyrdev/xpost:latest

Podman Quadlets#

Example Rootful Quadlet. Make sure the data dir exists on the host and is owned by 1000:1000!

[Unit]
Description=XPost

[Container]
Image=ghcr.io/zenfyrdev/xpost:latest
EnvironmentFile=/etc/containers/systemd/xpost/.env
Volume=/var/containers/xpost/data:/app/data:Z

[Service]
Restart=always
RestartSec=10s

[Install]
WantedBy=default.target

Docker Compose#

Make sure the data dir exists on the host and is owned by 1000:1000!

services:
  xpost:
    image: ghcr.io/zenfyrdev/xpost:latest
    restart: unless-stopped
    env_file: ./.env
    volumes:
      - ./data:/app/data

Native Install#

The project uses uv, so a native install using a .venv is pretty simple.

  1. Make sure that ffmpeg and libmagic are installed.
  2. Download and install uv
  3. Clone the project https://tangled.org/zenfyr.dev/xpost
  4. Run uv sync --locked

Quickstart#

Upon first launch, XPost will create a folder ./data with an example settings.json

Edit the file, and then start XPost again.

Features#

  • Based on streaming APIs to instantly crosspost new posts.
  • Splitting large posts into multiple smaller ones to fit into character limits.
  • Supports quotes and reposts.

Configuration#

XPost config accepts an array of input -> outputs pairs. find all services and example configs in services.md.

All "key": "value" options can be set to env:VARIABLE to read envvars instead of storing things directly in the settings file.

Additionally XPost accepts some envvars.

Key Description
DATA_DIR Base data directory.
SETTINGS_DIR settings.json file location.
DATABASE_DIR data.db file location.
SLINGSHOT_URL URL of the microcosm slingshot service for resolving identities.
JETSTREAM_URL URL of the Jetstream service for listening for incoming posts.

Advanced Features#

bi-directional crossposting#

This is experimental and unstable.

XPost supports pointing to services directly at each other, posts crossposted from other services are marked as so, and are skipped to avoid creating infinite loops.

While this works for most things, cross-service replies can end up being duplicated multiple times over or cause an infinite loop, this usually happens when a post from one service is split into multiple other on the other.

e.g. Post A from Mastodon ends up as Post A1 and Post A2 on bsky, replying from bsky to either may result in Reply B being posted twice, or getting stuck in a loop.