Fossil SCM

fossil-scm / www / server / macos / service.md
Source Blame History 181 lines
f146e21… drh 1 # Serving via launchd on macOS
f146e21… drh 2
f146e21… drh 3 [`launchd`][ldhome] is the default service management framework on macOS
f146e21… drh 4 [since the release of Tiger in 2005][wpa]. If you want a Fossil server
f146e21… drh 5 to launch in the background on a Mac, it’s the way Apple wants you to do
f146e21… drh 6 it. `launchd` is to macOS as `systemd` is to most modern Linux desktop
f146e21… drh 7 systems. (Indeed, `systemd` arguably reinvented the perfectly good,
f146e21… drh 8 pre-existing `launchd` wheel.)
f146e21… drh 9
f146e21… drh 10 Unlike in [our `systemd` article](../debian/service.md), we’re not going
f146e21… drh 11 to show the per-user method here, because those so-called
f146e21… drh 12 [LaunchAgents][la] only start when a user is logged into the GUI, and
f146e21… drh 13 they stop when that user logs out. This does not strike us as proper
f146e21… drh 14 “server” behavior, so we’ll stick to system-level LaunchDaemons instead.
f146e21… drh 15
f146e21… drh 16 However, we will still give two different configurations, just as in the
f146e21… drh 17 `systemd` article: one for a standalone HTTP server, and one using
f146e21… drh 18 socket activation.
f146e21… drh 19
f146e21… drh 20 For more information on `launchd`, the single best resource we’ve found
7de6f15… danield 21 is [launchd.info](https://launchd.info). The next best is:
f146e21… drh 22
8a1ba49… wyoung 23 $ man launchd.plist
f146e21… drh 24
f146e21… drh 25 [la]: http://www.grivet-tools.com/blog/2014/launchdaemons-vs-launchagents/
f146e21… drh 26 [ldhome]: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html
f146e21… drh 27 [wpa]: https://en.wikipedia.org/wiki/Launchd
f146e21… drh 28
f146e21… drh 29
f146e21… drh 30
f146e21… drh 31 ## Standalone HTTP Server
f146e21… drh 32
f146e21… drh 33 To configure `launchd` to start Fossil as a standalone HTTP server,
f146e21… drh 34 write the following as `com.example.dev.FossilHTTP.plist`:
f146e21… drh 35
f146e21… drh 36 ```xml
8a1ba49… wyoung 37 <?xml version="1.0" encoding="UTF-8"?>
8a1ba49… wyoung 38 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
8a1ba49… wyoung 39 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
8a1ba49… wyoung 40 <plist version="1.0">
8a1ba49… wyoung 41 <dict>
8a1ba49… wyoung 42 <key>Label</key>
8a1ba49… wyoung 43 <string>com.example.dev.FossilHTTP</string>
8a1ba49… wyoung 44 <key>ProgramArguments</key>
8a1ba49… wyoung 45 <array>
8a1ba49… wyoung 46 <string>/usr/local/bin/fossil</string>
8a1ba49… wyoung 47 <string>server</string>
8a1ba49… wyoung 48 <string>--port</string>
8a1ba49… wyoung 49 <string>9000</string>
8a1ba49… wyoung 50 <string>repo.fossil</string>
8a1ba49… wyoung 51 </array>
8a1ba49… wyoung 52 <key>WorkingDirectory</key>
8a1ba49… wyoung 53 <string>/Users/you/museum</string>
8a1ba49… wyoung 54 <key>KeepAlive</key>
8a1ba49… wyoung 55 <true/>
8a1ba49… wyoung 56 <key>RunAtLoad</key>
8a1ba49… wyoung 57 <true/>
8a1ba49… wyoung 58 <key>StandardErrorPath</key>
8a1ba49… wyoung 59 <string>/tmp/fossil-error.log</string>
8a1ba49… wyoung 60 <key>StandardOutPath</key>
8a1ba49… wyoung 61 <string>/tmp/fossil-info.log</string>
8a1ba49… wyoung 62 <key>UserName</key>
8a1ba49… wyoung 63 <string>you</string>
8a1ba49… wyoung 64 <key>GroupName</key>
8a1ba49… wyoung 65 <string>staff</string>
8a1ba49… wyoung 66 <key>InitGroups</key>
8a1ba49… wyoung 67 <true/>
8a1ba49… wyoung 68 </dict>
8a1ba49… wyoung 69 </plist>
f146e21… drh 70 ```
f146e21… drh 71
f146e21… drh 72 In this example, we’re assuming your development organization uses the
f146e21… drh 73 domain name “`dev.example.org`”, that your short macOS login name is
f146e21… drh 74 “`you`”, and that you store your Fossils in “`~/museum`”. Adjust these
f146e21… drh 75 elements of the plist file to suit your local situation.
f146e21… drh 76
f146e21… drh 77 You might be wondering about the use of `UserName`: isn’t Fossil
f146e21… drh 78 supposed to drop privileges and enter [a `chroot(2)`
f146e21… drh 79 jail](../../chroot.md) when it’s started as root like this? Why do we
f146e21… drh 80 need to give it a user name? Won’t Fossil use the owner of the
f146e21… drh 81 repository file to set that? All I can tell you is that in testing here,
f146e21… drh 82 if you leave the user and group configuration at the tail end of that
f146e21… drh 83 plist file out, Fossil will remain running as root!
f146e21… drh 84
f146e21… drh 85 Install that file and set it to start with:
f146e21… drh 86
8a1ba49… wyoung 87 $ sudo install -o root -g wheel -m 644 com.example.dev.FossilHTTP.plist \
8a1ba49… wyoung 88 /Library/LaunchDaemons/
8a1ba49… wyoung 89 $ sudo launchctl load -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist
f146e21… drh 90
f146e21… drh 91 Because we set the `RunAtLoad` key, this will also launch the daemon.
f146e21… drh 92
f146e21… drh 93 Stop the daemon with:
f146e21… drh 94
8a1ba49… wyoung 95 $ sudo launchctl unload -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist
f146e21… drh 96
f146e21… drh 97
f146e21… drh 98 ## Socket Listener
f146e21… drh 99
f146e21… drh 100 Another useful method to serve a Fossil repo via `launchd` is by setting
f146e21… drh 101 up a socket listener:
f146e21… drh 102
f146e21… drh 103 ```xml
f146e21… drh 104 <?xml version="1.0" encoding="UTF-8"?>
8a1ba49… wyoung 105 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
8a1ba49… wyoung 106 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
f146e21… drh 107 <plist version="1.0">
f146e21… drh 108 <dict>
f146e21… drh 109 <key>Label</key>
f146e21… drh 110 <string>com.example.dev.FossilSocket</string>
f146e21… drh 111 <key>ProgramArguments</key>
f146e21… drh 112 <array>
f146e21… drh 113 <string>/usr/local/bin/fossil</string>
f146e21… drh 114 <string>http</string>
f146e21… drh 115 <string>repo.fossil</string>
f146e21… drh 116 </array>
f146e21… drh 117 <key>Sockets</key>
f146e21… drh 118 <dict>
f146e21… drh 119 <key>Listeners</key>
f146e21… drh 120 <dict>
f146e21… drh 121 <key>SockServiceName</key>
f146e21… drh 122 <string>9001</string>
f146e21… drh 123 <key>SockType</key>
f146e21… drh 124 <string>stream</string>
f146e21… drh 125 <key>SockProtocol</key>
f146e21… drh 126 <string>TCP</string>
f146e21… drh 127 <key>SockFamily</key>
f146e21… drh 128 <string>IPv4</string>
f146e21… drh 129 </dict>
f146e21… drh 130 </dict>
f146e21… drh 131 <key>inetdCompatibility</key>
f146e21… drh 132 <dict>
f146e21… drh 133 <key>Wait</key>
f146e21… drh 134 <false/>
f146e21… drh 135 </dict>
f146e21… drh 136 <key>WorkingDirectory</key>
f146e21… drh 137 <string>/Users/you/museum</string>
f146e21… drh 138 <key>UserName</key>
f146e21… drh 139 <string>you</string>
f146e21… drh 140 <key>GroupName</key>
f146e21… drh 141 <string>staff</string>
f146e21… drh 142 <key>InitGroups</key>
f146e21… drh 143 <true/>
f146e21… drh 144 </dict>
f146e21… drh 145 </plist>
f146e21… drh 146 ```
f146e21… drh 147
f146e21… drh 148 Save it as “`com.example.dev.FossilSocket.plist`” and install and load
f146e21… drh 149 it into `launchd` as above.
f146e21… drh 150
f146e21… drh 151 This version differs in several key ways:
f146e21… drh 152
f146e21… drh 153 1. We’re calling Fossil as `fossil http` rather than `fossil server` to
f146e21… drh 154 make it serve a single request and then shut down immediately.
f146e21… drh 155
f146e21… drh 156 2. We’ve told `launchd` to listen on our TCP port number instead of
f146e21… drh 157 passing it to `fossil`.
f146e21… drh 158
f146e21… drh 159 3. We’re running the daemon in `inetd` compatibility mode of `launchd`
f146e21… drh 160 with “wait” mode off, which tells it to attach the connected socket
f146e21… drh 161 to the `fossil` process’s stdio handles.
f146e21… drh 162
f146e21… drh 163 4. We’ve removed the `Standard*Path` keys because they interfere with
f146e21… drh 164 our use of stdio handles for HTTP I/O. You might therefore want to
f146e21… drh 165 start with the first method and then switch over to this one only
f146e21… drh 166 once you’ve got the daemon launching debugged, since once you tie up
f146e21… drh 167 stdio this way, you won’t be able to get logging information from
f146e21… drh 168 Fossil via that path. (Fossil does have some internal logging
f146e21… drh 169 mechanisms, but you can’t get at them until Fossil is launching!)
f146e21… drh 170
f146e21… drh 171 5. We’ve removed the `KeepAlive` and `RunAtLoad` keys because those
f146e21… drh 172 options aren’t appropriate to this type of service.
f146e21… drh 173
f146e21… drh 174 6. Because we’re running it via a socket listener instead of as a
f146e21… drh 175 standalone HTTP server, the Fossil service only takes system
f146e21… drh 176 resources when it’s actually handling an HTTP hit. If your Fossil
f146e21… drh 177 server is mostly idle, this method will be a bit more efficient than
f146e21… drh 178 the first option.
f146e21… drh 179
f146e21… drh 180
f146e21… drh 181 *[Return to the top-level Fossil server article.](../)*

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button