Here's a solution that may fix the problem without requiring to reset Xcode Server.
What's the problem?
First, check whether this answer applies by inspecting the xcsnginx.log
log file:
sudo tail /Library/Developer/XcodeServer/Logs/xcsnginx.log
Search for the following line at the end of the log:
nginx: [emerg] SSL_CTX_use_PrivateKey_file("/Library/Developer/XcodeServer/Certificates/xcsnginx.key") failed (SSL: error:0906A068:PEM routines:PEM_do_header:bad password read error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib)
I you don't see that entry in the log, I'm afraid this answer won't help you. If you do see that entry, you may continue.
Why does it happen?
Xcode Server internally runs an Nginx web server (on port 20543
) named xcsnginx
that acts as a proxy between some services. This server uses a TLS/SSL certificate to ensure communications remain secure. The involved files are the following:
xcsnginx.crt
: contains the PEM certificate.
xcsnginx.key
: contains the private key for the certificate.
xcsnginx.pass
: contains the passphrase for the private key.
As far as I understand, the private key is stored unencrypted, which means the xcsnginx.pass
should be empty (and seems to be reset every time Xcode Server starts).
However for some reason, as some point, the private key in xcsnginx.key
was exported as an encrypted key. I've no idea how and why this could happen but it did happen on my server so I'll assume it may happen on your server too. The consequence is that xcsnginx
cannot load the certificate and fails to launch.
You can verify that xcsnginx
is not running by executing:
pgrep xcsnginx || echo "Not running"
How to fix it?
Rather than resetting Xcode Server from scratch, we can:
- export the identity again from the
xcsnginx.keychain
keychain or
- restore the previous certificate and key or
- create a new certificate and key for
xcsnginx
.
So let's have a look at each option.
Option 1
Copies of the certificate and private key are stored in the xcsnginx.keychain
keychain located in /Library/Developer/XcodeServer/Keychains
. This keychain is protected by a passphrase stored in a file named XCSNginxKeychainSharedSecret
in the /Library/Developer/XcodeServer/SharedSecrets
folder.
If you're familiar with OS X keychains, you may retrieve the certificate and the key from the keychain.
However manipulating keychains using the command-line is a real nightmare so I'll let this as an exercise for the reader (or an editor).
Option 2
The /Library/Developer/XcodeServer/Certificates
folder may contains a backup of your certificate and key. Let's find out:
sudo find /Library/Developer/XcodeServer/Certificates -name "*.original"
If you're lucky, you should get the following result:
/Library/Developer/XcodeServer/Certificates/xcsnginx.crt.original
/Library/Developer/XcodeServer/Certificates/xcsnginx.key.original
/Library/Developer/XcodeServer/Certificates/xcsnginx.pass.original
Which mean you can restore the original files:
sudo cp /Library/Developer/XcodeServer/Certificates/xcsnginx.crt.original /Library/Developer/XcodeServer/Certificates/xcsnginx.crt
sudo cp /Library/Developer/XcodeServer/Certificates/xcsnginx.key.original /Library/Developer/XcodeServer/Certificates/xcsnginx.key
sudo cp /Library/Developer/XcodeServer/Certificates/xcsnginx.pass.original /Library/Developer/XcodeServer/Certificates/xcsnginx.pass
Option 3
If you cannot restore the previous certificate and keychains, you may decide to just generate new ones like this:
sudo openssl req -new -x509 -newkey rsa:2048 -nodes -out /Library/Developer/XcodeServer/Certificates/xcsnginx.crt -keyout /Library/Developer/XcodeServer/Certificates/xcsnginx.key -subj /CN=your-server.example.com -days 1000 -batch
where your-server.example.com
is replaced with the DNS address of your server. Ideally the certificate should be issued by the Xcode Server Root Certificate Authority but using a single-signed certificate doesn't seem to be a problem (as far as I now / for the moment / your mileage may vary).
Finally
Now we just have to wait until the system starts xcsnginx
again. That should happen automatically after a minute or less. You can verify that xcsnginx
did start with:
pgrep xcsnginx || echo "Not running"