Building and running on Raspberry Pi
NickSutton opened this issue · 45 comments
Hi, trying to get Grumble up and running on the Pi so I can leverage the websockets functionality.
The install go get mumble.info/grumble/cmd/grumble
Fails on a $GOPATH not set error, even when $GOPATH is explicitly set before hand and can be seen in go env
Could someone let me know what I’ve missed?
What's the output of go env
?
Thank Tim,
GOARCH="arm"
GOBIN=""
GOEXE=""
GOHOSTARCH="arm"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/pi/gocode"
GORACE=""
GOROOT="/usr/lib/go-1.7"
GOTOOLDIR="/usr/lib/go-1.7/pkg/tool/linux_arm"
CC="gcc"
GOGCCFLAGS="-fPIC -marm -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-abuild589052819=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
Not sure why you're seeing that error, but Go 1.7 is a few versions behind. It might be worthwhile to upgrade to Go 1.10 and then try to build grumble.
Cancel last! Was running with sudo
so perhaps it was unhappy with the pi username?
Anyway, install out put gave this, is this a fail or information warnings: go get mumble.info/grumble/cmd/grumble
mumble.info/grumble/cmd/grumble
../pi/gocode/src/mumble.info/grumble/cmd/grumble/server.go:1457: unknown http.Server field 'IdleTimeout' in struct literal
../pi/gocode/src/mumble.info/grumble/cmd/grumble/server.go:1461: undefined: http.ErrServerClosed
../pi/gocode/src/mumble.info/grumble/cmd/grumble/server.go:1522: server.webhttp.Shutdown undefined (type *http.Server has no field or method Shutdown)`
Thanks for your quick help!
Those errors are related to the Go version. Upgrade to 1.10 and they should go away.
OK, will try that. Installing Go on the Pi is a pain!!
Awesome, perfect install. For anyone else going down this route, here are the instructions for GoLang 1.10 on Pi (lifted from elsewhere on Git)
To install golang 1.10 (or whatever the latest version is at the time anyone is reading this):
wget https://storage.googleapis.com/golang/go1.10.linux-armv6l.tar.gz
sudo tar -C /usr/local -xvf go1.10.linux-armv6l.tar.gz
cat >> ~/.bashrc << 'EOF'
export GOPATH=$HOME/go
export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin
EOF
source ~/.bashrc
Run go version
to check and you should see output of: go version g1.10 linux/arm also this preserves /usr/bin/go is you installed it previously.
Now, excuse my blatant lack of knowledge, but what next? Does this sit on top of a mumble-server install or instead? I’ve just removed a working mumble and hope for grumble to take its place!
UPDATE:
Following reboot, setup GOPATH
$ export GOPATH=$HOME/gocode
$ mkdir -p $GOPATH
Then run the following line:
$ go get mumble.info/grumble/cmd/grumble
CD in to GOPATH/src/mumble.info/grumble/cmd/grumble and make any config changes you need before building the program: go build -o grumble mumble.info/grumble/cmd/grumble
And check ./grumble —help
this will expose the various command line switches, you will need to populate at least the following:
./grumble --datadir ~/gocode --log ~/gocode/log
Does this sit on top of a mumble-server install or instead?
The latter; grumble is a separate, standalone Mumble server. After starting grumble, you should be able to connect to your Pi from your Mumble client.
I thought so... That’s it!? So simple... Where is the configuration to add my password and define port etc?
Configuration is currently unmerged in PR #26. In the mean time, you can manually apply that patch to your local copy to enable configuration.
Wow, look like you guys have done a lot of work, and I’ve got a lot of learning to do! I wish someone had travelled this path before me (and documented it along the way!)
How do i start Grumble?
Thanks for being a trailblazer.
After building grumble (go build -o grumble mumble.info/grumble/cmd/grumble
), just run it (./grumble
). You may have to play around with the arguments (pass --help
to see available ones).
Thanks - I’m getting there... but you’re definitely right about the arguments!!
`go run grumble.go --help
command-line-arguments
./grumble.go:25:5: undefined: Args
./grumble.go:26:3: undefined: Usage
./grumble.go:31:26: undefined: Args
./grumble.go:33:56: undefined: Args
./grumble.go:39:34: undefined: Args
./grumble.go:41:62: undefined: Args
./grumble.go:48:41: undefined: Args
./grumble.go:56:27: undefined: Args
./grumble.go:68:26: undefined: Args
./grumble.go:69:25: undefined: Args
./grumble.go:69:25: too many errors
`
The --help
flag is mean for the compiled grumble binary, not go run
.
You should also use go build
to compile grumble -- go run
isn't straightforward with respect to how grumbles files are organized.
Yep, go build
command seemed to execute without any issue. ./grumble
wasn’t working though so i tried grumble.go
but no dice.?
Does ./grumble
need to be from a specific directory?
if you passed -o grumble
to go build
, then the grumble binary will appear in your current working directory.
Yes, did that. Can see the binary, but ./grumble
gives Unable to open data directory (/home/pi/.grumble): open /home/pi/.grumble: no such file or directory
Worth noting home/pi/gocode
is current GOPATH
Variable
Those errors are what I was alluding to earlier: you'll have to pass some arguments to grumble
, specifically --datadir
and --log
.
Ok! Got the help text. Is there anywhere I can write this all up for the next Pi guy?
I'd just leave it in a comment in this thread. We should hopefully get some official docs together in the future.
Ok, well I’d be happy to help!
So here’s where I’m at:
./grumble --datadir ~/gocode --log ~/gocode/log [G] 2018/04/14 13:17:30.342856 Grumble [G] 2018/04/14 13:17:30.343374 Using data directory: /home/pi/gocode [G] 2018/04/14 13:17:30.343782 Generating 4096-bit RSA keypair for self-signed certificate... [G] 2018/04/14 13:19:49.679947 Certificate output to /home/pi/gocode/cert.pem [G] 2018/04/14 13:19:49.680261 Private key output to /home/pi/gocode/key.pem [1] 2018/04/14 13:19:49.695490 Started: listening on [::]:64738 and 0.0.0.0:443 [1] 2018/04/14 13:19:49.696451 Fatal HTTP server error: listen tcp 0.0.0.0:443: bind: permission denied
How can I set my IP or, more ideally, domain name
You can either:
- Modify the source code to bind your server on a specific IP address and port, or
- Locally merge the #26 branch to enable configuration file support where you can set configuration options
Ok, 26 sounds like more flexibility in the long run, but i don’t know how to merge the files in #26.
I can look through the source files and find where to set the IP.
Thanks again for your support
Tried to merge the file changes on local machine and rebuild, once I fixed all my typos I’m still getting errors about a missing ini package “gopkg.in/ini.v1" from the new file_ini.go file . Do I need a template configuration in .ini format?
The config support adds a new external dependency, so you may have to go get gopkg.ini/ini.v1
to be able to build it. A template configuration should be automatically created on first run. However, the config support is still WIP and I recommend you merge the new changes in #26 to avoid a persistence issue before you set any config keys.
Thanks, I think I’ll keep an eye on the config support and d/l when it’s part of the git proper.
In the meantime, can you tell me where I can set the domain of my machine, also webport 443 is in use by email SSL, so will need to rename that to be able to connect to websockets?
The reason the default webport is 443 is because that will be required for the planned Let's Encrypt support. Websockets works fine on any port otherwise. Setting the config key webport
(if you're on the config branch) or editing line 40 in server.go will do the trick. If you're connecting from a browser, make sure it trusts the certificate that Grumble sends, otherwise the connection will fail.
The default host should work fine in most cases but if you need to set it it's the config key host
or line 1384 in server.go.
On Linux you can only bind to port 443 (really, allow ports <= 1024) as root -- unless you set a capability on the binary.
See for example:
https://unix.stackexchange.com/questions/10735/linux-allowing-an-user-to-listen-to-a-port-below-1024
Personally, I like this method:
https://unix.stackexchange.com/a/10737
That looks pretty advanced. 443 isnt that much of an issue to me as I can reallocate the email port, and I’m not really sure it’s a problem.
Got the script to recognise my IP now, but still have a permission denied message ( Fatal HTTP server error: listen tcp 127.0.0.1:443: bind: address already in use
) for binding to 443. Will investigate and update
Update, 443 was in use by Apache2. Changed to 442 and rebuilt, and now:
Started: listening on 127.0.0.1:64738 and 127.0.0.1:442Started: listening on 127.0.0.1:64738 and 127.0.0.1:442
woop!! Just the TLS side of thing to sort out now
Hi All,
Thanks again for the help so far. Is it possible to disable TLS/SSL for testing, I’m having difficulty getting the mumble client to connect with the Grumble generated cert.PEM file, once converted to PKCS12 format. Also, iOS Mumble app requires that certificates are imported from iTunes, which I’ve successfully avoided for nearly 5 years!! Any tips on clients that will use the generated certs, or can it be temporarily disabled?
openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile CACert.crt
I don't quite understand. There should be no need to convert the generated certificate, or import it into the client - it is meant for the server. You can't disable TLS, but nothing says the certificate needs to be trusted by the client (neither the ordinary Mumble protocol on 64738 nor Websockets require this), so the generated certificates should work fine.
Sorry for the vague answer. If you post the exact steps you are taking, I could probably give you a more concrete suggestion.
hi, thanks for reply.
so, all my connections are being refused due to SSL error. thought i might need to import the certificate from the server into the client. followed mumble client server wizard which demands a different format to PEM. A bit stuck know and sense that i am close to being accept a connection!
The client wizard configures the user certificate. Could you please post the exact error message from the client and any relevant logs (if they exist) from Grumble?
Ok, thinking it through, I may be launching grumble and not telling about the certificate with the correct flags! My bad. Will test later
So the mumble client running on another Pi does now connect.
Required to ‘Surpress certificate and password storage’ in network (Advanced) settings, guess there must have been an old one cached or something?
Still no luck from iOS - Getting a connection refused message. Is there a Grumble log that might shed more light on this?
The server running on 127.0.0.1 can still be reached externally with port forwarding cant it? I’ve not changed any port forwarding settings as it worked fine with the mumble server and we are using the same port?..
If you bind to 127.0.0.1 it is only accessible on the loopback interface locally. (It's strange that it is accessible from another Pi.) You have to bind to 0.0.0.0 to listen on all interfaces, which should be reachable externally with port forwarding as usual.
Regarding the need to surpress certificates, maybe the mismatch from the old server certificate caused a security error on the client? I know too little about the mumble client to answer this one.
That makes sense, I’ve gone back to 0.0.0.0 and can now accept connections internally and externally, so that’s great!
Regarding the websockets, has anyone written a client to view the information that is sent from the Grumble Server via WS? I manipulated an existing page, but stuck with an ‘Error during websockets handshake: ERR_INVALID_HTTP_RESPONSE message. I think this is the last piece of the puzzle for me!
Thanks again for all your help so far, I hope this helps other Pi users out!
ERR_INVALID_HTTP_RESPONSE usually indicates you haven't attempted the TLS handshake first – make sure you use the wss:// scheme and not ws:// when connecting. (If you're trying this in a browser, you should receive a 400 bad request when connecting via https - that means the TLS layer is working.) These kinds of errors should generate Grumble log messages however.
I don't know of any easy way to dump the traffic, but once the handshakes are done it's just WS messages containing the binary Mumble protocol.
Ok, changing to wss:// changes the error code to ERR_INSECURE_RESPONSE in the browser console.
Do you know what Grumble typically sends out over websockets?
ERR_INSECURE_RESPONSE means the browser doesn't trust the certificate. Since you're using the autogenerated cert, you have to either import the server cert in the browser to make it trusted (complicated, but permanent) or connect over https in the browser window to show Chromes exception ui (fast, but temporary).
I don't understand what you mean by "typically". The websocket messages only wrap the mumble protocol just like the one used over port 64738, nothing more. Grumble doesn't support any sort of RPC yet. If you want to speak the protocol in a browser I'd suggest a library like mumble-client together with mumble-client-websocket (an example built with those is mumble-web).
I’ll look in to that Chromium on Pi seems that little bit more complicated than everything else!
So, with the WebSockets, literally the only reason I’m interested is to see if I can send a message from the server to my mumble clients when a user is transmitting. I hope to display the user ID of the mumble session transmitting on all the other clients. I appreciate this may require a change to the underlying code.
I’m starting to think it might be easier to change the underlying to code to simply write to a log instead, whenever anyone transmits, and use something like WebsocketD to send out the messages whilst parsing the log. I’m not looking to build a mumble web client or anything like that.... Hopefully something much simpler!
I imported the cert and set the websocket JavaScript to connect to wss://127.0.0.1:442
and now it connects. The console shows a ‘blob’ dump, so this is good progress.
How can I edit the binary code to identify the user that is transmitting and send that either over websockets or to log?
Sending extra data over WS requires substantial modifications, as it shares the ordinary mumble protocol implementation. In essence, a WS connection is equivalent to an ordinary user connecting with an ordinary mumble client -- using it for RPC-like tasks is probably more trouble than it's worth. (Unfortunately, Grumble has no RPC support at this moment.) AFAIK, the Mumble protocol has no "talking" state and the server doesn't keep track of this anyway. (Unless you try to build a hack around requesting idle time or something like that, I guess...)
The hacky way closest to what you are describing would be to log the user id for every voice packet received by the server in the udp loops. I guess it would work but you would need to communicate this (quite spammy) info over some other channel. The proper way to solve this is probably modifying your client to expose the talking/silent state based on voice packets being received or not, just like the "standard" Mumble client. That should be compatible with any server speaking the Mumble protocol.
Hey, thanks for the reply. I guess I’m trying to use the WS for something way outside what it was designed for.
Fortunately my client is a GoLang implementation and does already log when the PTT is hit. I didn’t follow this up previously as I’d thought running WS on each client to tell the server something it already knows seemed an untidy way of achieving what i wanted. However, as WS is two way, I guess it’s not actually that bad! I’ll leave the server alone for now and see what can be done from the client...Thanks for all the support here, really good of you guys
I have grumble working on a RaspberryPi3 with LetsEncrype certificates in conjunction with mumble-web, which ran on a different machine. Being new to golang, I tried to document my efforts to get this going in a somewhat hackish way:
a) install golang
sudo apt install golang-go
go version # gives go1.11.6 linux/arm at the time of this writing
b) build grumble
This should be working now, but we will recompile later in (g)
git clone https://github.com/mumble-voip/grumble.git
cd cmd/grumble
go build
c) create the data directory
mkdir /home/pi/.grumble
d) edit args.go
I hardcoded the datadir to '/home/pi/.grumble' here, since it's not configurable.
This may not be needed, but I wanted to start the server with sudo, which would change home to root, so that was one easy way. Also, comment out the other lines, or go will complain about unused variables and not compile.
e) edit server.go
Hardcode the port here. I chose 9444, and you need to open this port in your router (and maybe also 64738 to connect with a client).
f) copy the keys.
This could probably done in a more elegant way, but I sudo copied the keys to the .grumble directory according to this information. If you don't do this, mumble-web/Chrome will not be able to connect to grumbles web sockets.
sudo su
cp /etc/letsencrypt/live/MYDOMAIN/cert.pem /home/pi/.grumble/cert.pem
cp /etc/letsencrypt/live/MYDOMAIN/privkey.pem /home/pi/.grumble/key.pem
Change MYDOMAIN to your letsencrypt domain name. Note that the clients will be able to connect, but will complain about the certificate. Maybe it would have been better to hardcode the paths to the keys in the the letsencrypt folder, I didn't try this (yet EDIT: tried it, same result).
g) build
Build with cd /home/pi/grumble/cmd/grumble; go build
again and start with sudo ./grumble
.
You should be able to connect to yourdomain.com with a mumble client and to yourdomain.com:9444 with mumble-web.