{ lib, pkgs, const, config, ... }: {
	mkContainer = cfg: extra: lib.recursiveUpdate {
		# Allow nested containers.
		additionalCapabilities = [
			''all" --system-call-filter="add_key keyctl bpf" --capability="all''
		];
		enableTun = true;

		# Start containers with the system by default.
		autoStart = config.container.autoStart;

		# IP Address of the host. This is required for container to have access to the Internet.
		hostAddress = config.container.host;

		# Container's IP address.
		localAddress = cfg.address;

		# Isolate container from other hosts.
		privateNetwork = true;
	} extra;

	# Common configuration for the system inside the container.
	mkContainerConfig = cfg: extra: lib.recursiveUpdate {
		boot.isContainer = true;

		# HACK: Do not evaluate nixpkgs inside the container. Use host's instead.
		nixpkgs.pkgs = lib.mkForce pkgs;

		# Release version.
		system.stateVersion = const.stateVersion;

		# Allow passwordless login as root.
		users = {
			users.root.password = "";
			mutableUsers = false;
		};

		networking = {
			# Default DNS servers.
			nameservers = [
				"1.1.1.1"
				"1.0.0.1"
			];

			# HACK: Fix for upstream issue: https://github.com/NixOS/nixpkgs/issues/162686
			useHostResolvConf = lib.mkForce false;

			# Configure firewall.
			firewall = {
				enable = true;
				extraCommands = ''
					# Full access from the host.
					iptables -I INPUT -s ${config.container.host} -j ALLOW
				'';
			};
		};
	} extra;

	# Create a directory on the host for container use.
	mkContainerDir = cfg: dirs: map (path: "d '${cfg.storage}/${path}' 1777 root root - -") dirs;

	# Common configuration for Nginx server.
	mkServer = cfg: lib.recursiveUpdate {
		forceSSL = false;
	} cfg;

	# Attach the host media directory to container.
	# They will be added to /type/{0..9}
	attachMedia = type: ro: builtins.listToAttrs (lib.imap0 (i: path:
		{
			name = "/${type}/${toString i}";
			value = {
				hostPath   = path;
				isReadOnly = ro;
			};
		}
	) config.container.media.${type});
}