pybsposter is a simple, containerized Python service that accepts webhook payloads to post messages and links to BlueSky and Mastodon. It's designed for easy integration with CI/CD pipelines (like GitHub Actions or Azure DevOps) or any other system that can trigger a webhook.
The fastest way to get started is to run the pre-built container image from Docker Hub.
# Run the container in the background, mapping port 5550 on your host to port 5000 in the container
docker run -d -p 5550:5000 idjohnson/pybsposter:latestOnce running, the service is ready to accept POST requests. See the API Usage section below for details on the payloads.
Note: A non-Docker Hub image is also available at harbor.freshbrewed.science/library/pybsposter:latest.
The service provides separate endpoints for posting to BlueSky and Mastodon.
To post to BlueSky, send a POST request to the /post endpoint with a JSON payload.
POST /post
USERNAME(string, required): Your BlueSky username (e.g.,myuser.bsky.social).PASSWORD(string, required): Use a BlueSky App Password! Do not use your main account password.TEXT(string, required): The text content of your post.LINK(string, required): The URL you want to include in the post.
DO NOT use your primary BlueSky password. It is extremely insecure to store your main password in configuration files or send it directly via API calls.
Instead, create a dedicated App Password from your BlueSky settings. This is a standard security practice that limits the potential damage if a password is leaked.
- Go to Settings in your BlueSky client.
- Navigate to App Passwords.
- Generate a new password and give it a descriptive name (e.g.,
pybsposter-webhook). - Use that password in your payload.
-
Create the payload file (e.g.,
bsky-payload.json):{ "USERNAME": "myuser.bsky.social", "PASSWORD": "xxxx-xxxx-xxxx-xxxx", "TEXT": "Check out this awesome website I found!", "LINK": "https://freshbrewed.science" } -
Send the request:
curl -X POST http://localhost:5550/post \ -H "Content-Type: application/json" \ -d @bsky-payload.json
To post to Mastodon, send a POST request to the /post/mastodon endpoint with a JSON payload.
To post to Threads, send a POST request to the /post/threads endpoint with a JSON payload.
POST /post/threads
user_id(string, required): Your Threads user ID.access_token(string, required): Your Threads Access Token. This is used for authentication with the Threads API.text(string, required): The text content of your post.link(string, optional): A URL to include in your post.
DO NOT use your primary Threads/Instagram password. You must use an Access Token for authentication.
To obtain a Threads Access Token:
- Create a Threads app in the Meta for Developers portal.
- Configure your app with the necessary permissions for posting (
threads_basicandthreads_content_publish). - Complete the OAuth flow to obtain a long-lived access token.
- Your user_id can be obtained from the Threads API after authentication.
- Use the access token as the
access_tokenin your payload.
Refer to the Threads API documentation for detailed setup instructions.
-
Create the payload file (e.g.,
threads-payload.json):{ "user_id": "123456789", "access_token": "YOUR_THREADS_ACCESS_TOKEN", "text": "Hello from pybsposter!", "link": "https://freshbrewed.science" } -
Send the request:
curl -X POST http://localhost:5550/post/threads \ -H "Content-Type: application/json" \ -d @threads-payload.json
POST /post/mastodon
baseURL(string, required): The base URL of your Mastodon instance (e.g.,https://mastodon.social).PASSWORD(string, required): Your Mastodon Access Token. This is used for authentication.TEXT(string, required): The text content of your toot.LINK(string, optional): A URL to include in your toot.USERNAME(string, required): This field is currently required by the API but is not used for Mastodon posting. You can provide any non-empty string.
DO NOT use your primary Mastodon password. You must use an Access Token for authentication.
- In your Mastodon instance, go to Preferences -> Development.
- Click New Application.
- Give your application a name (e.g.,
pybsposter-webhook). - Ensure the
write:statusesscope is checked. - Save the application.
- Your Access Token will be displayed on the next page. Use this token as the
PASSWORDin your payload.
-
**Create the payload file (e.g.,
mastodon-payload.json):{ "baseURL": "https://mastodon.social", "PASSWORD": "YOUR_MASTODON_ACCESS_TOKEN", "TEXT": "This is a test post to Mastodon from my awesome service!", "LINK": "https://freshbrewed.science", "USERNAME": "unused" } -
Send the request:
curl -X POST http://localhost:5550/post/mastodon \ -H "Content-Type: application/json" \ -d @mastodon-payload.json
The service is designed to be deployed easily in containerized environments like Kubernetes.
YouYou can deploy the service using the provided deploy.yaml manifest. This will create a Deployment and a Service.
# Apply the manifest to your cluster
kubectl apply -f ./deploy.yamlTo access the service from your local machine, you can use port-forward:
# Forward local port 5550 to the service's port 80
kubectl port-forward svc/pybsposter 5550:80For production use, you should configure an Ingress controller to expose the service publicly and handle TLS termination.
A Helm chart is available in the charts/pybsposter directory for more configurable deployments.
# Install the chart
helm install pybsposter ./charts/pybsposter
NAME: pybsposter
LAST DEPLOYED: Fri Dec 6 07:37:34 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: NoneYou can customize the deployment by modifying the values.yaml file within the chart.
For those who prefer docker-compose, a docker-compose.yaml file is provided in the root of the repository.
# Start the service in detached mode
docker-compose up -dThis will start the service and expose it on port 8000.
If you need to build the image locally for testing or development.
-
Build the Docker image:
# Tag the image as 'mytest:01' docker build -t mytest:01 .
-
Run the Docker container: You can set the
VERSIONenvironment variable to display a version (e.g., the current Git SHA) at startup. The service runs on port 8000 inside the container.# Run the container, mapping host port 8000 to container port 8000 docker run -p 8000:8000 -e VERSION=$(git rev-parse --short HEAD) mytest:01
- Post Length:
- BlueSky: The service does not currently validate the total post length. BlueSky has a limit of 300 characters. If your combined
TEXTandLINKexceed this, the post will be trimmed automatically. - Mastodon: The default character limit is 500 characters. The service will trim posts that exceed this limit.
- BlueSky: The service does not currently validate the total post length. BlueSky has a limit of 300 characters. If your combined
- Error Responses: Invalid credentials or other API issues will also likely result in a
500error. Future versions should provide more specific error feedback.
