Running your own internal MDM server, Part 1

Part 1 – Obtaining a push certificate


Update 2-16-2016: Unfortunately “part 2” never materialized. We eventually switched to Meraki for our MDM needs (internal software worked fine, but I no longer had time to do programming at the job and we had to get an out of the box solution). However I have uploaded all the code to github. If somebody wants to fork it and put in some decent documentation on it I would be happy to switch out my github link for your repository. Just let me know.


There is a lot of piecemeal information out on the Internet on how to run your own MDM server for iOS and Mac devices. Most of the information is accurate and helpful but none of it is all-inclusive. While I may not manage to give all-inclusive information and will certainly not get perfect step-by-step steps, I hope that it will be accurate enough to help get you going. I will be assuming that you have knowledge of command line, git, development tools, openssl and a few other things.

This is going to be a multi-part series of (slowly posted) articles. In part one I am going to cover the steps I undertook to get the MDM push certificate required to run the MDM server. At the end of this article you should be able to put your push certificate into a test server and successfully push “wake up” notifications to your devices and watch them query the MDM server.

Another point to make is that I do not intend to breach any NDA with these articles. If I accidentally post anything I shouldn’t have then I will be pulling the content immediately upon request by Apple. I do hope to publish the source code for the MDM server on github once enough is working to do something with it. Because MDM has been available for a few years and I still have not seen any open-source MDM server projects, I will probably contact Apple in the near future to verify I will not be breaking NDA by posting the code we will be running.

Finally, like many of my other projects, this may never actually go anywhere. Some of the other work I have done recently with munki, sal, django and other projects have shown me that it really shouldn’t take very long to develop a simple MDM server. My goal with this server is basically a MunkiWebAdmin type reporting for iOS devices and (and Mac) and, hopefully, basic managed preferences like MCX. At worse, the church is out $299 for one years worth of Enterprise program and I have spent a number of hours at home learning new technologies.

  1. Create a iOS Developer Enterprise account
    • Cost is $299/year.
    • You need to create a new Apple ID for this, you cannot use the same one you use with your existing iOS, Mac or Safari developer logins.
    • Your organization needs a D-U-N-S number.
    • This took about 2 days to finish and a few phone calls, one to me and one to my boss (to verify that I indeed worked for the church). In my call they asked what we planned to do with the Enterprise account. I was up front in my plans to run an in-house MDM server for asset tracking and that we didn’t want to use a third party or Profile Manager. The representative I talked to was perfectly satisfied with that answer.
  2. Contact Apple Developer Support and request your account be flagged for MDM Vendor use.
    • After your Enterprise account is active and you can login to the developer portal you need to contact support and request that you become an MDM Vendor. You can call them but I used the contact form. I simply told them in as few words as possible that we wanted to run our own minimal MDM server for improved asset tracking. Within a few hours they responded and we were all set.
  3. Create a MDM Vendor CSR
    • Fire up Keychain Access and Request a Certificate From a Certificate Authority.
    • User Email Address: Enter same e-mail address used for Apple ID.
    • Common Name: <company name> MDM (e.g. Acme Inc. MDM)
    • Request is Saved to Disk.
  4. Upload the CSR to Apple via the iOS Certificate Manager
    • Add a new certificate and select MDM CSR under the Production category.
    • Click through the one or two screens and then attach the CSR to the form.
    • When it finishes you should have a success message.
  5. Download the Apple signed certificate and load into Keychain Access
    • Inside Keychain Access under your Certificates you should have a new item called MDM Vendor: Acme Inc.
    • If you expand the certificate you should see your Acme Inc. MDM private key.
  6. Now we need to create our push certificate CSR
    • We now need a CSR for the actual push certificate.
    • Fire up Keychain Access again and run Request a Certificate From a Certificate Authority.
    • User Email Address: Enter the contact e-mail, this may be your own e-mail rather than the ADC Apple ID.
    • Common Name: <company name> Push (e.g. Acme Inc. Push)
    • Request is Saved to Disk (call it push.csr for our purposes).
  7. Export your Acme Inc. MDM private key and MDM Vendor certificate.
    • Export the private key as a .p12 file, this will include both certificate and key. Call it private.p12.
    • Extract private key: openssl pkcs12 -in private.p12 -nocerts -out key.pem
    • Extract certificate: openssl pkcs12 -in private.p12 -clcerts -nokeys -out cert.pem
    • Convert certificate to DES form: openssl x509 -in cert.pem -inform PEM -out mdm.cer -outform DES
    • Strip password from private key: openssl rsa -in key.pem -out private.key
    • These will be used in the next step to generate the special CSR for Apple to sign.
  8. Grab the mdmvendorsign tools from github
    • Run the following command from inside the cloned directory.
    • python –key private.key –csr push.csr –mdm mdm.cer –out applepush.csr
    • If all works, you should see no errors and a message telling you to go upload the file.
    • If something went wrong, do some research my friend!
  9. Generate Push certificate from Apple
  10. Import Certificate into Keychain Access (it will be called something like APSP:xxxxxx)
  11. Prepare certificate for pushing
    • Double click certificate to get the push topic to be used, it will be the Subject User ID, something like<guid>.
    • Export certificate as a p12 file, let’s call it mdm.p12
    • Next we need to convert it into a format that can be used with APNSWrapper.
    • openssl pkcs12 -in mdm.12 -out pushcert.pem -nodes
  12. You can now use pushcert.pem with APNSWrapper, or any other method you wish to push notifications with, with your MDM server.
    • Testing your certificate requires that you run some kind of MDM test server. The link above is one such test server. This is not the one I used as I had already written my own, though it was far less featured. Mine was a few lines of django code which let me see the data sent by the client when it registered. I could then take the two device identifiers and use them to manually (via APNSWrapper) push a “wakeup” command to the device and watch it query the server.
    • The link above also has some information on this process as well.
  13. IMPORTANT: Clean up after yourself! This process leaves your certificates and, more importantly, private keys all over your hard drive. Make sure you don’t leave anything laying around that somebody could use to pretend to be you. The final article should include a more stream-lined process that also cleans up along the way. Right now that is extra credit for you.

