diff --git a/roles/kubernetes/node/defaults/main.yml b/roles/kubernetes/node/defaults/main.yml
index a74e52b77c158712f4417c666b4e6072145a9869..d60b7620822d3244d848325e9e695251db267216 100644
--- a/roles/kubernetes/node/defaults/main.yml
+++ b/roles/kubernetes/node/defaults/main.yml
@@ -29,3 +29,7 @@ nginx_image_repo: nginx
 nginx_image_tag: 1.11.4-alpine
 
 etcd_config_dir: /etc/ssl/etcd
+
+# A port range to reserve for services with NodePort visibility.
+# Inclusive at both ends of the range.
+kube_apiserver_node_port_range: "30000-32767"
diff --git a/roles/kubernetes/node/tasks/main.yml b/roles/kubernetes/node/tasks/main.yml
index 3e0c095e18e822504ad9cd2cb3dcb67e4c84daad..2c18937c9a464f4d62b038885f157eb3e9bf263b 100644
--- a/roles/kubernetes/node/tasks/main.yml
+++ b/roles/kubernetes/node/tasks/main.yml
@@ -21,6 +21,16 @@
   notify: restart kubelet
   tags: kubelet
 
+- name: Ensure nodePort range is reserved
+  sysctl:
+    name: net.ipv4.ip_local_reserved_ports
+    value: "{{ kube_apiserver_node_port_range }}"
+    sysctl_set: yes
+    state: present
+    reload: yes
+  when: kube_apiserver_node_port_range is defined
+  tags: kube-proxy
+
 - name: Write proxy manifest
   template:
     src: manifests/kube-proxy.manifest.j2