Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
How can you support the project?

Here you'll find simple guides for using BlueBubbles
Here you will find more advanced guides for using BlueBubbles
Here, you will find guides on virtualizing macOS, whether that be in a virtual machine, or in a docker container.
If you want to change the Mac server that your BlueBubbles Server runs on, you've come to the right place!
Here you will find guides on how to develop against BlueBubbles
This document will guide you on how you can configure your Mac to automatically restart the BlueBubbles Server app if the app crashes (unsafe exit)
Here you will find child guides for setting up BlueBubbles with a BYO (Bring Your Own) Proxy Service (Dynamic DNS).
Remove Attachments
KeepAliveSuccessfulExit: falselaunchctl bootstrap gui/$(id -u $(whoami)) ~/Library/LaunchAgents/com.bluebubbles.server.plistlaunchctl kickstart gui/$(id -u $(whoami))/com.bluebubbles.serverlaunchctl remove com.bluebubbles.serverlaunchctl print gui/$(id -u $(whoami))/com.bluebubbles.server<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.bluebubbles.server</string>
<key>Program</key>
<string>/Users/{username}/Applications/BlueBubbles.app/Contents/MacOS/BlueBubbles</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
</dict>
</plist>







Here is a sample of a web server written in Python to receive new message events.
import json
import requests
from time import sleep
from http.server import HTTPServer, BaseHTTPRequestHandler
# Your BlueBubbles local address + port
server_addr = 'http://localhost:1234'
server_password = 'your-server-password'
# Create a class to handle a POST request on port 8000
class PostHandler(BaseHTTPRequestHandler):
def return_bad_request(self, error="Bad Request"):
"""
A function to return a 400 error.
Args:
error (str): The error message to return
"""
self.send_response(400)
self.end_headers()
self.wfile.write(error.encode('utf-8'))
def return_ok(self, message="OK"):
"""
A function to return a 200 response.
Args:
message (str): The message to return
"""
self.send_response(200)
self.end_headers()
self.wfile.write(message.encode('utf-8'))
def do_POST(self):
"""
A POST request handler. This is called when a POST request is received.
This function does some validation around "valid" requests relative to
what the BlueBubbles server will emit via Webhooks.
"""
print("Received POST request")
# Ignore any request that isn't JSON
if self.headers["Content-Type"] != "application/json":
return self.return_bad_request()
# Read the data
content_length = int(self.headers["Content-Length"])
post_data = self.rfile.read(content_length)
try:
# Convert the data to a JSON object and pass it to the handler
data = json.loads(post_data)
self.handle_json(data)
except ValueError as ex:
return self.return_bad_request(ex.message or "Invalid JSON received")
self.return_ok()
def handle_json(self, data):
"""
Handles a generic JSON object. This function will check the type of the
event and handle it accordingly.
Args:
data (dict): The JSON data
"""
print("Received JSON data: ", data)
if data.get('type') == 'new-message':
self.handle_new_message()
else:
print("Unhandled event type: ", data.get('type'))
def handle_new_message(self, data):
"""
Handles a new-message event.
This is a general handler that will respond to any new message with "Hello World!"
Args:
data (dict): The JSON data
"""
if not isinstance(data.get('data'), dict):
return
# Ignore messages that I sent
if data.get('data').get('isFromMe'):
return
# Extract the chat guid and message text
chats = data.get('data').get('chats', [])
if not chats:
raise ValueError('No chats found in data')
chat_guid = chats[0].get('guid')
print("Detected incoming message... Dispatching response...")
self.send_text(chat_guid, "Hello World!")
print("Response dispatched")
def send_text(self, chat_guid, text, method='private-api'):
"""
Sends a text message to a chat via the BlueBubbles server.
Args:
chat_guid (str): The chat guid to send the message to
text (str): The text to send
method (str): The method to use to send the message. Defaults to "private-api"
"""
params = {'password': server_password}
data = {
'chatGuid': chat_guid,
'text': text,
'method': method
}
requests.post(
'{}/api/v1/message/text'.format(server_addr),
json=data,
params=params,
headers={'Content-Type': 'application/json'}
)
# Create a server on port 8000
server = HTTPServer(("", 8000), PostHandler)
print("Server started on port 8000")
server.serve_forever(){
status: (int) Status Code,
message: (String) Status Message,
data: (Variable)
}{
status: (int) Status Code,
message: (String) Status Message,
error: {
type: (String) Error Type,
error: (String) Error Message
},
data?: (any)
}


