Tiny Deathstars of Foulness

December 29th, 2017

Posted In: MacAdmins Podcast

Tags: , , , , ,

Leave a Comment

My latest Huffington Post article, called 20 Constants In Software Development is up. It starts out like this:

There are so many things I wish people had told me when I was in school, or earlier in my career. Things that aren’t variable between organizations you work with, or even teams you work in. So I thought I’d jot a few down of these for software development teams (if only to prove that no, despite what product managers say, you aren’t crazy). So here goes:

  1. A project will never have enough people to build all the features you want. Period.
  2. Less features means fewer defects.
  3. As a software project nears completion the amount of work remaining rises in proportion to how many hacks and shortcuts you took.
Read more…

December 11th, 2017

Posted In: Articles and Books, Programming

Tags: , , ,

High Sierra sees the Caching service moved out of macOS Server and into the client macOS. This means administrators no longer need to run the Server app on caching servers. Given the fact that the Caching service only stores volatile data easily recreated by caching updates again, there’s no need to back the service up, and it doesn’t interact with users or groups, so it’s easily divested from the rest of the Server services.

And the setup of the Caching service has never been easier. To do so, first open System Preferences and click on the Sharing System Preferences pane.

From here, click on the checkbox for Content Caching to start the service.

At the Content Caching panel, the service will say “Content Caching: On” once it’s running. Here, you can disable the “Cache iCloud content” option, which will disable the caching of user data supplied for iCloud (everything in here is encrypted, by the way). You can also choose to share the Internet Connection, which will create a wireless network that iOS devices can join to pull content. 

Click Options. Here, you can see how much storage is being used and limit the amount used. 

defaults read /Library/Preferences/

Which returns the following configurable options:

Activated = 1;
CacheLimit = 0; DataPath = “/Library/Application Support/Apple/AssetCache/Data”; LastConfigData = <BIGLONGCRAZYSTRING>; LastConfigURL = “”; LastPort = 56452; LastRegOrFlush = “2017-09-11 16:32:56 +0000”; LocalSubnetsOnly = 1; PeerLocalSubnetsOnly = 1; Port = 0; Region = 263755EFEF1C5DA178E82754D20D47B6; ReservedVolumeSpace = 2000000000; SavedCacheDetails = {
SavedCacheSize = 0;
ServerGUID = “EB531594-B51E-4F6A-80B9-35081B924629”;
Version = 1;}

This means that all those settings that you used to see in the GUI are still there, you just access them via the command line, by sending defaults commands. For example, 

defaults write /Library/Preferences/ CacheLimit -int 20000000000

You can

AssetCacheManagerUtil status

Which returns something similar to the following:

