diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm
index 5657b141d9..a4d3affa6c 100644
--- a/gnu/services/networking.scm
+++ b/gnu/services/networking.scm
@@ -41,6 +41,7 @@ (define-module (gnu services networking)
   #:use-module (gnu services)
   #:use-module (gnu services base)
   #:use-module (gnu services configuration)
+  #:use-module (gnu services configuration generic-ini)
   #:use-module (gnu services linux)
   #:use-module (gnu services shepherd)
   #:use-module (gnu services dbus)
@@ -1157,92 +1158,145 @@ (define-record-type* <modem-manager-configuration>
 ;;;
 
 ;; TODO: deprecated field, remove later.
-(define-with-syntax-properties (warn-iwd?-field-deprecation
-                                (value properties))
+(define (warn-iwd?-field-deprecation value)
   (when value
-    (warning (source-properties->location properties)
-             (G_ "the 'iwd?' field is deprecated, please use \
+    (warning (G_ "the 'iwd?' field is deprecated, please use \
 'shepherd-requirement' field instead~%")))
   value)
 
-(define-record-type* <network-manager-configuration>
-  network-manager-configuration make-network-manager-configuration
-  network-manager-configuration?
-  (network-manager network-manager-configuration-network-manager
-                   (default network-manager))
-  (shepherd-requirement network-manager-configuration-shepherd-requirement
-                        (default '(wpa-supplicant)))
-  (dns network-manager-configuration-dns
-       (default "default"))
-  (vpn-plugins network-manager-configuration-vpn-plugins ;list of file-like
-               (default '()))
-  (iwd? network-manager-configuration-iwd?  ; TODO: deprecated field, remove.
-        (default #f)
-        (sanitize warn-iwd?-field-deprecation)))
+(define-configuration network-manager-configuration
+  (network-manager
+   (package network-manager)
+   "The NetworkManager package to use."
+   empty-serializer)
+
+  (shepherd-requirement
+   (list-of-symbols '(wpa-supplicant))
+   "This option can be used to provide a list of symbols naming Shepherd
+services that this service will depend on, such as @code{'wpa-supplicant} or
+@code{'iwd} if you require authenticated access for encrypted WiFi or Ethernet
+networks."
+   empty-serializer)
+
+  (dns
+   (string "default")
+   "Processing mode for DNS, which affects how NetworkManager uses the
+@code{resolv.conf} configuration file.
+
+@table @samp
+@item default
+NetworkManager will update @code{resolv.conf} to reflect the nameservers
+provided by currently active connections.
+
+@item dnsmasq
+NetworkManager will run @code{dnsmasq} as a local caching nameserver, using a
+@dfn{conditional forwarding} configuration if you are connected to a VPN, and
+then update @code{resolv.conf} to point to the local nameserver.
+
+With this setting, you can share your network connection.  For example when
+you want to share your network connection to another laptop @i{via} an
+Ethernet cable, you can open @command{nm-connection-editor} and configure the
+Wired connection's method for IPv4 and IPv6 to be ``Shared to other computers''
+and reestablish the connection (or reboot).
+
+You can also set up a @dfn{host-to-guest connection} to QEMU VMs
+(@pxref{Installing Guix in a VM}).  With a host-to-guest connection, you can
+e.g.@: access a Web server running on the VM (@pxref{Web Services}) from a Web
+browser on your host system, or connect to the VM @i{via} SSH
+(@pxref{Networking Services, @code{openssh-service-type}}).  To set up a
+host-to-guest connection, run this command once:
 
-(define (network-manager-activation config)
-  ;; Activation gexp for NetworkManager
-  (match-record config <network-manager-configuration>
-    (network-manager dns vpn-plugins)
-    #~(begin
-        (use-modules (guix build utils))
-        (mkdir-p "/etc/NetworkManager/system-connections")
-        #$@(if (equal? dns "dnsmasq")
-               ;; create directory to store dnsmasq lease file
-               '((mkdir-p "/var/lib/misc"))
-               '()))))
+@example
+nmcli connection add type tun \
+ connection.interface-name tap0 \
+ tun.mode tap tun.owner $(id -u) \
+ ipv4.method shared \
+ ipv4.addresses 172.28.112.1/24
+@end example
 
-(define (vpn-plugin-directory plugins)
-  "Return a directory containing PLUGINS, the NM VPN plugins."
-  (directory-union "network-manager-vpn-plugins" plugins))
+Then each time you launch your QEMU VM (@pxref{Running Guix in a VM}), pass
+@option{-nic tap,ifname=tap0,script=no,downscript=no} to
+@command{qemu-system-...}.
+
+@item none
+NetworkManager will not modify @code{resolv.conf}.
+@end table"
+   (serializer-options '(#:section main)))
+
+  (vpn-plugins
+   (list-of-packages '())
+   "This is the list of available plugins for virtual private networks
+(VPNs).  An example of this is the @code{network-manager-openvpn}
+package, which allows NetworkManager to manage VPNs @i{via} OpenVPN."
+   empty-serializer)
+
+  ;; Deprecated options
+  (iwd?
+   (boolean #f)
+   "Deprecated."
+   (sanitizer warn-iwd?-field-deprecation)
+   (serializer-options '(#:section device))
+   (serializer
+    (lambda (_ value . rest)
+      (let ((value (if value "iwd" "wpa_supplicant")))
+        (apply generic-ini-serialize-string
+               'wifi.backend value rest)))))
+
+  (prefix generic-ini-))
+
+(define (network-manager-serialize-configuration config)
+  (mixed-text-file
+   "NetworkManager.conf"
+   (serialize-ini-configuration config
+                                network-manager-configuration-fields)))
 
 (define (network-manager-accounts config)
   "Return the list of <user-account> and <user-group> for CONFIG."
-  (define nologin
-    (file-append shadow "/sbin/nologin"))
-
-  (define accounts
-    (append-map (lambda (package)
-                  (map (lambda (name)
-                         (user-account (system? #t)
-                                       (name name)
-                                       (group "network-manager")
-                                       (comment "NetworkManager helper")
-                                       (home-directory "/var/empty")
-                                       (create-home-directory? #f)
-                                       (shell nologin)))
-                       (or (assoc-ref (package-properties package)
-                                      'user-accounts)
-                           '())))
-                (network-manager-configuration-vpn-plugins config)))
-
-  (match accounts
-    (()
-     '())
-    (_
-     (cons (user-group (name "network-manager") (system? #t))
-           accounts))))
+  (match-record config <network-manager-configuration>
+    (vpn-plugins)
+    (let* ((nologin (file-append shadow "/sbin/nologin"))
+           (accounts
+            (append-map (lambda (package)
+                          (map (lambda (name)
+                                 (user-account
+                                  (system? #t)
+                                  (name name)
+                                  (group "network-manager")
+                                  (comment "NetworkManager helper")
+                                  (home-directory "/var/empty")
+                                  (create-home-directory? #f)
+                                  (shell nologin)))
+                               (or (assoc-ref (package-properties package)
+                                              'user-accounts)
+                                   '())))
+                        vpn-plugins)))
+      (cond
+       ((null? accounts) '())
+       (else (cons (user-group (name "network-manager")
+                               (system? #t))
+                   accounts))))))
 
 (define (network-manager-environment config)
+  "Define NM_VPN_PLUGIN_DIR variable in the global environment such that
+\"nmcli connection import type openvpn file foo.ovpn\" works."
   (match-record config <network-manager-configuration>
-    (network-manager dns vpn-plugins)
-    ;; Define this variable in the global environment such that
-    ;; "nmcli connection import type openvpn file foo.ovpn" works.
-    `(("NM_VPN_PLUGIN_DIR"
-       . ,(file-append (vpn-plugin-directory vpn-plugins)
-                       "/lib/NetworkManager/VPN")))))
+    (vpn-plugins)
+    (let ((plugin-union (directory-union "network-manager-vpn-plugins"
+                                         vpn-plugins)))
+      `(("NM_VPN_PLUGIN_DIR" . ,(file-append plugin-union
+                                             "/lib/NetworkManager/VPN"))))))
 
 (define (network-manager-shepherd-service config)
   (match-record config <network-manager-configuration>
-    (network-manager shepherd-requirement dns vpn-plugins iwd?)
+    (network-manager shepherd-requirement dns iwd?)
     (let* ((iwd? (or iwd?  ; TODO: deprecated field, remove later.
                      (and shepherd-requirement
                           (memq 'iwd shepherd-requirement))))
-           (conf (plain-file "NetworkManager.conf"
-                             (string-append
-                              "[main]\ndns=" dns "\n"
-                              (if iwd? "[device]\nwifi.backend=iwd\n" ""))))
-           (vpn  (vpn-plugin-directory vpn-plugins)))
+           (conf (network-manager-serialize-configuration config))
+           (vpn-plugin-env (map (match-lambda
+                                  ((key . value)
+                                   #~(string-append #$key "=" #$value)))
+                                (network-manager-environment config))))
       (list (shepherd-service
              (documentation "Run the NetworkManager.")
              (provision '(NetworkManager networking))
@@ -1254,6 +1308,10 @@ (define (network-manager-shepherd-service config)
              (actions (list (shepherd-configuration-action conf)))
              (start
               #~(lambda _
+                  (mkdir-p "/etc/NetworkManager/system-connections")
+                  ;; Create directory to store dnsmasq lease file.
+                  #$@(if (equal? dns "dnsmasq")
+                         '((mkdir-p "/var/lib/misc")) '())
                   (let ((pid
                          (fork+exec-command
                           (list #$(file-append network-manager
@@ -1261,8 +1319,7 @@ (define (network-manager-shepherd-service config)
                                 (string-append "--config=" #$conf)
                                 "--no-daemon")
                           #:environment-variables
-                          (list (string-append "NM_VPN_PLUGIN_DIR=" #$vpn
-                                               "/lib/NetworkManager/VPN")
+                          (list #$@vpn-plugin-env
                                 ;; Override non-existent default users
                                 "NM_OPENVPN_USER="
                                 "NM_OPENVPN_GROUP="
@@ -1301,8 +1358,6 @@ (define network-manager-service-type
                                 network-manager-configuration-network-manager))
             (service-extension account-service-type
                                network-manager-accounts)
-            (service-extension activation-service-type
-                               network-manager-activation)
             (service-extension session-environment-service-type
                                network-manager-environment)
             ;; Add network-manager to the system profile.
