--- a/gmid.1
+++ b/gmid.1
@@ -22,6 +22,7 @@
 .Bk -words
 .Op Fl fnv
 .Op Fl c Ar config
+.Op Fl P Ar pidfile
 .Ek
 .Nm
 .Bk -words
@@ -51,6 +52,10 @@ Specify the configuration file.
 Stays and logs on the foreground.
 .It Fl n
 Check that the configuration is valid, but don't start the server.
+.It Fl P Pa pidfile
+Write
+.Nm
+pid to the given path.
 .El
 .Pp
 If no configuration file is given,
--- a/gmid.c
+++ b/gmid.c
@@ -316,7 +316,7 @@ static void
 usage(const char *me)
 {
 	fprintf(stderr,
-	    "USAGE: %s [-fn] [-c config] | [-6h] [-d certs-dir] [-H host]\n"
+	    "USAGE: %s [-fn] [-c config] [-P pidfile] | [-6h] [-d certs-dir] [-H host]\n"
 	    "       [-p port] [-x cgi] [dir]\n",
 	    me);
 }
@@ -411,6 +411,34 @@ serve(int argc, char **argv, struct imsgbuf *ibuf)
 	_exit(executor_main(ibuf));
 }
 
+static int
+write_pidfile(const char *pidfile)
+{
+	struct flock	lock;
+	int		fd;
+
+	if (pidfile == NULL)
+		return -1;
+
+	if ((fd = open(pidfile, O_WRONLY|O_CREAT|O_CLOEXEC, 0600)) == -1)
+		fatal("can't open pidfile %s: %s", pidfile, strerror(errno));
+
+	lock.l_start = 0;
+	lock.l_len = 0;
+	lock.l_type = F_WRLCK;
+	lock.l_whence = SEEK_SET;
+
+	if (fcntl(fd, F_SETLK, &lock) == -1)
+		fatal("can't lock %s, gmid is already running?", pidfile);
+
+	if (ftruncate(fd, 0) == -1)
+		fatal("ftruncate: %s: %s", pidfile, strerror(errno));
+
+	dprintf(fd, "%d\n", getpid());
+
+	return fd;
+}
+
 static void
 setup_configless(int argc, char **argv, const char *cgi)
 {
@@ -434,11 +462,12 @@ main(int argc, char **argv)
 {
 	struct imsgbuf exibuf;
 	int ch, conftest = 0, configless = 0;
-	int old_ipv6, old_port;
+	int pidfd, old_ipv6, old_port;
+	const char *pidfile = NULL;
 
 	init_config();
 
-	while ((ch = getopt(argc, argv, "6c:d:fH:hnp:vx:")) != -1) {
+	while ((ch = getopt(argc, argv, "6c:d:fH:hnP:p:vx:")) != -1) {
 		switch (ch) {
 		case '6':
 			conf.ipv6 = 1;
@@ -472,6 +501,10 @@ main(int argc, char **argv)
 			conftest = 1;
 			break;
 
+		case 'P':
+			pidfile = optarg;
+			break;
+
 		case 'p':
 			conf.port = parse_portno(optarg);
 			configless = 1;
@@ -536,6 +569,8 @@ main(int argc, char **argv)
 		return 0;
 	}
 
+	pidfd = write_pidfile(pidfile);
+
 	/* Linux seems to call the event handlers even when we're
 	 * doing a sigwait.  These dummy handlers are here to avoid
 	 * being terminated on SIGHUP, SIGINT or SIGTERM. */
@@ -604,5 +639,8 @@ main(int argc, char **argv)
 	imsg_compose(&logibuf, IMSG_QUIT, 0, 0, -1, NULL, 0);
 	imsg_flush(&logibuf);
 
+	if (pidfd != -1)
+		close(pidfd);
+
 	return 0;
 }
