Fossil SCM

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

Keyboard Shortcuts

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