Setting up Marchat #75
Description
Activity
Thanks for the detailed report and for running the test suite.
The error:
Error initializing keystore: failed to decrypt keystore: cipher: message authentication failedis coming from AES-GCM when trying to decrypt your existing keystore file. That usually means either:
- the keystore passphrase doesn’t match what was used when the file was created, or
- the keystore was written with an older key-derivation scheme and the current version can’t decrypt it.
Recently I changed the keystore key derivation from a simple SHA256-based scheme to PBKDF2. The JSON format is backward-compatible, but the encryption key is not, so older
keystore.datfiles can’t be decrypted by newer builds even with the same passphrase.If you don’t need to keep the existing keystore contents, the simplest fix is to remove only the keystore file and let marchat create a new one. You can keep your profiles and use the same passphrase:
-
On Linux (default config location):
rm ~/.config/marchat/keystore.dat -
Then run
marchat-clientagain, pick your existing profile, and enter the same keystore passphrase. A new keystore file will be created with that passphrase.
If you’re sure this is a brand‑new install and there was no older keystore, then it’s likely a passphrase mismatch (e.g. admin key vs keystore passphrase, or a typo). Removing
keystore.datand starting that profile again with the correct passphrase should fix it.I’ll look at adding a clearer error message and a migration path for old keystores so this is less confusing. Thanks for surfacing it.
Quick question to help confirm: did this start happening after updating marchat from an older version, or is this a fresh install on this machine?
I just started setting up marchat yesterday, and I didn't update as it was already the latest update. I would also like help setting up access to the chatroom without having to use ssh
Got it, thanks for clarifying.
You don’t need SSH access for clients to join a marchat server. SSH is only required if you’re managing the machine the server is running on.
If your intention is to run everything locally (for example on a home network), you just need:
marchat-serverrunning on one machinemarchat-clientrunning on any other machines (or the same one)
As long as the server is reachable over the network and the client is configured with the correct server URL, that’s all that’s required for clients to connect.
To connect remotely (outside your local network), you’ll also need:
- The server running and reachable on a public address/IP
- The WebSocket port (default :5555) open/forwarded
- The correct server URL in the client (for example
ws://your-server-ip:5555/ws, orwss://if TLS is enabled)
Typical setups are:
- Port forwarding on your router if the server is on a home network
- Running the server on a VPS
- Using a tunnel or reverse proxy (Cloudflare Tunnel, etc.)
how would i set up TLS, the readme is vague on that, but incredibly extensive on everything else
well, actually, what does TLS give you? all im aware is that is secure, but that's all i know
What TLS gives you
- Encryption in transit – Traffic between client and server (including your admin key and keystore passphrase when you type them) is encrypted. Without TLS, anyone on the same network can sniff that traffic.
- Server identity – With proper (CA-signed) certificates, clients can confirm they’re talking to your server and not an impersonator.
- Integrity – The connection detects if someone is altering data in flight.
So: no TLS = fine for localhost or a trusted LAN. TLS = what you want if the server is on the internet or any network you don’t fully trust.
How to set up TLS with marchat
-
Get a certificate and key. Two options:
- Self-signed (testing / personal use):
Use
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
wss://and--skip-tls-verifyon the client (see below). - Production: Use a real certificate (e.g. Let’s Encrypt with certbot). Use the full chain for the cert file and the private key for the key file.
- Self-signed (testing / personal use):
-
Run the server with TLS: Set both env vars (marchat enables TLS only when both are set), then start the server:
export MARCHAT_ADMIN_KEY="your-key" export MARCHAT_USERS="admin1,admin2" export MARCHAT_TLS_CERT_FILE="/path/to/cert.pem" export MARCHAT_TLS_KEY_FILE="/path/to/key.pem" ./marchat-server
Default port is 8080 (or set
MARCHAT_PORTif you use something else, e.g. 5555). The banner will showWebSocket: wss://<addr>/wsandTLS: Enabledwhen TLS is active. -
Connect the client over TLS: Use
wss://and the same host and port as the server:./marchat-client --server wss://your-server:8080/ws
If you’re using a self-signed cert:
./marchat-client --skip-tls-verify --server wss://your-server:8080/ws
(Use your actual port if you set
MARCHAT_PORT.)
If you run marchat behind nginx/traefik/Cloudflare, you can terminate TLS there and keep marchat on
ws://locally; the README’s “HTTPS reverse proxies” note refers to that pattern.okay. thank you, are there any recommended clients like termux to use on apple? termux only has paid offbrands on apple because apple bad.
i was thinking having a bunch of isolated ttys with nothing but marchat on them but that will go about as well-not at allalso, where would the environment variables be?
Apple / clients
- macOS: Use the darwin build (darwin-amd64 or darwin-arm64 from the releases). Run
marchat-clientin Terminal.app, iTerm2, or any terminal. No extra “client” app. It’s just the binary. - iOS (iPhone/iPad): There’s no marchat client for iOS. Termux-style environments aren’t available the same way on Apple’s app store, and marchat doesn’t ship an iOS app. The only option is to SSH into a machine (e.g. a VPS or a Raspberry Pi) and run
marchat-clientthere, so you’re using marchat from that host, not natively on the phone.
Where to put the environment variables
You can do either of these:
-
Same terminal session – Before starting the server, run:
export MARCHAT_ADMIN_KEY="your-key" export MARCHAT_USERS="admin1,admin2" export MARCHAT_TLS_CERT_FILE="/path/to/cert.pem" export MARCHAT_TLS_KEY_FILE="/path/to/key.pem" # ... any others ./marchat-server
-
.envin the server’s config directory – The server loads a.envfile from its config directory. Create a file named.envthere with oneKEY=valueper line (noexport), for example:MARCHAT_ADMIN_KEY=your-key MARCHAT_USERS=admin1,admin2 MARCHAT_TLS_CERT_FILE=/path/to/cert.pem MARCHAT_TLS_KEY_FILE=/path/to/key.pem MARCHAT_PORT=5555The config directory is usually
./configwhen you run the server from the repo directory, or~/.config/marchatotherwise (or whatever you set withMARCHAT_CONFIG_DIR). So the file would be e.g../config/.envor~/.config/marchat/.env.
- macOS: Use the darwin build (darwin-amd64 or darwin-arm64 from the releases). Run
whats the admin key
The admin key is a secret you choose when you set up the server. Marchat doesn’t generate or assign it.
- Server: You set it with
MARCHAT_ADMIN_KEY(in the environment or in the server’s.env). That value is the “admin key” for your instance. - Client: When connecting as admin, you must supply the same value, via the “Admin Key” prompt or
--admin-key, so the server can verify you.
So it’s one shared secret: whatever you put in
MARCHAT_ADMIN_KEYon the server is the admin key you use on the client when logging in as an admin user.- Server: You set it with
thank you, i wrote .env to the marchat root folder but it doesnt seem to accept my config as the port and TLS hasn't changed
nvm while looking for config to point to i i found it was somewhere else xD
Why your
.envisn't usedThe server only loads a
.envfile from its config directory, not from the marchat repo root.- If you start the server from the repo (where
go.modis), the config directory is./config(aconfigfolder next togo.mod). Put your.envthere:config/.env. - If you run the server from somewhere else (or without
go.modin the current dir), the config directory is usually~/.config/marchat. Then the file must be~/.config/marchat/.env.
So: move (or copy) your
.envinto that config directory (e.g.config/.envwhen running from the repo) and restart the server. Port and TLS are read from that file once it's in the right place.- If you start the server from the repo (where
31 remaining items
here is localhost ig
Screencast_20260219_174827.webm
TLS (wss://)
If the server is running with TLS (you setMARCHAT_TLS_CERT_FILEandMARCHAT_TLS_KEY_FILE), use wss:// on the phone, e.g.:wss://PC_IP:5555/wsIf the cert is self-signed, the client on the phone needs to be run with
--skip-tls-verifyso it accepts that cert.
If the server is not using TLS, use ws:// instead of wss:// (e.g.ws://PC_IP:5555/ws).So: same idea as before (use the PC’s IP, not localhost), but with wss and the right port when TLS is on, and --skip-tls-verify for a self-signed cert.
any ideas
One thing that helps: connect a client from the same machine that’s running the server (e.g. a second terminal with
marchat-clientusingws://localhost:5555/wsorwss://localhost:5555/wsif you use TLS). If that works, server and config are fine and the problem is likely network or firewall between the phone and the PC. If it fails there too, fix that first (port, TLS, username, etc.), then try the phone again.localhost wont work
i'll check the config
nothing's abnormal
idk how to fix it, i'd down for you to remote control if you wanna
One more thing to try: if you're on a self-signed cert, use
--skip-tls-verifywhen launching the client, or set"skip_tls_verify": truefor that profile inprofiles.json. Calling it a night. We can pick this up tomorrow if it's still not working.okay, sleep well!
I need to see actual error output to help further. Videos of the UI don't show what's failing.
Required diagnostic output:
Server side:
# Show startup output ./marchat-server 2>&1 | tee server-log.txt # Verify it's listening ss -tlnp | grep 5555 # or whatever port
Client side (same machine as server):
# Test local connection ./marchat-client --server ws://localhost:5555/ws --username TestUser 2>&1 | tee client-log.txt
Paste the text output from both. Without actual error messages and server logs, I can't debug this.
Important: This project assumes basic familiarity with:
- Terminal/command-line usage
- TCP/IP networking (localhost vs LAN vs internet)
- Server administration basics
- Reading error logs
If you're new to self-hosting, I recommend:
- Start with the Docker image (simpler deployment)
- Get localhost working before attempting remote access
- Use GitHub Discussions for setup questions (Issues are for bugs)
- Repository owner locked and limited conversation to collaborators
on Mar 19, 2026
Create New Profile
Selected: Default
Authentication Required
Admin Key: ••••••••
Keystore passphrase: ••••••
Connecting to ws://localhost:5555/ws as BlueAzure...
Error initializing keystore: failed to decrypt keystore: cipher: message authentication failed
blueazure@Azura ~/D/M/marchat (main) [1]> marchat-client
📝 Select a connection profile or create a new one...
Select a connection profile:
▶ Default (BlueAzure@ws://localhost:5555/ws) [Admin] [E2E] [Recent]
Profile-2 (Azura@ws://localhost:5555/ws) [Admin] [E2E]
Create New Profile
Selected: Default
Authentication Required
Admin Key: ••••••••
Keystore passphrase: ••••••
Connecting to ws://localhost:5555/ws as BlueAzure...
Error initializing keystore: failed to decrypt keystore: cipher: message authentication failed
blueazure@Azura ~/D/M/marchat (main) [1]> marchat-client
📝 Select a connection profile or create a new one...
Select a connection profile:
▶ Default (BlueAzure@ws://localhost:5555/ws) [Admin] [E2E] [Recent]
Profile-2 (Azura@ws://localhost:5555/ws) [Admin] [E2E]
Create New Profile
Selected: Default
Authentication Required
Admin Key: ••••••••
Keystore passphrase: ••••••
Connecting to ws://localhost:5555/ws as BlueAzure...
Error initializing keystore: failed to decrypt keystore: cipher: message authentication failed
blueazure@Azura ~/D/M/marchat (main) [1]> marchat-client
📝 Select a connection profile or create a new one...
Select a connection profile:
▶ Default (BlueAzure@ws://localhost:5555/ws) [Admin] [E2E] [Recent]
Profile-2 (Azura@ws://localhost:5555/ws) [Admin] [E2E]
Create New Profile
Selected: Default
Authentication Required
Admin Key: ••••••
Keystore passphrase: ••••••
Connecting to ws://localhost:5555/ws as BlueAzure...
Error initializing keystore: failed to decrypt keystore: cipher: message authentication failed
blueazure@Azura ~/D/M/marchat (main) [1]> marchat-client
📝 Select a connection profile or create a new one...
Select a connection profile:
Default (BlueAzure@ws://localhost:5555/ws) [Admin] [E2E] [Recent]
Profile-2 (Azura@ws://localhost:5555/ws) [Admin] [E2E]
▶ Create New Profile
Creating a new connection profile...
🚀 marchat Configuration
Server URL: ws://localhost:5555/ws
Username: Az
Admin user? n
Enable E2E encryption? y
Keystore passphrase: ••••••
Theme: retro
[ Connect ]
✅ Configuration saved as 'Profile-3'! You can use --auto or --quick-start for faster connections.
Connecting to ws://localhost:5555/ws as Az...
Error initializing keystore: failed to decrypt keystore: cipher: message authentication failed
blueazure@Azura ~/D/M/marchat (main) [1]> marchat-client
📝 Select a connection profile or create a new one...
Select a connection profile:
Profile-3 (Az@ws://localhost:5555/ws) [E2E] [Recent]
▶ Default (BlueAzure@ws://localhost:5555/ws) [Admin] [E2E]
Profile-2 (Azura@ws://localhost:5555/ws) [Admin] [E2E]
Create New Profile
Selected: Default
Authentication Required
Admin Key: ••••••••
Keystore passphrase: ••••••
Connecting to ws://localhost:5555/ws as BlueAzure...
Error initializing keystore: failed to decrypt keystore: cipher: message authentication failed
blueazure@Azura ~/D/M/marchat (main) [1]> marchat-client
📝 Select a connection profile or create a new one...
Select a connection profile:
Default (BlueAzure@ws://localhost:5555/ws) [Admin] [E2E] [Recent]
Profile-4 (aua@ws://localhost:5555/ws)
Profile-3 (Az@ws://localhost:5555/ws) [E2E]
▶ Profile-2 (Azura@ws://localhost:5555/ws) [Admin] [E2E]
Create New Profile
Selected: Profile-2
Authentication Required
Admin Key: ••••••••
Keystore passphrase: ••••••
Connecting to ws://localhost:5555/ws as Azura...
Error initializing keystore: failed to decrypt keystore: cipher: message authentication failed
blueazure@Azura ~/D/M/marchat (main) [1]> bash test.sh
Running Marchat Test Suite
Using Go: go version go1.25.7 X:nodwarf5 linux/amd64
Running tests...
ok github.com/Cod-e-Codes/marchat/client (cached)
ok github.com/Cod-e-Codes/marchat/client/config (cached)
ok github.com/Cod-e-Codes/marchat/client/crypto (cached)
ok github.com/Cod-e-Codes/marchat/cmd/license (cached)
ok github.com/Cod-e-Codes/marchat/cmd/server (cached)
ok github.com/Cod-e-Codes/marchat/config (cached)
ok github.com/Cod-e-Codes/marchat/plugin (cached)
ok github.com/Cod-e-Codes/marchat/plugin/host (cached)
ok github.com/Cod-e-Codes/marchat/plugin/license (cached)
ok github.com/Cod-e-Codes/marchat/plugin/manager (cached)
ok github.com/Cod-e-Codes/marchat/plugin/store (cached)
ok github.com/Cod-e-Codes/marchat/server (cached)
ok github.com/Cod-e-Codes/marchat/shared (cached)
All tests passed!
Generating test coverage report...
ok github.com/Cod-e-Codes/marchat/client (cached) coverage: 25.3% of statements
ok github.com/Cod-e-Codes/marchat/client/config (cached) coverage: 54.5% of statements
ok github.com/Cod-e-Codes/marchat/client/crypto (cached) coverage: 76.9% of statements
ok github.com/Cod-e-Codes/marchat/cmd/license (cached) coverage: 42.2% of statements
ok github.com/Cod-e-Codes/marchat/cmd/server (cached) coverage: 5.3% of statements
ok github.com/Cod-e-Codes/marchat/config (cached) coverage: 74.2% of statements
ok github.com/Cod-e-Codes/marchat/plugin (cached) coverage: [no statements]
ok github.com/Cod-e-Codes/marchat/plugin/host (cached) coverage: 22.4% of statements
ok github.com/Cod-e-Codes/marchat/plugin/license (cached) coverage: 83.1% of statements
ok github.com/Cod-e-Codes/marchat/plugin/manager (cached) coverage: 22.5% of statements
ok github.com/Cod-e-Codes/marchat/plugin/store (cached) coverage: 46.8% of statements
ok github.com/Cod-e-Codes/marchat/server (cached) coverage: 33.2% of statements
ok github.com/Cod-e-Codes/marchat/shared (cached) coverage: 82.4% of statements
Coverage report generated: coverage.html
Coverage Summary:
total: (statements) 34.7%
Test suite completed successfully!
blueazure@Azura ~/D/M/marchat (main)> marchat-client
📝 Select a connection profile or create a new one...
Select a connection profile:
▶ Profile-2 (Azura@ws://localhost:5555/ws) [Admin] [E2E] [Recent]
Default (BlueAzure@ws://localhost:5555/ws) [Admin] [E2E]
Profile-4 (aua@ws://localhost:5555/ws)
Profile-3 (Az@ws://localhost:5555/ws) [E2E]
Create New Profile
Selected: Profile-2
Authentication Required
Admin Key: ••••••••
Keystore passphrase: ••••••
Connecting to ws://localhost:5555/ws as Azura...
Error initializing keystore: failed to decrypt keystore: cipher: message authentication failed
blueazure@Azura ~/D/M/marchat (main) [1]> openssl rand -hex 32
61014f45e194e5b585a18336b0bf3d795a911f533903c45adc3c3506bc441436
blueazure@Azura ~/D/M/marchat (main)> marchat-client --interactive
flag provided but not defined: -interactive
Usage of marchat-client:
-admin
Connect as admin (requires --admin-key)
-admin-key string
Admin key for privileged commands
-auto
Automatically connect using most recent profile
-config string
Path to config file (optional)
-e2e
Enable end-to-end encryption
-keystore-passphrase string
Passphrase for keystore (required for E2E)
-non-interactive
Skip interactive prompts (require all flags)
-quick-start
Use last connection or select from saved profiles
-server string
Server URL
-skip-tls-verify
Skip TLS certificate verification
-theme string
Theme
-username string
Username
blueazure@Azura ~/D/M/marchat (main) [2]> marchat-client --keystore-passphrase
flag needs an argument: -keystore-passphrase
Usage of marchat-client:
-admin
Connect as admin (requires --admin-key)
-admin-key string
Admin key for privileged commands
-auto
Automatically connect using most recent profile
-config string
Path to config file (optional)
-e2e
Enable end-to-end encryption
-keystore-passphrase string
Passphrase for keystore (required for E2E)
-non-interactive
Skip interactive prompts (require all flags)
-quick-start
Use last connection or select from saved profiles
-server string
Server URL
-skip-tls-verify
Skip TLS certificate verification
-theme string
Theme
-username string
Username
blueazure@Azura ~/D/M/marchat (main) [2]> marchat-client --keystore-passphrase 641366
📝 Select a connection profile or create a new one...
Select a connection profile:
Profile-2 (Azura@ws://localhost:5555/ws) [Admin] [E2E] [Recent]
▶ Default (BlueAzure@ws://localhost:5555/ws) [Admin] [E2E]
Profile-4 (aua@ws://localhost:5555/ws)
Profile-3 (Az@ws://localhost:5555/ws) [E2E]
Create New Profile
Selected: Default
Authentication Required
Admin Key: ••••••••
Keystore passphrase: ••••••
Connecting to ws://localhost:5555/ws as BlueAzure...
Error initializing keystore: failed to decrypt keystore: cipher: message authentication failed
blueazure@Azura ~/D/M/marchat (main) [1]> openssl rand -hex 32