19 comments for “Running your own internal MDM server, Part 1

  1. Sharad Unni
    May 18, 2014 at 11:26 am


    I am trying to implement my Apple MDM, I have a valid PushCert.pem and Enroll.mobileconfig. The device successfully installs the Enrollment certificate and i get the token but when i try to send any MDM commands nothing happens on the device. Looks like Apple Server just consumes the command and responds with HTTP_OK (200) and does nothing. I am using APNSWrapper to send commands using the below project
    The server code is, please help


  2. May 18, 2014 at 12:10 pm

    Verify that you are using the correct push topic from the certificate (the* one). In all my testing I never got an “error” response from the push notification, even if I sent completely bogus data. If you have a packet sniffer, sniff the data going to your MDM server to see if the device is trying to contact the server. I ran into various issues with the MDM server while I was building it. Differences in the way iOS and Mac expected to receive data back from the server. For example, iOS didn’t need a Content-Length header, but Mac did. If the client tries to contact your web server after you send the push notification then the push is working, but something between the MDM server and the client when it checks in is not working. If it never tries to contact your web server (I have had it take up to 10 minutes even with my iPad on and awake) then something about the push request is not valid.

    You can also keep an eye out for the next post. I don’t know just when I will put it up, but it will go into more detail about what to do. I do not have the code published yet but I have a working (but in progress) MDM server that monitors the devices, collects info about the device and pushes managed preference settings.

  3. Sharad Unni
    May 18, 2014 at 7:57 pm

    I can confirm that my push topic is correct and i think everything seems to be correct with respect to the communication between my server and apple. I think there is something probably wrong in APNSNotificationWrapper and i want to try a Java Server application instead of a python version. Can you share your Java Server code sooner so that i can try. I am good in Java (but not so good in python) and i can definitely help you in adding more features in the code if that helps.
    Thanks for the help.

  4. May 19, 2014 at 7:33 am

    Unfortunately mine is Python / Django. Were you able to see if there was any communication at all happening between your iOS device and the MDM server after the push notification was sent? If not then the problem is (likely) something with your push request. Even if it can’t correctly contact the MDM server, it should still try if the push notification worked.

    You might also sniff traffic (via firewall) between your iOS device and the Internet and see if it receives any traffic over the push notification ports when you sent your push notification.

    Another thing to check, be sure you are using SSL communication to the MDM server with a valid certificate. I had trouble getting my devices to talk to the MDM server until I put in a valid SSL certificate, I don’t remember if that was on the Mac devices or the iOS devices (or both).

  5. Steve
    December 30, 2014 at 6:28 pm

    Great article! Will there ever be a Part 2?

  6. December 30, 2014 at 6:34 pm

    Yes. Unfortunately I cannot say when. Part 2 will likely be more of a walk through on setting up the MDM server code I wrote. It is functional in-house, but has a lot of hard-coded things I need to change out (internal domain names, etc.). Everything got held up trying to get an SCEP server built into the code, since MDM requires a client certificate. I never could get the SCEP communication to work properly and Apple has very little documentation on the SCEP part, they just say “point it at your SCEP server”.

    Anyway it is still on my list of things to do, but right now the “part 2” kind of ends with a hacked together solution. Such as at enroll time it generates the certificate and embeds it (along with the private key password) into the mobileconfig, which is kind of defeating the purpose of the security of it.

  7. September 25, 2015 at 1:45 pm

    I’m looking for a developer to build an Apple MDM. Not sure if you do consulting, or maybe know someone that can help us?

  8. September 25, 2015 at 1:48 pm

    Unfortunately I don’t on either. That is a full time job and I already have one. 🙂

  9. Dhiren
    July 27, 2016 at 4:10 am

    That was really good article. I want to try out the MDM server (with non-trusted certificate) just to prove my concept. Will I still require iOS Enterprise license? Is there anyway, I can work without enterprise licence just for development work.

  10. July 27, 2016 at 8:21 am

    Unfortunately no. You could technically create your own self-signed certificate, but it would be ignored by the client devices and they would fail to associate with the MDM server. I tried this a few times with my iPhone hooked up to Xcode debugger for logging and it kept logging something to the effect that the certificate was not signed by Apple. No amount of trying to load my own signing cert into the device first ever helped.

  11. Patricio
    September 5, 2016 at 10:54 am

    Hi, thanks for the article!
    I’m implementing a MDM solution but after create the mobileconfig file my Macbook returns a error on console:
    [MDM_SCEP_Enroll] Calling SCEPGetCACert. CA Ident: (null) –> -25300 (The specified item could not be found in the keychain.

    I’m using a self signed certificate. Could you help me? Thanks!

  12. September 5, 2016 at 12:33 pm

    I can’t give much help, but it looks like you configured the MDM profile to use SCEP for certificate enrollment. I never got this to work. From what I can tell it requires some special magic on the SCEP server that the open source ones don’t know about. If you have a Microsoft SCEP server then in theory it should work. I didn’t have one available to test against.

    The way I did them was to generate a certificate for the client at enroll time and include it in the mobileconfig.

  13. Naum
    December 14, 2016 at 1:40 am

    Hi Daniel,
    When i try to install the certificate on a real device it’s failed… can you help me? Not sure why…

  14. December 14, 2016 at 9:14 am

    Your best bet would be to plug the device into a computer via lightning and use XCode to view the device logs and see what it says when you try to install the certificate.

  15. Naum
    December 15, 2016 at 6:29 am

    Hi, again
    “The certificate for this server is invalid. You might be connecting to a server that is pretending to be “” which could put your confidential information at risk. If the server’s certificate cannot be verified using a trusted root authority, you must install the “Trust Profile” for the server.” This is what i get when i try to connect to my server … I will build your server today and try again to see if its works. If you would have just a few minutes you can add me on skype: hancnaum . Romania.
    Best regards, Hanc

  16. Naum
    December 18, 2016 at 4:35 am

    Hi Daniel,
    I build your server and it’s working. There ware some problems but i made a small documentation to can build it any1 who want’s to play whit it. Btw, nice article.
    PS: did you play Cabal :)?
    Best regards, Hanc

  17. December 18, 2016 at 11:31 am

    Glad to hear it’s working. No, never played that game. 🙂

  18. Pedram
    April 26, 2017 at 12:03 am

    I get the following error when try to install the config profile:
    Installation failed. Error: NSError:
    Desc : Profile Installation Failed
    Sugg : Profile Failed to Install
    US Desc: Profile Installation Failed
    US Sugg: Profile Failed to Install
    Domain : MCInstallationErrorDomain
    Code : 4001
    Type : MCFatalError
    …Underlying error:
    Desc : Profile Failed to Install
    Sugg : The profile “JDisc MDM” could not be installed.
    US Desc: Profile Failed to Install
    US Sugg: The profile “JDisc MDM” could not be installed.
    Domain : MCInstallationErrorDomain
    Code : 4001
    Type : MCFatalError
    …Underlying error:
    Desc : The profile “JDisc MDM” could not be installed.
    Sugg : The payload “Mobile Device Management” could not be installed.
    US Desc: The profile “JDisc MDM” could not be installed.
    US Sugg: The payload “Mobile Device Management” could not be installed.
    Domain : MCProfileErrorDomain
    Code : 1009
    Type : MCFatalError
    Params : (
    “JDisc MDM”

  19. Marcin
    November 6, 2017 at 11:18 pm

    You are awesome. I had no idea why my MDM solution is not working, your Python script save my work. Thank you!

Leave a Reply

Your email address will not be published. Required fields are marked *