2017-09-11 11:49:37.427 AssetCacheManagerUtil[23957:564981] Built-in caching server status: {
Activated = 1;
Active = 1;
CacheDetails = {
iCloud = 4958643;
“iOS Software” = 936182434;};
CacheFree = 472585174016;
CacheLimit = 0;
CacheStatus = OK;
CacheUsed = 941141077;
Parents = ();
Peers = ();
PersonalCacheFree = 472585174016;
PersonalCacheLimit = 0;
PersonalCacheUsed = 4958643;
Port = 56452;
PrivateAddresses = (“”);
PublicAddress = “”;
RegistrationStatus = 1;
RestrictedMedia = 0;
ServerGUID = “EB531594-B51E-4F6A-80B9-35081B924629”;
StartupStatus = OK;
TotalBytesDropped = 0;
TotalBytesImported = 4958643;
TotalBytesReturnedToChildren = 0;
TotalBytesReturnedToClients = 166627405;
TotalBytesReturnedToPeers = 0;
TotalBytesStoredFromOrigin = 166627405;
TotalBytesStoredFromParents = 0;
TotalBytesStoredFromPeers = 0;

You can also use AssetCacheManagerUtil to manage tasks previously built into the Server app. To see the available options, simply run the command:

bash-3.2# /usr/bin/AssetCacheManagerUtil

Which would show the following:

Options are:
-a|–all show all events
-j|–json print results in JSON
-l|–linger don’t exit
2017-09-11 11:57:30.066 AssetCacheManagerUtil[24213:569932] Commands are:
moveCacheTo path
absorbCacheFrom path read-only|and-destroy

As such, to enable the server:

bash-3.2# /usr/bin/AssetCacheManagerUtil activate 

To disable the server

bash-3.2# /usr/bin/AssetCacheManagerUtil deactivate

To check if the server can be activated

bash-3.2# /usr/bin/AssetCacheManagerUtil canActivate

To flush the cache of assets on the server:

bash-3.2# /usr/bin/AssetCacheManagerUtil flushCache 

To reload settings if you make any changes:

bash-3.2# /usr/bin/AssetCacheManagerUtil reloadSettings

To move the database

/usr/bin/AssetCacheManagerUtil moveCacheTo "/Volumes/SONY/Library/Application Support/Apple/AssetCache/Data"

Finally, if you’d like to see the caching server your client system is using, you can run the following command:

/usr/bin/AssetCacheLocatorUtil 2>&1 | grep guid | awk '{print$4}' | sed 's/^\(.*\):.*$/\1/' | uniq

And if you use Jamf Pro and would like to use this as an extension attribute, that’s posted here: I didn’t do any of the if/then there, as I’d usually just do that on the JSS.

Note: To see how AssetCache interacts with Tetherator, see Tethered Caching of iOS Assets from macOS 10.12.4.

September 28th, 2017

Posted In: Mac OS X, Mac OS X Server

Tags: , , , , , ,

The first thing you’ll want to do on any server is setup the networking for the computer. To do this, open the System Preferences and click on Network. You usually want to use a wired Ethernet connection on a server, but in this case we’ll be using Wi-Fi. Here, click on the Wi-Fi interface and then click on the Advanced… button.

At the setup screen for the interface, provide a good static IP address. Your network administrator can provide this fairly easily. Here, make sure you have an IP address and a subnet mask. Since we need to install the Server app from the Mac App Store, and that’s on the Internet, you’ll also need to include a gateway, which provides access to the Internet and using the DNS tab, the name servers for your Internet Service Provider (ISP).
Once you have provided a static IP address, verify that you can route to the Internet (e.g. open Safari and visit a website). Provided you can, the first step to installing macOS Server onto High Sierra is to download the Server app from the Mac App Store. To do so, open the App Store app and search for Server. In the available apps, you’ll see the Server app from Apple. Here, click on Buy and let the app download. That was pretty easy, right. Well, the fun has just gotten started. Next, open the app.

When you first open the Server app, you’ll see the Server screen. Here, you can click on the following options:
  • Other Mac: Shows a list of Macs with the Server app that can be remotely configured. Choosing another system does not complete the setup process on the system you’re working on at the moment.
  • Cancel: Stops the Server app setup assistant and closes the Server App.
  • Continue: Continues installing the Server app on the computer you are using.
  • Help: Brings up the macOS Server manual.

Click Continue to setup macOS Server on the machine you’re currently using. You’ll then be prompted for the licensing agreement from Apple. Here, check the box to “Use Apple services to determine this server’s Internet reachability” and click on Agree (assuming of course that you agree to Apple’s terms in the license agreement).

Installing macOS Server must be done with elevated privileges. At the prompt, enter the credentials for an account with administrative access and click on the Allow button.

The services are then configured as needed and the command line tools are made accessible. This can take some time, so be patient. When the app is finished with the automation portion of the configuration, you will be placed into the Server app for the first time. Your first order of business is to make sure that the host names are good on the computer. Here, first check the Host Name. If the name doesn’t resolve properly (forward and reverse) then you will likely have problems with the server at some point. Therefore, go ahead and click on Edit Host Name… Here, enter the fully qualified address that the server should have. In the DNS article, we’ll look at configuring a good DNS server, but for now, keep in mind that you’ll want your DNS record that points to the server to match what you enter here. And users will use this address to access your server, so use something that is easy to communicate verbally, when needed.

At the Change Host Name screen, click Next. At the “Accessing your Server” screen, click on Internet and then click on the Next button.

At the “Connecting to your Server” screen, provide the Computer Name and the Host Name. The Computer Name is what you will see when you connect to the server over Bonjour and what will be listed in the Sharing System Preference pane. The Host Name is the fully qualified host name (fqdn) of the computer. I usually like to take the computer name and put it in front of the domain name. For example, in the following screen, I have osxserver as the name of the computer and as the host name.

Once you have entered the names, click on the Finish button. You are then prompted to Change Host Name. Click on Change Host Name at this screen.

Next, let’s open Terminal and run changeip with the -checkhostname option, to verify that the IP and hostname match:

sudo changeip -checkhostname

Provided that the IP address and hostname match, you’ll see the following response.

sudirserv:success = “success”

If the IP address and hostname do not match, then you might want to consider enabling the DNS server and configuring a record for the server. But at this point, you’ve finished setting up the initial server and are ready to start configuring whatever options you will need on the server.

September 28th, 2017

Posted In: Mac OS X, Mac OS X Server, Mac Security, Mass Deployment

Tags: , , , , ,

In order to use the Apple Volume Purchase Program (VPP), you will need an MDM solution (Profile Manager, Jamf Pro, MobileIron, Meraki, FileWave, etc). The same program is used for device-based VPP or user-based VPP. There are two programs, which is meant to simplify the experience of setting up an MDM solution and long-term maintenance. The first is the traditional VPP account, available to companies and other non-educational environments that have a DUNS number. The second is the newer Apple School Manager, for educational institutions.

Before starting to buy apps and associating those apps from an MDM solution, there are a few things you should know. The first is that your organization can have multiple VPP tokens or Apple School Manager tokens, and you can hierarchically manage apps this way. The second is that each token should only be installed on one MDM solution or server (if you have multiple instances of the same solution). Therefore, if you’re going to have multiple servers or solutions for managing apps, keep in mind to buy apps for groups based on the VPP account that will be associated with devices for each solution. Also, note that the traditional deployment mechanism of VPP is user, or Apple ID-based VPP apps. Here, you associate an Apple ID to a VPP account from an MDM and then the administrator sends apps to devices based via the MDM solution. And this is still an option.

In 10.11 and up, we got device-based VPP. Here, you can send apps to devices even if they don’t have Apple IDs associated to the device, and you can send apps automatically, meaning they will not require user interaction. This makes VPP multi-tenant and great for school labs, or shared-use Macs and iOS devices. But this article isn’t about the fine print details of the new VPP. Instead, this article is about making Profile Manager work with your new VPP token. Before you get started, know that when you install your vpptoken, if it’s in use by another MDM, Profile Manager will unlicensed all apps with your other MDM. To get started, log into your VPP account. Once logged in, click on your account email address and then select Account Summary.

Then, click on the Download Token link and your token will be downloaded to your ~/Downloads (or wherever you download stuff).

Once you have your token, open the Server app and click on the Profile Manager service.


Click on the checkbox for Volume Purchase Program.


At the VPP Managed Distribution screen, drag the .vpptoken file downloaded earlier into the screen. Then click on Continue. The VPP code email address will appear in the screen. Click Done. Back at the profile manager screen, you should then see that the checkbox is filled and you can now setup Profile Manager. The rest of the configuration of Profile Manager is covered in a previous article. Note: The account used to configure the VPP information is not tracked in any serveradmin settings.

September 28th, 2017

Posted In: Mac OS X, Mac OS X Server, Mass Deployment

Tags: , , , ,

There are a couple of ways to create groups in macOS Server 5.4, running on High Sierra. The first is using the Server app, the second is using the Users & Groups System Preference pane and the third is using the command line. In this article we will look at creating groups in the directory service with the Server app.

Once a server has been an Open Directory Master all user and group accounts created will be in the Local Network Group when created in Server app. Before that, all user and group objects are stored locally when created in Server app. Once promoted to an Open Directory server, groups are created in the Open Directory database or if you select it from the directory domain drop-down list, locally. Groups can also be created in both locations, using a command line tool appropriate for group management.

To create a new group, open the Server app and then click on Groups in the ACCOUNTS list of the Server app sidebar. From here, you can switch between the various directory domains accessible to the server using the drop-down list available. Click on the plus sign to create a local network group.
At the New Group screen, provide a name for the group in the Full Name field. This can have spaces. Then create a short name for the group in the Group Name field. This should not have spaces.
Click Done when you have supplied the appropriate information and the group is created. Once done, double-click on the group to see more options.
Here, use the plus sign (“+”) to add members to the group or highlight members and use the minus sign (“-“) to remove users from the group. You can also choose to use the following options:
  • Mailing Lists: Lists that are connected to the group.
  • Members: The users that are part of the group
  • Give this group a shared folder: Creates a shared directory for the group, or a group with an ACL that grants all group members access.
  • Make group members Messages buddies: Adds each group member to each other group members buddy list in the Messages client.
  • Enable group mailing list: Enables a list using the short name of the group where all members receive emails to that address.
  • Create Group Wiki: Opens the Wiki interface for creating a wiki for the group.
  • Keywords: Keywords/tags to help locate users.
  • Notes: Notes about users.
Once changes have been made, click Done to commit the changes.

September 28th, 2017

Posted In: Mac OS X Server

Tags: , , , , , , , ,

You might be happy to note that other than the ability to interpret new payloads, the profiles command mostly stays the same in High Sierra. You can still export profiles from Apple Configurator or Profile Manager (or some of the 3rd party MDM tools). You can then install profiles by just opening them and installing.

Once profiles are installed on a Mac, mdmclient, a binary located in /usr/libexec will process changes such as wiping a system that has been FileVaulted (note you need to FileVault if you want to wipe an OS X Lion client computer). /System/Library/LaunchDaemons and /System/Library/LaunchAgents has a mdmclient daemon and agent respectively that start it up automatically. This, along with all of the operators remains static from 10.10 and on. To script profile deployment, administrators can add and remove configuration profiles using the new /usr/bin/profiles command. To see all profiles, aggregated, use the profiles command with just the -P option:

/usr/bin/profiles -P

If there are no profiles installed, you’ll see a message similar to the following: There are no configuration profiles installed As with managed preferences (and piggy backing on managed preferences for that matter), configuration profiles can be assigned to users or computers. To see just user profiles, use the -L option:

/usr/bin/profiles -L

If there aren’t any profiles in the System Domain, you’ll see a message similar to the following:

There are no configuration profiles installed in the system domain

You can remove all profiles using -D:

/usr/bin/profiles -D

You’ll then see a prompt to remove all profiles, enter y to do so or n to skip:

Are you sure you want to remove all device configuration profiles? [y/n]

The -I option installs profiles and the -R removes profiles. Use -p to indicate the profile is from a server or -F to indicate it’s source is a file. To remove a profile:

/usr/bin/profiles -R -F /tmp/HawkeyesTrickshot.mobileconfig

To remove one from a server:

/usr/bin/profiles -R -p com.WestCoastAvengers.HawkeyesTrickshot

The following installs HawkeyesTrickshot.mobileconfig from your desktop:

/usr/bin/profiles -I -F ~/Desktop/HawkeyesTrickshot.mobileconfig

If created in Profile Manager:

/usr/bin/profiles -I -p com.WestCoastAvengers.HawkeyesTrickshot

You can configure profiles to install at the next boot, rather than immediately. Use the -s to define a startup profile and take note that if it fails, the profile will attempt to install at each subsequent reboot until installed. To use the command, simply add a -s then the -F for the profile and the -f to automatically confirm, as follows (and I like to throw in a -v usually for good measure):

profiles -s -F /Profiles/SuperAwesome.mobileconfig -f -v

And that’s it. Nice and easy and you now have profiles that only activate when a computer is started up. As of OS X Yosemite, the dscl command got extensions for dealing with profiles as well. These include the available MCX Profile Extensions: -profileimport -profiledelete -profilelist [optArgs] -profileexport -profilehelp

To list all profiles from an Open Directory object, use 
-profilelist. To run, follow the dscl command with -u to specify a user, -P to specify the password for the user, then the IP address of the OD server (or name of the AD object), then the profilelist verb, then the relative path. Assuming a username of diradmin for the directory, a password of moonknight and then cedge user:

dscl -u diradmin -P moonknight profilelist /LDAPv3/

To delete that information for the given user, swap the profilelist extension with profiledelete:

dscl -u diradmin -P apple profilelist /LDAPv3/

If you would rather export all information to a directory called ProfileExports on the root of the drive:

dscl -u diradmin -P moonknight profileexport . all -o /ProfileExports

In Yosemite we got a few new options (these are all still in 10.11 with no new operators), such as -H which shows whether a profile was installed, -z to define a removal password and -o to output a file path for removal information. Also, as in Yosemite it seems as though if a configuration profile was pushed to you from MDM, you can’t remove it (fyi, I love having the word fail as a standalone in verbose output):
bash-3.2# profiles -P _computerlevel[1] attribute: profileIdentifier: 772BED54-5EDF-4987-94B9-654456CF0B9A _computerlevel[2] attribute: profileIdentifier: 00000000-0000-0000-A000-4A414D460003 _computerlevel[3] attribute: profileIdentifier: C11672D9-9AE2-4F09-B789-70D5678CB397 charlesedge[4] attribute: profileIdentifier: com.krypted.office365.a5f0e328-ea86-11e3-a26c-6476bab5f328 charlesedge[5] attribute: profileIdentifier: _computerlevel[6] attribute: profileIdentifier: EE08ABE9-5CB8-48E3-8E02-E46AD0A03783 _computerlevel[7] attribute: profileIdentifier: F3C87B6E-185C-4F28-9BA7-6E02EACA37B1 _computerlevel[8] attribute: profileIdentifier: 24DA416D-093A-4E2E-9E6A-FEAD74B8B0F0 There are 8 configuration profiles installed bash-3.2# profiles -r 772BED54-5EDF-4987-94B9-654456CF0B9A bash-3.2# profiles -P _computerlevel[1] attribute: profileIdentifier: F3C87B6E-185C-4F28-9BA7-6E02EACA37B1 _computerlevel[2] attribute: profileIdentifier: EE08ABE9-5CB8-48E3-8E02-E46AD0A03783 _computerlevel[3] attribute: profileIdentifier: 24DA416D-093A-4E2E-9E6A-FEAD74B8B0F0 _computerlevel[4] attribute: profileIdentifier: 00000000-0000-0000-A000-4A414D460003 _computerlevel[5] attribute: profileIdentifier: 772BED54-5EDF-4987-94B9-654456CF0B9A _computerlevel[6] attribute: profileIdentifier: C11672D9-9AE2-4F09-B789-70D5678CB397 charlesedge[7] attribute: profileIdentifier: charlesedge[8] attribute: profileIdentifier: com.krypted.office365.a5f0e328-ea86-11e3-a26c-6476bab5f328 There are 8 configuration profiles installed bash-3.2# profiles -rv 772BED54-5EDF-4987-94B9-654456CF0B9A profiles: verbose mode ON profiles: returned error: -204 fail
The -N option will re-run the DEP enrollment:

profiles -N

A list of command verbs found using “profiles -help”:

Command Verbs:
status – indicates if profiles are installed
list – list profile information
show – show expanded profile information
install – install profile
remove – remove profile
sync – synchronize installed configuration profiles with known users
renew – renew configuration profile installed certificate
version – display tool version number

Options: (not all options are meaningful for a command)
-type= – type of profile; either ‘configuration’,
‘provisioning’, ‘enrollment’, or ‘startup’
-user= – short user name
-identifier= – profile identifier
-path= – file path
-uuid= – profile UUID
-enrolledUser= – enrolled user name
-verbose – enable verbose mode
-forced – when removing profiles, automatically confirms requests
-all – select all profiles
-quiet – enable quiet mode

September 27th, 2017

Posted In: Mac OS X, Mac OS X Server

Tags: , , , , , , ,

Web Services in macOS Server, Linux and most versions of Unix are provided by Apache, an Open Source project that much of the Internet owes its origins to. Apache owes its name to the fact that it’s “a patchy” service. These patches are often mods, or modules. Configuring web services is as easy in macOS Server 5.4, running on High Sierra (10.13), as it has ever been.

To set up the default web portal, simply open the Server app, click on the Websites service and click on the ON button.

After a time, the service will start. Once running, click on the View Server Website link at the bottom of the pane.

Provided the stock macOS Server page loads, you are ready to use macOS Server as a web server.

Before we setup custom sites, there are a few things you should know. The first is, the server is no longer really designed to remove the default website. So if you remove the site, your server will exhibit inconsistent behavior. Also, don’t remove the files that comprise the default site. Instead just add sites, which is covered next. Webmail is gone. You don’t have to spend a ton of time looking for it as it isn’t there. Also, Mountain Lion Server added web apps, which we’ll briefly review later in this article as well, as those continue in Mavericks Server, Yosemite Server, El Capitan Server and ultimately macOS Server 5.2 for Sierra and macOS Server 5.4 for High Sierra.  Finally, enabling PHP and Python on sites is done globally, so this setting applies to all sites hosted on the server.

Now that we’ve got that out of the way, let’s add our first custom site. Do so by clicking on the plus sign. At the New Web Site pane, you’ll be prompted for a number of options. The most important is the name of the site, with other options including the following:
  • Domain Name: The name the site is accessible from. The default sites do not have this option as they are accessible from all names that resolve to the server.
  • IP Address: The IP address the site listens on. Any means the site is available from every IP address the server is configured to use. The default websites do not have this option as they are accessible from all addresses automatically
  • Port: By default, sites without SSL run on port 80 on all network interfaces, and sites with SSL run on port 443 on all network interfaces. Use the Port field to use custom ports (e.g., 8080). The default sites do not have this option as they are configured to use 80 and 443 for default and SSL-based communications respectively.
  • SSL Certificate: Loads a list of SSL certificates installed using Keychain or the SSL Certificate option in the Settings pane of the Server application
  • Store Site Files In: The directory that the files that comprise the website are stored in. These can be placed into the correct directory using file shares or copying using the Finder. Click on the drop-down menu and then select Other to browse to the directory files are stored in.
  • Who Can Access: By default Anyone (all users, including unauthenticated guests) can access the contents of sites. Clicking on Anyone and then Customize… brings up the “Restrict access to the following folders to a chosen group” screen, where you can choose web directories and then define groups of users who can access the contents.
  • Additional Domains: Click on the Edit… button to bring up a simple list of domain names the the site also responds for (e.g. in addition to, add
  • Redirects: Click on the Edit… button to bring up a list of redirects within the site. This allows configuring redirects to other sites. For example, use /en to load or /cn to load
  • Aliases: Click on the Edit… button to load a list of aliases. This allows configuring redirects to folders within the same server. For example, /en loads /Library/Server/Web/Data/Sites/Default
  • Index Files: Click on the Edit… button to bring up a list of pages that are loaded when a page isn’t directly indicated. For example, when visiting, load the wp.php page by default.
  • Advanced Options: The remaining options are available by clicking on the “Edit Advanced Settings…” button.

The Advanced Option include the following:
  • Enable Server Side Includes: Allows administrators to configure leveraging includes in web files, so that pieces of code can be used across multiple pages in sites.
  • Allow overrides using .htaccess files: Using a .htaccess file allows administrators to define who is able to access a given directory, defining custom user names and passwords in the hidden .htaccess file. These aren’t usually required in an OS X Server web environment as local and directory-based accounts can be used for such operations. This setting enables using custom .htaccess files instead of relying on Apple’s stock web permissions.
  • Allow folder listing: Enables folder listings on directories of a site that don’t have an Index File (described in the non-Advanced settings earlier).
  • Allow CGI execution: Enables CGI scripts for the domain being configured.
  • Use custom error page: Allows administrators to define custom error pages, such as those annoying 404 error pages that load when a page can’t be found
  • Make these web apps available on this website: A somewhat advanced setting, loads items into the webapps array, which can be viewed using the following command:  sudo serveradmin settings web:definedWebApps
Once you’ve configured all the appropriate options, click on Done to save your changes. The site should then load. Sites are then listed in the list of Websites.

The Apache service is most easily managed from the Server app, but there are too many options in Apache to really be able to put into a holistic graphical interface. The easiest way to manage the Websites service in OS X Yosemite Server is using the serveradmin command. Apache administrators from other platforms will be tempted to use the apachectl command to restart the Websites service. Instead, use the serveradmin command to do so. To start the service:

sudo serveradmin start web

To stop the service(s):

sudo serveradmin stop web

And to see the status:

sudo serveradmin fullstatus web

Fullstatus returns the following information:
web:health = _empty_dictionary
web:readWriteSettingsVersion = 1
web:apacheVersion = “2.4”
web:servicePortsRestrictionInfo = _empty_array
web:startedTime = “2017-08-26 02:38:57 +0000”
web:apacheState = “RUNNING”
web:statusMessage = “”
web:ApacheMode = 2
web:servicePortsAreRestricted = “NO”
web:state = “RUNNING”
web:setStateVersion = 1

While the health option typically resembles kiosk computers in the Computer Science departments of most major universities, much of the rest of the output can be pretty helpful including the Apache version, whether the service is running, any restrictions on ports and the date/time stamp that the service was started.

To see all of the settings available to the serveradmin command, run it, followed by settings and then web, to indicate the Websites service:

sudo serveradmin settings web

The output is pretty verbose and can be considered in two sections, the first includes global settings across sites as well as the information for the default sites that should not be deleted:
web:defaultSite:documentRoot = “/Library/Server/Web/Data/Sites/Default”
web:defaultSite:serverName = “”
web:defaultSite:realms = _empty_dictionary
web:defaultSite:redirects = _empty_array
web:defaultSite:enableServerSideIncludes = no
web:defaultSite:networkAccesses = _empty_array
web:defaultSite:customLogPath = “&quot;/var/log/apache2/access_log&quot;”
web:defaultSite:webApps = _empty_array
web:defaultSite:sslCertificateIdentifier = “”
web:defaultSite:fullSiteRedirectToOtherSite = “https://%{SERVER_NAME}”
web:defaultSite:allowFolderListing = no
web:defaultSite:serverAliases = _empty_array
web:defaultSite:errorLogPath = “&quot;/var/log/apache2/error_log&quot;”
web:defaultSite:fileName = “/Library/Server/Web/Config/apache2/sites/0000_127.0.0.1_34580_.conf”
web:defaultSite:aliases = _empty_array
web:defaultSite:directoryIndexes:_array_index:0 = “index.html”
web:defaultSite:directoryIndexes:_array_index:1 = “index.php”
web:defaultSite:directoryIndexes:_array_index:2 = “default.html”
web:defaultSite:allowAllOverrides = no
web:defaultSite:identifier = “67127006”
web:defaultSite:port = 34580
web:defaultSite:allowCGIExecution = no
web:defaultSite:serverAddress = “”
web:defaultSite:requiresSSL = no
web:defaultSite:proxies = _empty_dictionary
web:defaultSite:errorDocuments = _empty_dictionary
The second section is per-site settings, with an array entry for each site:
web:customSites:_array_index:0:documentRoot =
“/Library/Server/Web/Data/Sites/” web:customSites:_array_index:0:serverName = “”
web:customSites:_array_index:0:realms = _empty_dictionary
web:customSites:_array_index:0:redirects = _empty_array
web:customSites:_array_index:0:enableServerSideIncludes = no
web:customSites:_array_index:0:networkAccesses = _empty_array
web:customSites:_array_index:0:customLogPath = “/var/log/apache2/access_log”
web:customSites:_array_index:0:webApps = _empty_array
web:customSites:_array_index:0:sslCertificateIdentifier = “”
web:customSites:_array_index:0:fullSiteRedirectToOtherSite = “”
web:customSites:_array_index:0:allowFolderListing = no
web:customSites:_array_index:0:serverAliases = _empty_array
web:customSites:_array_index:0:errorLogPath = “/var/log/apache2/error_log”
web:customSites:_array_index:0:fileName = “/Library/Server/Web/Config/apache2/sites/”
web:customSites:_array_index:0:aliases = _empty_array
web:customSites:_array_index:0:directoryIndexes:_array_index:0 = “index.html”
web:customSites:_array_index:0:directoryIndexes:_array_index:1 = “index.php”
web:customSites:_array_index:0:directoryIndexes:_array_index:2 = “default.html”
web:customSites:_array_index:0:allowAllOverrides = no
web:customSites:_array_index:0:identifier = “67127002”
web:customSites:_array_index:0:port = 34580
web:customSites:_array_index:0:allowCGIExecution = no
web:customSites:_array_index:0:serverAddress = “”
web:customSites:_array_index:0:requiresSSL = no
web:customSites:_array_index:0:proxies = _empty_dictionary
web:customSites:_array_index:0:errorDocuments = _empty_dictionary
web:dataLocation = “/Library/Server/Web/Data”
The next section (the largest by far) includes array entries for each defined web app. The following shows the entry for a Hello World Python app
web:definedWebApps:_array_index:0:requiredWebAppNames = _empty_array
web:definedWebApps:_array_index:0:includeFiles:_array_index:0 = “/Library/Server/Web/Config/apache2/httpd_ACSServer.conf”
web:definedWebApps:_array_index:0:requiredModuleNames:_array_index:0 = “”
web:definedWebApps:_array_index:0:startCommand = “”
web:definedWebApps:_array_index:0:sslPolicy = 1
web:definedWebApps:_array_index:0:requiresSSL = no
web:definedWebApps:_array_index:0:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:0:launchKeys:_array_index:0 = “”
web:definedWebApps:_array_index:0:proxies:/AccountsConfigService/api/:path = “/AccountsConfigService/api/”
web:definedWebApps:_array_index:0:proxies:/AccountsConfigService/api/:urls:_array_index:0 = “http://localhost:31415/AccountsConfigService/api”
web:definedWebApps:_array_index:0:preflightCommand = “”
web:definedWebApps:_array_index:0:stopCommand = “”
web:definedWebApps:_array_index:0:name = “”
web:definedWebApps:_array_index:0:displayName = “”
web:definedWebApps:_array_index:1:requiredWebAppNames:_array_index:0 = “”
web:definedWebApps:_array_index:1:includeFiles:_array_index:0 = “/Library/Server/Web/Config/apache2/httpd_corecollaboration_webauth.conf”
web:definedWebApps:_array_index:1:requiredModuleNames:_array_index:0 = “proxy_module”
web:definedWebApps:_array_index:1:requiredModuleNames:_array_index:1 = “headers_module”
web:definedWebApps:_array_index:1:startCommand = “”
web:definedWebApps:_array_index:1:sslPolicy = 4
web:definedWebApps:_array_index:1:requiresSSL = no
web:definedWebApps:_array_index:1:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:1:launchKeys = _empty_array
web:definedWebApps:_array_index:1:proxies:/auth:path = “/auth”
web:definedWebApps:_array_index:1:proxies:/auth:urls:_array_index:0 = “http://localhost:4444/auth”
web:definedWebApps:_array_index:1:preflightCommand = “”
web:definedWebApps:_array_index:1:stopCommand = “”
web:definedWebApps:_array_index:1:name = “”
web:definedWebApps:_array_index:1:displayName = “”
web:definedWebApps:_array_index:2:requiredWebAppNames:_array_index:0 = “”
web:definedWebApps:_array_index:2:includeFiles:_array_index:0 = “/Library/Server/Web/Config/apache2/httpd_corecollaboration_webcalssl.conf”
web:definedWebApps:_array_index:2:requiredModuleNames:_array_index:0 = “proxy_module”
web:definedWebApps:_array_index:2:requiredModuleNames:_array_index:1 = “headers_module”
web:definedWebApps:_array_index:2:startCommand = “”
web:definedWebApps:_array_index:2:sslPolicy = 1
web:definedWebApps:_array_index:2:requiresSSL = no
web:definedWebApps:_array_index:2:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:2:launchKeys = _empty_array
web:definedWebApps:_array_index:2:proxies = _empty_dictionary
web:definedWebApps:_array_index:2:preflightCommand = “”
web:definedWebApps:_array_index:2:stopCommand = “”
web:definedWebApps:_array_index:2:name = “”
web:definedWebApps:_array_index:2:displayName = “”
web:definedWebApps:_array_index:3:requiredWebAppNames:_array_index:0 = “”
web:definedWebApps:_array_index:3:includeFiles:_array_index:0 = “/Library/Server/Web/Config/apache2/httpd_corecollaboration_changepassword.conf”
web:definedWebApps:_array_index:3:requiredModuleNames:_array_index:0 = “proxy_module”
web:definedWebApps:_array_index:3:requiredModuleNames:_array_index:1 = “headers_module”
web:definedWebApps:_array_index:3:startCommand = “”
web:definedWebApps:_array_index:3:sslPolicy = 4
web:definedWebApps:_array_index:3:requiresSSL = no
web:definedWebApps:_array_index:3:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:3:launchKeys = _empty_array
web:definedWebApps:_array_index:3:proxies:/changepassword:path = “/changepassword”
web:definedWebApps:_array_index:3:proxies:/changepassword:urls:_array_index:0 = “http://localhost:4444/changepassword”
web:definedWebApps:_array_index:3:preflightCommand = “”
web:definedWebApps:_array_index:3:stopCommand = “”
web:definedWebApps:_array_index:3:name = “”
web:definedWebApps:_array_index:3:displayName = “”
web:definedWebApps:_array_index:4:requiredWebAppNames = _empty_array
web:definedWebApps:_array_index:4:includeFiles:_array_index:0 = “/Library/Server/Web/Config/apache2/httpd_corecollaboration_shared.conf”
web:definedWebApps:_array_index:4:requiredModuleNames:_array_index:0 = “proxy_module”
web:definedWebApps:_array_index:4:requiredModuleNames:_array_index:1 = “xsendfile_module”
web:definedWebApps:_array_index:4:requiredModuleNames:_array_index:2 = “headers_module”
web:definedWebApps:_array_index:4:requiredModuleNames:_array_index:3 = “expires_module”
web:definedWebApps:_array_index:4:requiredModuleNames:_array_index:4 = “deflate_module”
web:definedWebApps:_array_index:4:startCommand = “”
web:definedWebApps:_array_index:4:sslPolicy = 0
web:definedWebApps:_array_index:4:requiresSSL = no
web:definedWebApps:_array_index:4:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:4:launchKeys:_array_index:0 = “”
web:definedWebApps:_array_index:4:launchKeys:_array_index:1 = “”
web:definedWebApps:_array_index:4:proxies:/collabdproxy:path = “/collabdproxy”
web:definedWebApps:_array_index:4:proxies:/collabdproxy:urls:_array_index:0 = “http://localhost:4444/svc”
web:definedWebApps:_array_index:4:proxies:/__collabd/streams/activity:path = “/__collabd/streams/activity”
web:definedWebApps:_array_index:4:proxies:/__collabd/streams/activity:urls:_array_index:0 = “http://localhost:4444/streams/activity”
web:definedWebApps:_array_index:4:preflightCommand = “”
web:definedWebApps:_array_index:4:stopCommand = “”
web:definedWebApps:_array_index:4:name = “”
web:definedWebApps:_array_index:4:displayName = “”
web:definedWebApps:_array_index:5:requiredWebAppNames:_array_index:0 = “”
web:definedWebApps:_array_index:5:includeFiles = _empty_array
web:definedWebApps:_array_index:5:requiredModuleNames = _empty_array
web:definedWebApps:_array_index:5:startCommand = “”
web:definedWebApps:_array_index:5:sslPolicy = 0
web:definedWebApps:_array_index:5:requiresSSL = no
web:definedWebApps:_array_index:5:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:5:launchKeys:_array_index:0 = “”
web:definedWebApps:_array_index:5:launchKeys:_array_index:1 = “”
web:definedWebApps:_array_index:5:proxies = _empty_dictionary
web:definedWebApps:_array_index:5:preflightCommand = “”
web:definedWebApps:_array_index:5:stopCommand = “”
web:definedWebApps:_array_index:5:name = “”
web:definedWebApps:_array_index:5:displayName = “”
web:definedWebApps:_array_index:6:requiredWebAppNames = _empty_array
web:definedWebApps:_array_index:6:includeFiles = _empty_array
web:definedWebApps:_array_index:6:requiredModuleNames:_array_index:0 = “php5_module”
web:definedWebApps:_array_index:6:startCommand = “”
web:definedWebApps:_array_index:6:sslPolicy = 0
web:definedWebApps:_array_index:6:requiresSSL = no
web:definedWebApps:_array_index:6:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:6:launchKeys = _empty_array
web:definedWebApps:_array_index:6:proxies = _empty_dictionary
web:definedWebApps:_array_index:6:preflightCommand = “”
web:definedWebApps:_array_index:6:stopCommand = “”
web:definedWebApps:_array_index:6:name = “”
web:definedWebApps:_array_index:6:displayName = “”
web:definedWebApps:_array_index:7:requiredWebAppNames = _empty_array
web:definedWebApps:_array_index:7:includeFiles:_array_index:0 = “/Library/Server/Web/Config/apache2/httpd_webdavsharing.conf”
web:definedWebApps:_array_index:7:requiredModuleNames:_array_index:0 = “rewrite_module”
web:definedWebApps:_array_index:7:requiredModuleNames:_array_index:1 = “bonjour_module”
web:definedWebApps:_array_index:7:startCommand = “”
web:definedWebApps:_array_index:7:sslPolicy = 0
web:definedWebApps:_array_index:7:requiresSSL = no
web:definedWebApps:_array_index:7:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:7:launchKeys = _empty_array
web:definedWebApps:_array_index:7:proxies = _empty_dictionary
web:definedWebApps:_array_index:7:preflightCommand = “”
web:definedWebApps:_array_index:7:stopCommand = “”
web:definedWebApps:_array_index:7:name = “”
web:definedWebApps:_array_index:7:displayName = “”
web:definedWebApps:_array_index:8:requiredWebAppNames:_array_index:0 = “”
web:definedWebApps:_array_index:8:requiredWebAppNames:_array_index:1 = “”
web:definedWebApps:_array_index:8:includeFiles:_array_index:0 = “/Library/Server/Web/Config/apache2/httpd_corecollaboration_wiki.conf”
web:definedWebApps:_array_index:8:requiredModuleNames:_array_index:0 = “proxy_module”
web:definedWebApps:_array_index:8:requiredModuleNames:_array_index:1 = “headers_module”
web:definedWebApps:_array_index:8:startCommand = “”
web:definedWebApps:_array_index:8:sslPolicy = 0
web:definedWebApps:_array_index:8:requiresSSL = no
web:definedWebApps:_array_index:8:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:8:launchKeys:_array_index:0 = “”
web:definedWebApps:_array_index:8:launchKeys:_array_index:1 = “”
web:definedWebApps:_array_index:8:proxies:/__collabd/preview:path = “/__collabd/preview”
web:definedWebApps:_array_index:8:proxies:/__collabd/preview:urls:_array_index:0 = “http://localhost:4444/preview”
web:definedWebApps:_array_index:8:proxies:/wiki/files/upload:path = “/wiki/files/upload”
web:definedWebApps:_array_index:8:proxies:/wiki/files/upload:urls:_array_index:0 = “http://localhost:4444/upload_file”
web:definedWebApps:_array_index:8:proxies:/wiki/files/download:path = “/wiki/files/download”
web:definedWebApps:_array_index:8:proxies:/wiki/files/download:urls:_array_index:0 = “http://localhost:4444/files”
web:definedWebApps:_array_index:8:proxies:/wiki/ipad:path = “/wiki/ipad”
web:definedWebApps:_array_index:8:proxies:/wiki/ipad:urls = _empty_array
web:definedWebApps:_array_index:8:proxies:/wiki:path = “/wiki”
web:definedWebApps:_array_index:8:proxies:/wiki:urls:_array_index:0 = “http://localhost:4444/app-context/wiki”
web:definedWebApps:_array_index:8:preflightCommand = “”
web:definedWebApps:_array_index:8:stopCommand = “”
web:definedWebApps:_array_index:8:name = “”
web:definedWebApps:_array_index:8:displayName = “”
web:definedWebApps:_array_index:9:requiredWebAppNames = _empty_array
web:definedWebApps:_array_index:9:includeFiles:_array_index:0 = “/Library/Server/Web/Config/apache2/httpd_wsgi.conf”
web:definedWebApps:_array_index:9:requiredModuleNames:_array_index:0 = “wsgi_module”
web:definedWebApps:_array_index:9:startCommand = “”
web:definedWebApps:_array_index:9:sslPolicy = 0
web:definedWebApps:_array_index:9:requiresSSL = no
web:definedWebApps:_array_index:9:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:9:launchKeys = _empty_array
web:definedWebApps:_array_index:9:proxies = _empty_dictionary
web:definedWebApps:_array_index:9:preflightCommand = “”
web:definedWebApps:_array_index:9:stopCommand = “”
web:definedWebApps:_array_index:9:name = “”
web:definedWebApps:_array_index:9:displayName = “Python &quot;Hello World&quot; app at /wsgi”
web:definedWebApps:_array_index:10:requiredWebAppNames = _empty_array
web:definedWebApps:_array_index:10:includeFiles:_array_index:0 = “/Library/Developer/XcodeServer/CurrentXcodeSymlink/Contents/Developer/usr/share/xcs/httpd_xcs.conf”
web:definedWebApps:_array_index:10:requiredModuleNames = _empty_array
web:definedWebApps:_array_index:10:startCommand = “”
web:definedWebApps:_array_index:10:sslPolicy = 4
web:definedWebApps:_array_index:10:requiresSSL = no
web:definedWebApps:_array_index:10:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:10:launchKeys = _empty_array
web:definedWebApps:_array_index:10:proxies = _empty_dictionary
web:definedWebApps:_array_index:10:preflightCommand = “”
web:definedWebApps:_array_index:10:stopCommand = “”
web:definedWebApps:_array_index:10:name = “”
web:definedWebApps:_array_index:10:displayName = “”
web:definedWebApps:_array_index:11:requiredWebAppNames:_array_index:0 = “com.example.webapp.myotherwebapp”
web:definedWebApps:_array_index:11:includeFiles:_array_index:0 = “/Library/Server/Web/Config/apache2/httpd_myinclude.conf”
web:definedWebApps:_array_index:11:requiredModuleNames:_array_index:0 = “mystuff_module”
web:definedWebApps:_array_index:11:startCommand = “/usr/local/bin/startmywebapp”
web:definedWebApps:_array_index:11:sslPolicy = 0
web:definedWebApps:_array_index:11:requiresSSL = no
web:definedWebApps:_array_index:11:requiredByWebAppNames = _empty_array
web:definedWebApps:_array_index:11:launchKeys:_array_index:0 = “com.example.mywebapp”
web:definedWebApps:_array_index:11:proxies:/mywebapp:path = “/mywebapp”
web:definedWebApps:_array_index:11:proxies:/mywebapp:urls:_array_index:0 = “http://localhost:3000”
web:definedWebApps:_array_index:11:proxies:/mywebapp:urls:_array_index:1 = “http://localhost:3001”
web:definedWebApps:_array_index:11:preflightCommand = “/usr/local/bin/preflightmywebapp”
web:definedWebApps:_array_index:11:stopCommand = “/usr/local/bin/stopmywebapp”
web:definedWebApps:_array_index:11:name = “com.example.mywebapp”
web:definedWebApps:_array_index:11:displayName = “MyWebApp”
The final section defines the settings used for the default sites as well as a couple of host based settings:
web:defaultSecureSite:documentRoot = “/Library/Server/Web/Data/Sites/Default”
web:defaultSecureSite:serverName = “”
web:defaultSecureSite:realms = _empty_dictionary
web:defaultSecureSite:redirects = _empty_array
web:defaultSecureSite:enableServerSideIncludes = no
web:defaultSecureSite:networkAccesses = _empty_array
web:defaultSecureSite:customLogPath = “&quot;/var/log/apache2/access_log&quot;”
web:defaultSecureSite:webApps = _empty_array
web:defaultSecureSite:sslCertificateIdentifier = “”
web:defaultSecureSite:fullSiteRedirectToOtherSite = “”
web:defaultSecureSite:allowFolderListing = no
web:defaultSecureSite:serverAliases = _empty_array
web:defaultSecureSite:errorLogPath = “&quot;/var/log/apache2/error_log&quot;”
web:defaultSecureSite:fileName = “/Library/Server/Web/Config/apache2/sites/0000_127.0.0.1_34543_.conf”
web:defaultSecureSite:aliases = _empty_array
web:defaultSecureSite:directoryIndexes:_array_index:0 = “index.html”
web:defaultSecureSite:directoryIndexes:_array_index:1 = “index.php”
web:defaultSecureSite:directoryIndexes:_array_index:2 = “default.html”
web:defaultSecureSite:allowAllOverrides = no
web:defaultSecureSite:identifier = “67127004”
web:defaultSecureSite:port = 34543
web:defaultSecureSite:allowCGIExecution = no
web:defaultSecureSite:serverAddress = “”
web:defaultSecureSite:requiresSSL = yes
web:defaultSecureSite:proxies = _empty_dictionary
web:defaultSecureSite:errorDocuments = _empty_dictionary
web:mainHost:keepAliveTimeout = 15.000000
web:mainHost:maxClients = “256”
Each site has its own configuration file defined in the array for each section. By default these are stored in the /Library/Server/Web/Config/apache2/sites directory, with /Library/Server/Web/Config/apache2/sites/ being the file for the custom site we created previously. As you can see, many of the options available in the Server app are also available in these files:
ServerName ServerAdmin DocumentRoot "/Library/Server/Web/Data/Sites/" DirectoryIndex index.html index.php /wiki/ default.html CustomLog /var/log/apache2/access_log combinedvhost ErrorLog /var/log/apache2/error_log
SSLEngine Off
SSLProtocol -ALL +SSLv3 +TLSv1
SSLProxyEngine On
SSLProxyProtocol -ALL +SSLv3 +TLSv1
Options All -Indexes -ExecCGI -Includes +MultiViews
AllowOverride None
Deny from all
ErrorDocument 403 /customerror/websitesoff403.html
The serveradmin command can also be used to run commands. For example, to reset the service to factory defaults, delete the configuration files for each site and then run the following command:

sudo serveradmin command web:command=restoreFactorySettings

The final tip I’m going to give in this article is when to make changes with each app. I strongly recommend making all of your changes in the Server app when possible. When it isn’t, use serveradmin and when you can’t make changes in serveradmin, only then alter the configuration files that come with the operating system by default. For example, in this article I look at overriding some ports for some virtual sites that might conflict with other sites on your systems. I also recommend keeping backups of all configuration files that are altered and a log of what was altered in each, in order to help piece the server back together should it become unconfigured miraculously when a softwareupdate -all is run next.

September 27th, 2017

Posted In: Mac OS X Server

Tags: , , , , , , , , , ,

A wiki is a repository of dynamically created and managed content, or content created or edited by multiple users collaboratively. This article is about using the wiki service in macOS Server 5.4 (the Apple Server app running on 10.13/High Sierra). I reference file services with WebDAV because it is a very nice integration piece that I think a lot of people will find pretty beneficial.

To get started with the Wiki service, first turn it on. This one isn’t heavily dependent on host names (other than being able to access the server from a browser) or directory services (other than being able to authenticate users, but local accounts are perfectly functional) and it doesn’t require the Websites service to be running as well. One should always have good working directory services and host names, still…

To enable the service, open the Server app and click on Wiki in the list of SERVICES in the List Pane.

There are two configuration options. The first is to select who is able to create wikis. Use the “Wikis can be created by” drop-down list to select “all users” if anyone with an account on the server should be able to create a wiki or “only some users” to bring up the Wiki Creators screen.

If only some users can create new wikis, use the plus sign (“+”) at the Wiki Creators screen to add users and/or groups to the list of users that can create wikis. Click on OK when all users and groups that can create wikis are added. In a school I would imagine that only teachers or IT staff would be able to create wikis. Once a wiki is created, pages inside the wiki can still be created by non-wiki creators.

The other option available is the handy dandy WebDAV interface to the wikis. When you enable this option, you can connect to a server from macOS or iOS via WebDAV and access files in each wikis document repository. To be clear, this option doesn’t provide access to the user documents, but does provide access to the wiki documents. We’re going to check the box for “Enable WebDAV access to Wiki files” and then click the ON button.

Once the service starts, click on the View Wiki link in the Wiki workspace in Server app.

Here, click on the Log in button and enter a user with access to the server, preferably one who can create wikis.

At the Wikis page, you will then see a list of all wikis you have access to. Note that the previous screen showed one wiki and now we see two. That’s because one of the wikis has permissions that allow “All unauthenticated users” access to the wiki, which we’ll describe shortly. The first thing most administrators will do is create a wiki. To do so, click on the plus sign (“+”) icon on the web page and at the resultant screen, click on New Wiki.

At the “Create a new wiki” prompt, provide a name for the wiki and a brief description for it.

Click on Continue.

At the Set permissions screen, enter each user or group to provide access to edit and view wiki pages. Here, you’ll have the options for Read & Write (users can view and edit pages in the wiki), Read only (users can only view the contents of your pages) and No access (users have no access to the wiki). There is a group for All logged in users, which includes every user with access to the server and another for All unauthorized users, which includes guests to the server. Once you’ve given the appropriate permissions, click on Continue.

Note: You don’t have to get this perfect now as you can always edit these later.

At the Set Appearance screen, you can choose an icon for the wiki (shown in the wiki list and when you open the wiki) as well as a color scheme for the wiki. Choose the appropriate appearance for your wiki (again, you can always change this later) and then click on the Create button.

Once the setup is finished, you’ll see the Setup complete modal. Here, you can click on Go to Wiki button.

Once you’ve created your first wiki, let’s edit it and customize the content. To do so, click on it from the list of available wikis. Click on the cog-wheel icon and then Wiki Settings… to bring up the Wiki Settings page.

Here, you’ll see the previously entered name and description as well as options to enable Calendar (only available if Calendar Server is running on the server) and Blog, which enables  a blog service for the wiki (wiki administrators can post blog entries to the wiki). Click on Appearance.

Here, you will have the previous two options as well as the ability to upload a banner (which should be 62 pixels high) and background for each wiki.

Click on Permissions. Here, you’ll see the permissions previously configured as well as options to configure who can comment on articles (nobody disables comments completely) in the wiki and whether comments require approval (moderation).

Click on Save. Now, let’s edit the splash page. To do so, click the pencil icon in the top navigation bar.

At the edit screen, the top nav bar is replaced by a WYSIWIG editor for managing the page. Here you can justify, link, insert media and of course edit the text you see on the screen. I recommend spending some time embedding links, inserting tables, making text look like you want it to and editing the content to reflect the purpose of the wiki. Click Save when you’re done. Click the pencil again to edit it, and let’s create a new wiki page. Keep in mind that link wikipedia, each page should be linked to from other pages in the order they should be read. Unlike most wikis, there’s actually an index page of all the articles, which can come in handy.

From the edit page, to create a new page and link to it, enter some text (or lasso some) that you’ll use as the link to access the new page you’re creating. Then click on the arrow and select “New page.”

Note: Use Enter URL to link to an existing page or an external website, instead of creating a new page.

At the New Page screen, provide a name for the new page (the lasso’d text automatically appears as the Page Title) and click on the Add button.

Click Save and then click on the newly created link. You can now edit the new page the same way you edited the previous pages. Click on the disclosure triangles in the right sidebar to Comment on articles, link articles to related articles, tag articles and view editing history.

Now for the fun part. Click on Documents. Here, you’ll see the pages you already created. Click on the plus sign and select the option to Upload File to the wiki.

At the Upload File dialog, click on Choose File and then select a file to upload.

Click Upload when selected.

Then from the Finder of a macOS client, use the Go menu to select “Connect to Server”. Enter the name or IP of the server and then click on Connect.

Assuming you can access the server, you should then be prompted for a username and password. Enter it and click Connect. Eventually, the file(s) will display (it can take awhile according to your network speeds and how many files are in the directory). You can connect to this same screen through an iPad using a 3rd party WebDAV client or the build in options in Pages.

Managing wikis is as easy as its ever been, with the new options for appearance being a nice add-on. Active Directory integration is as easy as binding the server to Active Directory and using the accounts listed in Permissions of pages.

Now that iOS devices can edit wikis and many of the traditional word processing options are available in the wiki editor, consider what the Wiki can be. Could it replace text editing apps for iOS? Could the Wiki allow for more collaborative documents than a Word or other document editor? Could it keep from getting eaten like the rest of the homework? Could the comments in the Wiki be a good way for teachers to have students write responses to materials? Could the Wiki and the document management features allow your workers to access human resources documents and employee manuals? I know plenty of tech firms that use wikis to track information about the systems they manage.

Once you have all of this information, upgrading can seem downright scary. But fear not, there’s Carbon Copy Cloner. And once you’ve cloned, there’s wikiadmin. When doing an upgrade in place, the Wiki service is pretty straight forward to upgrade, but in many cases, due to aging hardware, wiki services are moving from an older computer to a newer computer. This can be done in one of two ways. The first is to “migrate” the data by copying the Collaboration folder onto the new system. The second is to “export” and “import” the data. I usually recommend doing a migrate where possible, so we’ll start with that method.

Note: Before getting started, make sure that the directory services side of things is good. If a user or group lookup for an object that owns, edits or has commented on a wiki fails then that wiki probably shouldn’t be migrated. Use the dscl or id commands to confirm that lookups are functioning as intended.

To migrate wikis from one server to another, first copy the Collaboration directory to the new server. In this example, the directory has been dropped onto the desktop of the currently logged in user. To migrate the data once copied, use the wikiadmin command, along with the migration option. The option requires the path to the Collaboration folder, defined with -r, as follows:

sudo /Applications/ migrate -r ~/Desktop/Collaboration

When moving wikis, you can take the opportunity to get rid of a few you don’t want (such as that test wiki from way back when). Or administrators may just choose to move a single wiki to a new server in order to split the load across multiple hosts. When doing so, use the same command as earlier, along with the name of each wiki that is being moved, along with the -g option. For example, if moving the Legal wiki:

sudo /Applications/ migrate -r ~/Desktop/Collaboration -g Legal

The second way of moving wikis around is to export and then import them. To do so, first export wikis on the old server, using the wikiadmin command along with the export option, which requires an –exportPath option and needs to be done, on a wiki-by-wiki basis. So to export that Legal wiki to a file called LegalWikiTMP on the desktop:

sudo /Applications/ export -g Legal --exportPath ~/Desktop/LegalWikiTMP

Next, copy the wiki to the new server and import it, using the import option along with –importPath to identify where the file being imported is located. Using the same location, the command would then be:

sudo /Applications/ import -g Legal --importPath ~/Desktop/LegalWikiTMP

Note: The ability to import a wiki also allows for an API of sorts, as you can programmatically create wikis from other sources. The ability to export also provides a way to move into another wiki tool if you happen to outgrow the options provided in Server and need to move to something more robust.

There is another way to move wikis, using pg_dump, copying the data and then using pg_restore to import the data once you’ve created the tables.  This way is, in my opinion, the last resort if the standard wikiadmin commands aren’t working. In my experience, if I’m doing the migration this way then I’ve got other, bigger issues that I need to deal with as well.

These commands work best when the wiki service has been started so that the databases are fully built out. To start the wiki service from the command line, use the serveradmin command instead of the wikiadmin command. The serveradmin command is used with the start option and then wiki is used to indicate the wiki service, as follows:

sudo /Applications/ start wiki

The service can also be stopped, swapping out the start option with a stop option:

sudo /Applications/ stop wiki

In a few cases (this is the main reason I’m writing this article), the attachments to wikis don’t come over during a migration. To migrate the files that are used for QuickLook, downloading attachments, etc, use the serveradmin command to locate the directory that these objects are stored in:

sudo /Applications/ settings wiki:FileDataPath

The output identifies the directory where these objects are stored. Placing the contents in the same relative path as they are to the output of the same command on the target server usually results in restoring them. Once moved, use the fixPermissions option to repair the permissions of any files from the source (if any changes to account IDs are encountered such as an export/import rather than an archive/restore in OD this can lead to odd issues:

sudo /Applications/ fixPermissions

Also use the rebuildSearchIndex option with the wikiadmin command to fix any indexing, once the permissions have been repaired:

sudo /Applications/ rebuildSearchIndex

And finally use resetQuicklooks to clear any cached Quicklook representations of objects that have been inserted into a wiki and might not display properly using Quicklook (you know you might need to do this if they look fine when downloaded but look bad with Quicklook even though QuickLook on the server can view the files just fine):

sudo /Applications/ resetQuicklooks

When done properly the migration can take awhile. Keep in mind that every tag, every article, every edit to every article and basically everything else is tracked inside the tables that you’re moving. While there might not be a ton of data in the Collaboration directory or in an export, all of the data needs to go to the right location. This can take a little time in environments that have a lot of articles, even if they’re really short articles…

September 26th, 2017

Posted In: Mac OS X, Mac OS X Server

Tags: , , , , , , , , , ,

Open Directory has never been this easy to setup for a basic environment as it is in macOS Server 5.4 (for macOS 10.13 running on High Sierra). As with almost any previous version of macOS Server and Open Directory, once you’ve installed the Server app, run the changeip command along with the -checkhostname option to verify that the IP, DNS and hostname match. If (and only if as it will fail if you try anyway) you get an indication of “Success.” I know, I know, you’ve been told that you didn’t have to do this kind of command line stuff any more… But really, you should – and if you don’t believe me, check out the contents of the attributes in the OD database… And besides, all you have to do is paste it in…

bash-3.2# sudo /Applications/ -checkhostname

Which should respond as follows if all your DNS stuff is configured to match your host name:

dirserv:success = "success"

Initially, you no longer see Open Directory in the sidebar of the Server app. Simply click on the entry in View to see it. Then, to set up the Open Directory Master, click on the Open Directory service. From here, click on the ON button.

For the purposes of this example, we’re setting up an entirely new Open Directory environment. At the “Configure Network Users and Groups” screen, click on “Create a new Open Directory Domain” and click on the Next button.

Note: If you are restoring an archive of an existing Open Directory domain, you would select the bottom option from this list.

At the Directory Administrator screen, enter a username and password for the directory administrator account. The default account is sufficient, although it’s never a bad idea to use something a bit less generic.

Once you’ve entered the username and password, click on the Next button. Then we’re going to configure the SSL information.

At the Organization Information screen, enter a name for the organization in the Organization Name field and an Email Address to be used in the SSL certificate in the Admin Email Address field. Click on Next.

At the Confirm Settings screen, make sure these very few settings are OK with you and then click on the Set Up button to let slapconfig (the command that runs the OD setup in the background, kinda’ like a cooler dcpromo) do its thing. When the Open Directory master has been configured, there’s no need to reboot or anything, the indicator light for the Open Directory service should appear. If the promotion fails then look to the preflight options I wrote up awhile back.

Clicking on the minus (“-”) button while a server is highlighted runs a slapconfig -destroyldapserver on the server and destroys the Open Directory domain if it is the only server. All domain information is lost when this happens.

Next, let’s bind a client. Binding clients can be done in a few different ways. You can use a script, a Profile, the Users & Groups System Preference pane or build binding into the imaging process. For the purpose of this example, we’ll use the System Preference pane. To get started, open up the System Preference pane and then click on Users & Groups. From here, click on Login Options and then unlock the lock in the lower left corner of the screen, providing a username and password when prompted.

Click on the Edit… button and then the plus sign (“+”).

Then, enter the name of the Open Directory Master (the field will expand with options when you enter the host name.

It’s probably best not to use the IP address at this point as the master will have an SSL certificate tied to the name. Click OK to accept the certificate (if it’s self-signed) and then the system should finish binding. Once bound, I like to use either id or dscl to verify that directory accounts are properly resolving before I try logging in as an Open Directory user. Provided everything works that’s it.

Next, use dscl to browse users and verify that you can see items in Open Directory as well as your local database. The following will do so, using your hostname in place of mine, and with your password:

dscl -u diradmin -P <PASSWORD> /LDAPv3/ -read /Users/diradmin

Once configured and tested, the devil is of course in the details. There is very little data worth having if it isn’t backed up. Notice that you can archive by clicking on the cog wheel icon in the Open Directory service pane, much like you could in Server Admin. Or, because this helps when it comes to automating backups (with a little expect), to run a backup from the command line, run the slapconfig command along with the -backupdb option followed by a path to a folder to back the data up to:

sudo slapconfig -backupdb /odbackups

The result will be a request for a password then a bunch of information about the backup:

bash-3.2# sudo slapconfig -backupdb /odbackups 2016-09-08 04:31:13 +0000 slapconfig -backupdb Enter archive password: 2016-09-08 04:31:17 +0000 1 Backing up LDAP database 2016-09-08 04:31:17 +0000 popen: /usr/sbin/slapcat -l /tmp/slapconfig_backup_stage1769HtaFE7/backup.ldif, "r" 55ee6495 bdb_monitor_db_open: monitoring disabled; configure monitor database to enable 2016-09-08 04:31:17 +0000 popen: /usr/sbin/slapcat -b cn=authdata -l /tmp/slapconfig_backup_stage1769HtaFE7/authdata.ldif, "r" 55ee6495 bdb_monitor_db_open: monitoring disabled; configure monitor database to enable 2016-09-08 04:31:17 +0000 popen: /bin/cp /var/db/openldap/openldap-data/DB_CONFIG /tmp/slapconfig_backup_stage1769HtaFE7/DB_CONFIG, "r" 2016-09-08 04:31:17 +0000 popen: /bin/cp /var/db/openldap/authdata//DB_CONFIG /tmp/slapconfig_backup_stage1769HtaFE7/authdata_DB_CONFIG, "r" 2016-09-08 04:31:17 +0000 popen: /bin/cp -r /etc/openldap /tmp/slapconfig_backup_stage1769HtaFE7/, "r" 2016-09-08 04:31:17 +0000 popen: /bin/hostname > /tmp/slapconfig_backup_stage1769HtaFE7/hostname, "r" 2016-09-08 04:31:17 +0000 popen: /usr/sbin/sso_util info -pr /LDAPv3/ > /tmp/slapconfig_backup_stage1769HtaFE7/local_odkrb5realm, "r" 2016-09-08 04:31:18 +0000 popen: /usr/bin/tar czpf /tmp/slapconfig_backup_stage1769HtaFE7/krb5backup.tar.gz /var/db/krb5kdc/kdc.conf /var/db/krb5kdc/acl_file.* /var/db/krb5kdc/m_key.* /etc/krb5.keytab , "r" tar: Removing leading '/' from member names 2016-09-08 04:31:18 +0000 2 Backing up Kerberos database 2016-09-08 04:31:18 +0000 popen: /bin/cp /var/db/dslocal/nodes/Default/config/KerberosKDC.plist /tmp/slapconfig_backup_stage1769HtaFE7/KerberosKDC.plist, "r" 2016-09-08 04:31:18 +0000 popen: /bin/cp /Library/Preferences/ /tmp/slapconfig_backup_stage1769HtaFE7/, "r" 2016-09-08 04:31:18 +0000 3 Backing up configuration files 2016-09-08 04:31:18 +0000 popen: /usr/bin/sw_vers > /tmp/slapconfig_backup_stage1769HtaFE7/version.txt, "r" 2016-09-08 04:31:18 +0000 popen: /bin/cp -r /var/db/dslocal /tmp/slapconfig_backup_stage1769HtaFE7/, "r" 2016-09-08 04:31:18 +0000 Backed Up Keychain 2016-09-08 04:31:18 +0000 4 Backing up CA certificates 2016-09-08 04:31:18 +0000 5 Creating archive 2016-09-08 04:31:18 +0000 command: /usr/bin/hdiutil create -ov -plist -puppetstrings -layout UNIVERSAL CD -fs HFS+ -volname ldap_bk -srcfolder /tmp/slapconfig_backup_stage1769HtaFE7 -format SPARSE -encryption AES-256 -stdinpass /odbackups 2016-09-08 04:31:25 +0000 Removed directory at path /tmp/slapconfig_backup_stage1769HtaFE7. 2016-09-08 04:31:25 +0000 Removed file at path /var/run/slapconfig.lock.

To restore a database (such as from a previous version of the operating system where such an important option was actually present) use the following command (which just swaps backupdb with -restoredb)

sudo slapconfig -restoredb /odbackups

Both commands ask you for a password to encrypt and decrypt the disk image created by them.

September 26th, 2017

Posted In: Mac OS X, Mac OS X Server

Tags: , , , , ,

Next Page »