Learn how you can generate an SSL Certificate using CertBot for BlueBubbles. This is especially useful for dynamic DNS setups.
This guide will show you how to setup the BlueBubbles Docker container to run as a service on your Linux host. This is to make sure that the host starts up when your Linux host restarts.
This page will help you troubleshoot and (hopefully) fix issues with not receiving notifications or URL changes on the Android app
BlueBubbles App on Android, and open the Settingsecho 'alias tailscale="/Applications/Tailscale.app/Contents/MacOS/Tailscale"' | sudo tee -a ~/.zshrctailscale serve --bg --https=443 1234tailscale funnel --bg --https=443 1234tailscale serve status https://machine-name.example.ts.net:443/sudo systemctl edit --force --full bluebubbles.service[Unit]
Description=BlueBubbles iMessage relay server
Requires=docker.service
After=docker.service
[Service]
Restart=always
ExecStart=/usr/bin/docker run \
--rm \
--name bluebubbles \
--dns=1.1.1.1 \
--device /dev/kvm \
-p 5999:5999 \
-p 1234:1234 \
-p 50922:10022 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v $PWD/maindisk.qcow2:/image \
-v $PWD/bootdisk.qcow2:/bootdisk \
-e IMAGE_PATH="/image" \
-e BOOTDISK="/bootdisk" \
-e EXTRA="-display none -vnc 0.0.0.0:99,password-secret=secvnc0 -object secret,id=secvnc0,data=vncpass" \
-e ADDITIONAL_PORTS="hostfwd=tcp::1234-:1234," \
-e DISPLAY=:99 \
-e WIDTH=1920 \
-e HEIGHT=1080 \
-e NOPICKER=true \
sickcodes/docker-osx:naked
ExecStop=/usr/bin/docker container stop bluebubbles
[Install]
WantedBy=multi-user.targetExecStart=/usr/bin/sh /absolute/path/to/your/script.shsudo systemctl daemon-reloadsudo systemctl enable --now bluebubbles.serviceEFI Internal Shellfs0:voldmpstore Asr-active-config -s csr.binhexedit csr.binexitsudo nvram Asr-active-config=%7f%00%00%00bios.forceSetupOnce = "TRUE"




board-id = "Mac-27AD2F918AE68F61"
hw.model.reflectHost = "FALSE"
hw.model = "MacPro7,1"
serialNumber.reflectHost = "FALSE"
serialNumber = "<YOUR GENERATED SERIAL NUMBER>"
smbios.reflectHost = "FALSE"
efi.nvram.var.ROM.reflectHost = "FALSE"
efi.nvram.var.MLB.reflectHost = "FALSE"
efi.nvram.var.ROM = "<YOUR GENERATED ROM VALUE>"
efi.nvram.var.MLB = "<YOUR GENERATED BOARD SERIAL (AKA MLB)>"sudo rm -rf ~/Library/Caches/com.apple.iCloudHelper*
sudo rm -rf ~/Library/Caches/com.apple.Messages*
sudo rm -rf ~/Library/Caches/com.apple.imfoundation.IMRemoteURLConnectionAgent*
sudo rm -rf ~/Library/Preferences/com.apple.iChat*
sudo rm -rf ~/Library/Preferences/com.apple.icloud*
sudo rm -rf ~/Library/Preferences/com.apple.imagent*
sudo rm -rf ~/Library/Preferences/com.apple.imessage*
sudo rm -rf ~/Library/Preferences/com.apple.imservice*
sudo rm -rf ~/Library/Preferences/com.apple.ids.service*
sudo rm -rf ~/Library/Preferences/com.apple.madrid.plist*
sudo rm -rf ~/Library/Preferences/com.apple.imessage.bag.plist*
sudo rm -rf ~/Library/Preferences/com.apple.identityserviced*
sudo rm -rf ~/Library/Preferences/com.apple.ids.service*
sudo rm -rf ~/Library/Preferences/com.apple.security*
sudo rm -rf ~/Library/Messages#### AMD USERS PLEASE READ
Make sure that your VMX does not have any duplicate items from your previous modifications to make the VM start up! You may need to delete the following from the previous modifications:
```config
smbios.reflectHost = "TRUE"
hw.model = "<HW MODEL FROM AMD GUIDE>"
board-id = "<BOARD ID FROM AMD GUIDE>"
```



dmpstore -l csr.bindmpstore -d Asr-active-configThe following guides are to help you if you run into any issues setting up or using the BlueBubbles Server.



If you want to perform a manual setup of Nginx, instead of using the Nginx Proxy Manager, here is a guide on how to do it. Big thanks to @JustBen in the BlueBubbles Discord, for putting this guide tog
docker (or podman) server {
listen 80;
server_name <server name>;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Connection "Upgrade";
proxy_set_header Upgrade $http_upgrade;
client_max_body_size 512M;
location / {
proxy_pass http://<BlueBubbles IP>:<BlueBubbles port>;
}
} <VirtualHost *:80>
ServerName <server name>
ProxyPreserveHost On
RequestHeader set X-ForwardedPort "80"
RequestHeader set X-Forwarded-Proto "http"
ErrorLog <error log location>
CustomLog <access log location> common
<Location />
ProxyPass http://<BlueBubbles IP>:<BlueBubbles port>/
ProxyPassReverse http://<BlueBubbles IP>:<BlueBubbles port>/
ProxyPass ws://<BlueBubbles IP>:<BlueBubbles port>/
ProxyPassreverse ws://<BlueBubbles IP>:<BlueBubbles port>/
</Location>
</VirtualHost> <VirtualHost *:80>
ServerName {server name}
<Location />
ProxyPass http://<BlueBubbles IP>:<BlueBubbles port>/
ProxyPass ws://<BlueBubbles IP>:<BlueBubbles port>/
</Location>
</VirtualHost> frontend
use_backend <backend name> [if {ACL}]
backend <backend name>
timeout client 60m
timeout http-keep-alive 5m
server <be server name> <BlueBubbles IP>:<BlueBubbles port> server {
listen 443 ssl;
server_name <server name>;
proxy_set_header Connection "Upgrade";
proxy_set_header Upgrade $http_upgrade;
proxy_http_version 1.1;
client_max_body_size 512M;
location / {
proxy_pass http://<BlueBubbles IP>:<BlueBubbles port>;
}
ssl_certificate /etc/letsencrypt/live/<server name>/fullchain.pem
ssl_certificate_key /etc/letsencrypt/live/<server name>/privkey.pem
include /etc/letsencrypt/options-ssl-nginx.conf
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem
}
server {
listen 80;
server_name <server name>;
# HTTP to HTTPS redirect
if ($host = <server name>) {
return 301 https://$host$request_uri;
}
return 404;
}ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off; <VirtualHost *:443>
ServerName <server name>
ProxyPreserveHost On
RequestHeader set X-ForwardedPort "443"
RequestHeader set X-Forwarded-Proto "https"
ErrorLog <error log location>
CustomLog <access log location> common
<Location />
ProxyPass http://<BlueBubbles IP>:<BlueBubbles port>/
ProxyPassReverse http://<BlueBubbles IP>:<BlueBubbles port>/
ProxyPass ws://<BlueBubbles IP>:<BlueBubbles port>/
ProxyPassreverse ws://<BlueBubbles IP>:<BlueBubbles port>/
</Location>
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/<server name>/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/<server name>/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/<server name>/fullchain.pem
</VirtualHost>
# HTTP to HTTPS redirect
<VirtualHost *:80>
ServerName <server name>
Redirect permanent / https://<server name>
</VirtualHost> frontend
bind *:80
bind *:443 ssl crt /etc/ssl/certs/mysite.pem
http-request redirect scheme https unless { ssl_fc }
use_backend <backend name> [if {ACL}]
backend <backend name>
timeout client 60m
timeout http-keep-alive 5m
server <be server name> <BlueBubbles IP>:<BlueBubbles port>qemu-img create -f qcow2 maindisk.qcow2 128Gdocker run \
--rm \
--name bluebubbles-setup \
--dns=1.1.1.1 \
--device /dev/kvm \
-p 5999:5999 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v $PWD/maindisk.qcow2:/image \
-e IMAGE_PATH="/image" \
-e EXTRA="-display none -vnc 0.0.0.0:99,password-secret=secvnc0 -object secret,id=secvnc0,data=vncpass" \
-e DISPLAY=:99 \
-e WIDTH=1920 \
-e HEIGHT=1080 \
-e GENERATE_UNIQUE=true \
sickcodes/docker-osx:venturadocker cp bluebubbles-setup:/home/arch/OSX-KVM/OpenCore/OpenCore.qcow2 ./bootdisk.qcow2docker stop bluebubbles-setupdocker run \
--rm \
--name bluebubbles \
--dns=1.1.1.1 \
--device /dev/kvm \
-p 5999:5999 \
-p 1234:1234 \
-p 50922:10022 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v $PWD/maindisk.qcow2:/image \
-v $PWD/bootdisk.qcow2:/bootdisk \
-e IMAGE_PATH="/image" \
-e BOOTDISK="/bootdisk" \
-e EXTRA="-display none -vnc 0.0.0.0:99,password-secret=secvnc0 -object secret,id=secvnc0,data=vncpass" \
-e ADDITIONAL_PORTS="hostfwd=tcp::1234-:1234," \
-e DISPLAY=:99 \
-e WIDTH=1920 \
-e HEIGHT=1080 \
-e NOPICKER=true \
sickcodes/docker-osx:nakeddocker stop bluebubblesserver collection (it should be pre-selected)I will install the operating system later.macOS Base SystemAAA: Replace with your Board ID (i.e. Mac-XXXXXXXXXXXXXX)smc.version = "0"cpuid.0.eax = "0000:0000:0000:0000:0000:0000:0000:1011"
cpuid.0.ebx = "0111:0101:0110:1110:0110:0101:0100:0111"
cpuid.0.ecx = "0110:1100:0110:0101:0111:0100:0110:1110"
cpuid.0.edx = "0100:1001:0110:0101:0110:1110:0110:1001"
cpuid.1.eax = "0000:0000:0000:0001:0000:0110:0111:0001"
cpuid.1.ebx = "0000:0010:0000:0001:0000:1000:0000:0000"
cpuid.1.ecx = "1000:0010:1001:1000:0010:0010:0000:0011"
cpuid.1.edx = "0000:0111:1000:1011:1111:1011:1111:1111"board-id = "AAA"
hw.model.reflectHost = "FALSE"
hw.model = "BBB"
serialNumber.reflectHost = "FALSE"
serialNumber = "CCC"
smbios.reflectHost = "FALSE"
efi.nvram.var.ROM.reflectHost = "FALSE"
efi.nvram.var.MLB.reflectHost = "FALSE"
efi.nvram.var.ROM = "DDD"
efi.nvram.var.MLB = "EEE"ethernet0.virtualDev = "vmxnet3"
python ./macrecovery.py -b Mac-27AD2F918AE68F61 -m 00000000000000000 downloadThis guide will show you how you can troubleshoot issues with sending messages through BlueBubbles.