diff --git a/.gitignore b/.gitignore
index 9c2842d9..281f0b89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ publish/
 Gemfile.lock
 .bundle
 bin/
+.idea
diff --git a/.travis.yml b/.travis.yml
index fc764963..930f6beb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,12 +3,23 @@ rvm:
   - 2.0.0
   - 2.1
   - 2.2
+  - 2.3
+  - 2.4
+  - 2.5
+  - 2.6
   # optional
   - ruby-head
   - jruby-19mode
   - jruby-head
   - rbx-2
 
+addons:
+  hosts:
+    - ldap.example.org # needed for TLS verification
+
+services:
+  - docker
+
 env:
   - INTEGRATION=openldap
 
@@ -16,7 +27,18 @@ before_install:
   - gem update bundler
 
 install:
-  - if [ "$INTEGRATION" = "openldap" ]; then sudo script/install-openldap; fi
+  - >
+    docker run \
+      --hostname ldap.example.org \
+      --env LDAP_TLS_VERIFY_CLIENT=try \
+      -p 389:389 \
+      -p 636:636 \
+      -v "$(pwd)"/test/fixtures/ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom \
+      --name openldap \
+      --detach \
+      osixia/openldap:1.3.0 \
+        --copy-service \
+        --loglevel debug \
   - bundle install
 
 script: bundle exec rake ci
diff --git a/README.rdoc b/README.rdoc
index f1b1ea36..5098431e 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -53,9 +53,14 @@ This task will run the test suite and the
   rake rubotest
 
 CI takes too long? If your local box supports
-{Vagrant}[https://www.vagrantup.com/], you can run most of the tests
-in a VM on your local box. For more details and setup instructions, see
-{test/support/vm/openldap/README.md}[https://github.com/ruby-ldap/ruby-net-ldap/tree/master/test/support/vm/openldap/README.md]
+{Docker}[https://www.docker.com/], you can also run integration tests locally.
+Simply run:
+
+  script/ldap-docker
+  INTEGRATION=openldap rake test
+
+CAVEAT: you need to add the following line to /etc/hosts
+    127.0.0.1 ldap.example.org
 
 == Release
 
diff --git a/script/generate-fixture-ca b/script/generate-fixture-ca
deleted file mode 100755
index 89eb3d8d..00000000
--- a/script/generate-fixture-ca
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash
-
-BASE_PATH=$( cd "`dirname $0`/../test/fixtures/ca" && pwd )
-cd "${BASE_PATH}" || exit 4
-
-USAGE=$( cat << EOS
-Usage:
-  $0 --regenerate
-
-Generates a new self-signed CA, for integration testing. This should only need
-to be run if you are writing new TLS/SSL tests, and need to generate
-additional fixtuer CAs.
-
-This script uses the GnuTLS certtool CLI. If you are on macOS,
-'brew install gnutls', and it will be installed as 'gnutls-certtool'.
-Apple unfortunately ships with an incompatible /usr/bin/certtool that does
-different things.
-EOS
-)
-
-if [ "x$1" != 'x--regenerate' ]; then
-  echo "${USAGE}"
-  exit 1
-fi
-
-TOOL=`type -p certtool`
-if [ "$(uname)" = "Darwin" ]; then
-  TOOL=`type -p gnutls-certtool`
-  if [ ! -x "${TOOL}" ]; then
-    echo "Sorry, Darwin requires gnutls-certtool; try `brew install gnutls`"
-    exit 2
-  fi
-fi
-
-if [ ! -x "${TOOL}" ]; then
-  echo "Sorry, no certtool found!"
-  exit 3
-fi
-export TOOL
-
-
-${TOOL} --generate-privkey > ./cakey.pem
-${TOOL} --generate-self-signed \
-  --load-privkey ./cakey.pem \
-  --template ./ca.info \
-  --outfile ./cacert.pem
-
-echo "cert and private key generated! Don't forget to check them in"
diff --git a/script/install-openldap b/script/install-openldap
deleted file mode 100755
index 3e391d87..00000000
--- a/script/install-openldap
+++ /dev/null
@@ -1,134 +0,0 @@
-#!/usr/bin/env sh
-set -e
-set -x
-
-BASE_PATH=$( cd "`dirname $0`/../test/fixtures/openldap" && pwd )
-SEED_PATH=$( cd "`dirname $0`/../test/fixtures"          && pwd )
-
-dpkg -s slapd time ldap-utils gnutls-bin ssl-cert > /dev/null ||\
-  DEBIAN_FRONTEND=noninteractive apt-get update  -y --force-yes && \
-  DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes slapd time ldap-utils gnutls-bin ssl-cert
-
-/etc/init.d/slapd stop
-
-TMPDIR=$(mktemp -d)
-cd $TMPDIR
-
-# Delete data and reconfigure.
-cp -v /var/lib/ldap/DB_CONFIG ./DB_CONFIG
-rm -rf /etc/ldap/slapd.d/*
-rm -rf /var/lib/ldap/*
-cp -v ./DB_CONFIG /var/lib/ldap/DB_CONFIG
-slapadd -F /etc/ldap/slapd.d -b "cn=config" -l $BASE_PATH/slapd.conf.ldif
-# Load memberof and ref-int overlays and configure them.
-slapadd -F /etc/ldap/slapd.d -b "cn=config" -l $BASE_PATH/memberof.ldif
-# Load retcode overlay and configure
-slapadd -F /etc/ldap/slapd.d -b "cn=config" -l $BASE_PATH/retcode.ldif
-
-# Add base domain.
-slapadd -F /etc/ldap/slapd.d <<EOM
-dn: dc=rubyldap,dc=com
-objectClass: top
-objectClass: domain
-dc: rubyldap
-EOM
-
-chown -R openldap.openldap /etc/ldap/slapd.d
-chown -R openldap.openldap /var/lib/ldap
-
-/etc/init.d/slapd start
-
-# Import seed data.
-# NOTE: use ldapadd in order for memberOf and refint to apply, instead of:
-# cat $SEED_PATH/seed.ldif | slapadd -F /etc/ldap/slapd.d
-/usr/bin/time ldapadd -x -D "cn=admin,dc=rubyldap,dc=com" -w passworD1 \
-             -h localhost -p 389 \
-             -f $SEED_PATH/seed.ldif
-
-rm -rf $TMPDIR
-
-# SSL
-export CA_CERT="/usr/local/share/ca-certificates/rubyldap-ca.crt"
-export CA_KEY="/etc/ssl/private/rubyldap-ca.key"
-
-# The self-signed fixture CA cert & key are generated by
-# `script/generate-fiuxture-ca` and checked into version control.
-# You shouldn't need to muck with these unless you're writing more
-# TLS/SSL integration tests, and need special magic values in the cert.
-
-cp "${SEED_PATH}/ca/cacert.pem" "${CA_CERT}"
-cp "${SEED_PATH}/ca/cakey.pem"  "${CA_KEY}"
-
-# actually add the fixture CA to the system store
-update-ca-certificates
-
-# Make a private key for the server:
-certtool --generate-privkey \
-  --bits 1024 \
-  --outfile /etc/ssl/private/ldap01_slapd_key.pem
-
-sh -c "cat > /etc/ssl/ldap01.info <<EOF
-organization = Example Company
-cn = ldap01.example.com
-dns_name = ldap01.example.com
-dns_name = ldap02.example.com
-dns_name = localhost
-tls_www_server
-encryption_key
-signing_key
-expiration_days = 3650
-EOF"
-
-# The integration server may be accessed by IP address, in which case
-# we want some of the IPs included in the cert. We skip loopback (127.0.0.1)
-# because that's the IP we use in the integration test for cert name mismatches.
-ADDRS=$(ifconfig -a | grep 'inet addr:' | cut -f 2 -d : | cut -f 1 -d ' ')
-for ip in $ADDRS; do
-  if [ "x$ip" = 'x127.0.0.1' ]; then continue; fi
-  echo "ip_address = $ip" >> /etc/ssl/ldap01.info
-done
-
-# Create the server certificate
-certtool --generate-certificate \
-  --load-privkey /etc/ssl/private/ldap01_slapd_key.pem \
-  --load-ca-certificate "${CA_CERT}" \
-  --load-ca-privkey "${CA_KEY}" \
-  --template /etc/ssl/ldap01.info \
-  --outfile /etc/ssl/certs/ldap01_slapd_cert.pem
-
-ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF | true
-dn: cn=config
-add: olcTLSCACertificateFile
-olcTLSCACertificateFile: ${CA_CERT}
--
-add: olcTLSCertificateFile
-olcTLSCertificateFile: /etc/ssl/certs/ldap01_slapd_cert.pem
--
-add: olcTLSCertificateKeyFile
-olcTLSCertificateKeyFile: /etc/ssl/private/ldap01_slapd_key.pem
-EOF
-
-# LDAP over TLS/SSL (ldaps://) is deprecated in favour of StartTLS. The latter
-# refers to an existing LDAP session (listening on TCP port 389) becoming
-# protected by TLS/SSL whereas LDAPS, like HTTPS, is a distinct
-# encrypted-from-the-start protocol that operates over TCP port 636. But we
-# enable it for testing here.
-sed -i -e 's|^SLAPD_SERVICES="\(.*\)"|SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///"|' /etc/default/slapd
-
-adduser openldap ssl-cert
-chgrp ssl-cert /etc/ssl/private/ldap01_slapd_key.pem
-chmod g+r /etc/ssl/private/ldap01_slapd_key.pem
-chmod o-r /etc/ssl/private/ldap01_slapd_key.pem
-
-# Drop packets on a secondary port used to specific timeout tests
-iptables -A INPUT -p tcp -j DROP --dport 8389
-
-# Forward a port for Vagrant
-iptables -t nat -A PREROUTING -p tcp --dport 9389 -j REDIRECT --to-port 389
-
-# fix up /etc/hosts for cert validation
-grep ldap01 /etc/hosts || echo "127.0.0.1 ldap01.example.com" >> /etc/hosts
-grep ldap02 /etc/hosts || echo "127.0.0.1 ldap02.example.com" >> /etc/hosts
-grep bogus /etc/hosts  || echo "127.0.0.1 bogus.example.com" >> /etc/hosts
-
-service slapd restart
diff --git a/script/ldap-docker b/script/ldap-docker
new file mode 100755
index 00000000..c677eec8
--- /dev/null
+++ b/script/ldap-docker
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+# Usage: script/ldap-docker
+#
+# Starts a openldap docker container ready for integration tests
+
+docker run --rm -ti \
+  --hostname ldap.example.org \
+  --env LDAP_TLS_VERIFY_CLIENT=try \
+  -p 389:389 -p 636:636 \
+  -v "$(pwd)"/test/fixtures/ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom \
+  --name my-openldap-container \
+  osixia/openldap:1.3.0 --copy-service --loglevel debug
\ No newline at end of file
diff --git a/test/fixtures/ca/ca.info b/test/fixtures/ca/ca.info
deleted file mode 100644
index c0fd3629..00000000
--- a/test/fixtures/ca/ca.info
+++ /dev/null
@@ -1,4 +0,0 @@
-cn = rubyldap
-ca
-cert_signing_key
-expiration_days = 7200
diff --git a/test/fixtures/ca/cacert.pem b/test/fixtures/ca/cacert.pem
deleted file mode 100644
index 0218dd8a..00000000
--- a/test/fixtures/ca/cacert.pem
+++ /dev/null
@@ -1,24 +0,0 @@
------BEGIN CERTIFICATE-----
-MIID7zCCAlegAwIBAgIMV7zWei6SNfABx6jMMA0GCSqGSIb3DQEBCwUAMBMxETAP
-BgNVBAMTCHJ1YnlsZGFwMB4XDTE2MDgyMzIzMDQyNloXDTM2MDUxMDIzMDQyNlow
-EzERMA8GA1UEAxMIcnVieWxkYXAwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGK
-AoIBgQDGe9wziGHZJhIf+IEKSk1tpT9Mu7YgsUwjrlutvkoO1Q6K+amTAVDXizPf
-1DVSDpZP5+CfBOznhgLMsPvrQ02w4qx5/6X9L+zJcMk8jTNYSKj5uIKpK52E7Uok
-aygMXeaqroPONGkoJIZiVGgdbWfTvcffTm8FOhztXUbMrMXJNinFsocGHEoMNN8b
-vqgAyG4+DFHoK4L0c6eQjE4nZBChieZdShUhaBpV7r2qSNbPw67cvAKuEzml58mV
-1ZF1F73Ua8gPWXHEfUe2GEfG0NnRq6sGbsDYe/DIKxC7AZ89udZF3WZXNrPhvXKj
-ZT7njwcMQemns4dNPQ0k2V4vAQ8pD8r8Qvb65FiSopUhVaGQswAnIMS1DnFq88AQ
-KJTKIXbBuMwuaNNSs6R/qTS2RDk1w+CGpRXAg7+1SX5NKdrEsu1IaABA/tQ/zKKk
-OLLJaD0giX1weBVmNeFcKxIoT34VS59eEt5APmPcguJnx+aBrA9TLzSO788apBN0
-4lGAmR0CAwEAAaNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwQA
-MB0GA1UdDgQWBBRTvXSkge03oqLu7UUjFI+oLYwnujANBgkqhkiG9w0BAQsFAAOC
-AYEATSZQWH+uSN5GvOUvJ8LHWkeVovn0UhboK0K7GzmMeGz+dp/Xrj6eQ4ONK0zI
-RCJyoo/nCR7CfQ5ujVXr03XD2SUgyD565ulXuhw336DasL5//fucmQYDeqhwbKML
-FTzsF9H9dO4J5TjxJs7e5dRJ0wrP/XEY+WFhXXdSHTl8vGCI6QqWc7TvDpmbS4iX
-uTzjJswu9Murt9JUJNMN2DlDi/vBBeruaj4c2cMMnKMvkfj14kd8wMocmzj+gVQl
-r+fRQbKAJNec65lA4/Zeb6sD9SAi0ZIVgxA4a7g8/sdNWHIAxPicpJkIJf30TsyY
-F+8+Hd5mBtCbvFfAVkT6bHBP1OiAgNke+Rh/j/sQbyWbKCKw0+jpFJgO9KUNGfC0
-O/CqX+J4G7HqL8VJqrLnBvOdhfetAvNQtf1gcw5ZwpeEFM+Kvx/lsILaIYdAUSjX
-ePOc5gI2Bi9WXq+T9AuhSf+TWUR874m/rdTWe5fM8mXCNl7C4I5zCqLltEDkSoMP
-jDj/
------END CERTIFICATE-----
diff --git a/test/fixtures/ca/cakey.pem b/test/fixtures/ca/cakey.pem
deleted file mode 100644
index d75ab299..00000000
--- a/test/fixtures/ca/cakey.pem
+++ /dev/null
@@ -1,190 +0,0 @@
-Public Key Info:
-	Public Key Algorithm: RSA
-	Key Security Level: High (3072 bits)
-
-modulus:
-	00:c6:7b:dc:33:88:61:d9:26:12:1f:f8:81:0a:4a:4d
-	6d:a5:3f:4c:bb:b6:20:b1:4c:23:ae:5b:ad:be:4a:0e
-	d5:0e:8a:f9:a9:93:01:50:d7:8b:33:df:d4:35:52:0e
-	96:4f:e7:e0:9f:04:ec:e7:86:02:cc:b0:fb:eb:43:4d
-	b0:e2:ac:79:ff:a5:fd:2f:ec:c9:70:c9:3c:8d:33:58
-	48:a8:f9:b8:82:a9:2b:9d:84:ed:4a:24:6b:28:0c:5d
-	e6:aa:ae:83:ce:34:69:28:24:86:62:54:68:1d:6d:67
-	d3:bd:c7:df:4e:6f:05:3a:1c:ed:5d:46:cc:ac:c5:c9
-	36:29:c5:b2:87:06:1c:4a:0c:34:df:1b:be:a8:00:c8
-	6e:3e:0c:51:e8:2b:82:f4:73:a7:90:8c:4e:27:64:10
-	a1:89:e6:5d:4a:15:21:68:1a:55:ee:bd:aa:48:d6:cf
-	c3:ae:dc:bc:02:ae:13:39:a5:e7:c9:95:d5:91:75:17
-	bd:d4:6b:c8:0f:59:71:c4:7d:47:b6:18:47:c6:d0:d9
-	d1:ab:ab:06:6e:c0:d8:7b:f0:c8:2b:10:bb:01:9f:3d
-	b9:d6:45:dd:66:57:36:b3:e1:bd:72:a3:65:3e:e7:8f
-	07:0c:41:e9:a7:b3:87:4d:3d:0d:24:d9:5e:2f:01:0f
-	29:0f:ca:fc:42:f6:fa:e4:58:92:a2:95:21:55:a1:90
-	b3:00:27:20:c4:b5:0e:71:6a:f3:c0:10:28:94:ca:21
-	76:c1:b8:cc:2e:68:d3:52:b3:a4:7f:a9:34:b6:44:39
-	35:c3:e0:86:a5:15:c0:83:bf:b5:49:7e:4d:29:da:c4
-	b2:ed:48:68:00:40:fe:d4:3f:cc:a2:a4:38:b2:c9:68
-	3d:20:89:7d:70:78:15:66:35:e1:5c:2b:12:28:4f:7e
-	15:4b:9f:5e:12:de:40:3e:63:dc:82:e2:67:c7:e6:81
-	ac:0f:53:2f:34:8e:ef:cf:1a:a4:13:74:e2:51:80:99
-	1d:
-
-public exponent:
-	01:00:01:
-
-private exponent:
-	1d:0d:9a:50:ec:c0:ad:e1:75:bb:ba:4b:61:2f:39:20
-	38:95:08:6d:5d:9e:71:75:5c:af:b3:f9:bd:a5:e7:7f
-	e6:4e:0f:77:73:ee:38:60:24:9f:26:3f:50:c2:bf:21
-	df:76:68:99:be:45:d3:29:f9:94:ee:bf:21:53:cb:b6
-	7d:a7:93:80:09:53:03:45:dc:c2:a6:a2:37:64:f1:a2
-	49:21:ac:91:6b:a3:d7:bd:d2:62:0c:ec:a6:83:10:e7
-	a7:ca:3d:be:dc:4b:1c:36:24:79:96:33:5b:43:5d:74
-	50:0e:46:b0:9b:6d:9f:71:06:89:a5:c8:65:ed:d9:a3
-	15:00:3c:3e:a9:75:50:9d:72:cb:c9:aa:e1:ba:a3:9c
-	07:77:14:32:30:d4:4d:65:f4:7c:23:1d:79:84:9b:2e
-	9a:19:df:43:ed:cd:e3:08:1f:d5:ff:6b:42:98:36:f7
-	44:cc:48:b4:f7:b8:16:b3:23:37:8d:b8:22:3f:8a:86
-	db:71:b3:85:2d:6d:42:44:b7:dc:c1:36:e0:c4:0f:fe
-	cb:76:84:81:e2:83:f5:82:76:a9:7b:35:d5:44:00:d1
-	1a:fc:ef:b9:a4:2b:62:aa:f8:56:eb:60:e5:16:33:f1
-	28:e1:da:91:50:e3:a4:c7:d6:30:21:cf:04:07:cd:8c
-	b6:9e:b0:a7:6c:96:57:2e:09:5b:39:26:d0:60:be:e3
-	90:59:a3:8e:e7:6e:3f:62:7e:b4:2a:e1:8f:00:37:7a
-	83:9e:7a:9c:d2:ae:ba:50:84:73:65:3a:64:95:d8:48
-	f9:fd:0e:c3:5b:6e:08:3b:c5:c9:1c:29:55:bb:67:e8
-	fa:50:40:30:2a:d1:b7:cf:54:a8:f0:f0:76:89:ad:19
-	e7:a0:3a:56:6c:75:c5:bc:d8:46:ce:1e:66:f2:61:96
-	11:e4:57:cc:52:ff:e4:ed:6b:2c:ce:78:15:ba:b7:ed
-	31:f2:68:88:79:bf:7c:29:3c:2f:66:71:0b:09:b7:41
-	
-
-prime1:
-	00:fd:c2:37:b9:6f:77:88:51:a2:f7:4f:c2:3c:a4:57
-	bf:ba:71:14:f3:61:f4:39:78:22:3d:bc:d8:d2:4e:c0
-	4b:9e:c2:6d:38:a8:21:e2:70:1a:96:48:95:18:85:01
-	46:fb:62:a4:81:09:f8:2a:3a:87:78:07:5d:93:54:ce
-	2a:51:b3:51:6f:61:0a:2e:9d:b0:51:37:e3:13:bd:81
-	23:2b:61:53:fa:ac:08:dc:a0:e6:63:a3:b0:cc:cf:73
-	1d:65:b7:11:bc:29:70:fb:72:ea:63:9d:67:02:d6:35
-	24:13:1d:bc:72:fb:9e:3d:ab:0b:57:6e:bd:a1:51:56
-	f9:bc:96:15:74:a3:31:16:c6:b8:98:1b:0a:a2:59:7c
-	c8:b7:14:b8:5b:f3:2e:26:b4:f0:46:c4:3d:27:dd:41
-	31:52:a7:15:a8:af:6a:98:a5:9c:20:17:f9:1d:54:54
-	ff:10:91:a3:a5:ca:ac:63:e7:16:2b:71:3c:3a:cd:4f
-	ed:
-
-prime2:
-	00:c8:3c:a8:9f:8a:db:42:b5:8d:cf:2a:a1:2f:e5:73
-	05:de:30:d8:17:b9:5c:9d:08:60:02:c9:66:9d:88:50
-	ac:cd:0f:b5:47:b4:a8:73:3b:7d:65:79:bf:4c:6f:d0
-	e2:03:ed:d4:28:4e:00:07:23:00:01:4f:05:de:9b:44
-	1a:84:ae:09:4a:d6:ed:61:5d:77:e2:fa:13:99:4c:b7
-	76:72:3d:f8:53:93:69:78:e8:bd:26:cb:b0:f9:01:f4
-	1d:20:4f:60:f5:ab:3c:19:85:73:34:f3:ec:d2:67:ef
-	56:b8:5d:93:73:8e:d9:3e:28:ff:87:f5:4a:26:fa:b1
-	ae:c6:d3:9d:03:e3:fd:c2:24:48:af:85:2a:8e:3b:5b
-	93:07:38:91:21:ae:49:cb:6d:e3:30:81:15:ed:65:eb
-	dc:01:df:3b:9d:43:fd:a6:e1:df:ef:ad:22:42:34:f1
-	3f:81:5e:57:0a:e0:56:94:f2:2a:00:d0:cc:c5:50:67
-	f1:
-
-coefficient:
-	00:bd:23:8c:2e:a7:7b:6b:1e:85:77:db:7d:77:f6:e5
-	b0:15:c6:e1:9e:35:57:72:df:35:6d:93:89:7f:83:9f
-	63:7f:08:0a:b3:d4:ba:63:9b:10:7f:0f:d3:55:e9:38
-	cf:90:37:3d:85:3d:a7:97:8c:33:f2:c2:b1:38:2b:db
-	39:ca:a8:d0:23:d7:89:cc:8d:02:7d:61:9b:b6:04:69
-	14:e8:c9:84:34:36:6c:fb:84:58:cc:9a:53:74:a4:42
-	bd:1d:25:1b:ba:82:c0:fb:23:2c:90:bb:35:4b:5b:b0
-	98:d0:ab:9d:61:6e:ea:e8:84:e7:a7:6c:ae:1b:2c:00
-	cb:0f:1a:f8:e2:7c:fd:42:1a:e2:13:52:c7:50:fa:65
-	c9:5f:ed:40:a8:7f:46:0e:ce:f6:56:83:6f:0e:8e:39
-	f8:33:5f:83:de:be:be:ef:8c:66:ad:16:c8:ec:98:d4
-	b2:b2:55:66:a2:9e:27:6a:84:f1:31:07:e8:bf:a7:a7
-	bd:
-
-exp1:
-	00:b6:50:0c:53:19:07:8b:14:03:fe:a4:fa:0b:31:93
-	ad:b7:18:b9:91:a6:c5:9d:68:77:49:5d:dd:75:33:89
-	2a:8b:54:6a:be:32:e5:ad:57:17:72:f3:90:d2:fd:f4
-	0d:f8:5c:45:8e:44:08:5c:e6:92:1f:a5:43:10:af:f4
-	33:29:61:a8:d7:59:a3:c4:1c:1c:ea:2d:39:e3:1b:da
-	a4:d6:ec:e5:36:0a:d5:8f:15:b6:90:cd:b1:1f:64:c7
-	f2:cd:fa:3a:2e:b2:a3:6e:b4:80:3b:b3:81:a7:e3:18
-	68:e3:a7:10:96:97:ba:77:d9:e4:9b:1b:7f:f8:5f:85
-	1a:85:e8:5a:5f:e3:43:48:76:db:76:c4:ae:de:37:66
-	d4:99:dc:b4:1b:b3:da:6b:8a:c1:ba:46:11:1e:0b:f3
-	63:a9:5b:4b:cf:56:c0:42:0d:71:df:08:fa:3c:9d:33
-	37:d1:c2:a1:0d:63:50:79:b2:34:16:60:13:82:b7:b1
-	7d:
-
-exp2:
-	00:98:38:2c:c4:24:4e:2c:b7:52:17:a4:43:a6:e2:99
-	ff:62:fa:e4:bb:9c:49:40:83:66:61:97:f3:af:5c:3a
-	60:32:ff:77:03:0c:de:65:c3:5a:bf:72:bf:2f:7f:6d
-	5e:f4:37:af:69:f8:69:e3:03:03:74:fb:3a:ee:10:40
-	c4:9c:0a:a5:bb:c4:09:ef:53:9b:d8:eb:dd:4c:53:da
-	c0:6b:76:9a:ba:06:3d:4f:12:37:01:30:25:d8:16:59
-	1a:6f:3e:88:ea:19:83:75:af:52:76:75:dc:99:d3:33
-	4a:4c:9b:ae:85:51:99:ea:bc:46:0d:78:36:27:cd:ba
-	97:b0:44:9c:7f:a1:a9:7e:16:11:3f:85:4f:65:92:d0
-	39:c4:6a:87:42:00:79:ce:f1:39:9d:dc:f3:eb:65:e8
-	d8:76:7f:da:94:e2:64:08:a2:7b:97:7b:99:a8:95:10
-	b5:03:46:d1:8a:ce:22:63:d6:78:81:e8:39:52:e2:9e
-	31:
-
-
-Public Key ID: 53:BD:74:A4:81:ED:37:A2:A2:EE:ED:45:23:14:8F:A8:2D:8C:27:BA
-Public key's random art:
-+--[ RSA 3072]----+
-|        .  o. .  |
-|       . +...+   |
-|      . o o.+ .  |
-|   o o . . .ooo  |
-|  o = . S o..o . |
-| . o .  .+..     |
-|.      . ..      |
-| .    .. .       |
-|E    oo.o        |
-+-----------------+
-
------BEGIN RSA PRIVATE KEY-----
-MIIG5QIBAAKCAYEAxnvcM4hh2SYSH/iBCkpNbaU/TLu2ILFMI65brb5KDtUOivmp
-kwFQ14sz39Q1Ug6WT+fgnwTs54YCzLD760NNsOKsef+l/S/syXDJPI0zWEio+biC
-qSudhO1KJGsoDF3mqq6DzjRpKCSGYlRoHW1n073H305vBToc7V1GzKzFyTYpxbKH
-BhxKDDTfG76oAMhuPgxR6CuC9HOnkIxOJ2QQoYnmXUoVIWgaVe69qkjWz8Ou3LwC
-rhM5pefJldWRdRe91GvID1lxxH1HthhHxtDZ0aurBm7A2HvwyCsQuwGfPbnWRd1m
-Vzaz4b1yo2U+548HDEHpp7OHTT0NJNleLwEPKQ/K/EL2+uRYkqKVIVWhkLMAJyDE
-tQ5xavPAECiUyiF2wbjMLmjTUrOkf6k0tkQ5NcPghqUVwIO/tUl+TSnaxLLtSGgA
-QP7UP8yipDiyyWg9IIl9cHgVZjXhXCsSKE9+FUufXhLeQD5j3ILiZ8fmgawPUy80
-ju/PGqQTdOJRgJkdAgMBAAECggGAHQ2aUOzAreF1u7pLYS85IDiVCG1dnnF1XK+z
-+b2l53/mTg93c+44YCSfJj9Qwr8h33Zomb5F0yn5lO6/IVPLtn2nk4AJUwNF3MKm
-ojdk8aJJIayRa6PXvdJiDOymgxDnp8o9vtxLHDYkeZYzW0NddFAORrCbbZ9xBoml
-yGXt2aMVADw+qXVQnXLLyarhuqOcB3cUMjDUTWX0fCMdeYSbLpoZ30PtzeMIH9X/
-a0KYNvdEzEi097gWsyM3jbgiP4qG23GzhS1tQkS33ME24MQP/st2hIHig/WCdql7
-NdVEANEa/O+5pCtiqvhW62DlFjPxKOHakVDjpMfWMCHPBAfNjLaesKdsllcuCVs5
-JtBgvuOQWaOO524/Yn60KuGPADd6g556nNKuulCEc2U6ZJXYSPn9DsNbbgg7xckc
-KVW7Z+j6UEAwKtG3z1So8PB2ia0Z56A6Vmx1xbzYRs4eZvJhlhHkV8xS/+TtayzO
-eBW6t+0x8miIeb98KTwvZnELCbdBAoHBAP3CN7lvd4hRovdPwjykV7+6cRTzYfQ5
-eCI9vNjSTsBLnsJtOKgh4nAalkiVGIUBRvtipIEJ+Co6h3gHXZNUzipRs1FvYQou
-nbBRN+MTvYEjK2FT+qwI3KDmY6OwzM9zHWW3EbwpcPty6mOdZwLWNSQTHbxy+549
-qwtXbr2hUVb5vJYVdKMxFsa4mBsKoll8yLcUuFvzLia08EbEPSfdQTFSpxWor2qY
-pZwgF/kdVFT/EJGjpcqsY+cWK3E8Os1P7QKBwQDIPKifittCtY3PKqEv5XMF3jDY
-F7lcnQhgAslmnYhQrM0PtUe0qHM7fWV5v0xv0OID7dQoTgAHIwABTwXem0QahK4J
-StbtYV134voTmUy3dnI9+FOTaXjovSbLsPkB9B0gT2D1qzwZhXM08+zSZ+9WuF2T
-c47ZPij/h/VKJvqxrsbTnQPj/cIkSK+FKo47W5MHOJEhrknLbeMwgRXtZevcAd87
-nUP9puHf760iQjTxP4FeVwrgVpTyKgDQzMVQZ/ECgcEAtlAMUxkHixQD/qT6CzGT
-rbcYuZGmxZ1od0ld3XUziSqLVGq+MuWtVxdy85DS/fQN+FxFjkQIXOaSH6VDEK/0
-MylhqNdZo8QcHOotOeMb2qTW7OU2CtWPFbaQzbEfZMfyzfo6LrKjbrSAO7OBp+MY
-aOOnEJaXunfZ5Jsbf/hfhRqF6Fpf40NIdtt2xK7eN2bUmdy0G7Paa4rBukYRHgvz
-Y6lbS89WwEINcd8I+jydMzfRwqENY1B5sjQWYBOCt7F9AoHBAJg4LMQkTiy3Uhek
-Q6bimf9i+uS7nElAg2Zhl/OvXDpgMv93AwzeZcNav3K/L39tXvQ3r2n4aeMDA3T7
-Ou4QQMScCqW7xAnvU5vY691MU9rAa3aaugY9TxI3ATAl2BZZGm8+iOoZg3WvUnZ1
-3JnTM0pMm66FUZnqvEYNeDYnzbqXsEScf6GpfhYRP4VPZZLQOcRqh0IAec7xOZ3c
-8+tl6Nh2f9qU4mQIonuXe5molRC1A0bRis4iY9Z4geg5UuKeMQKBwQC9I4wup3tr
-HoV323139uWwFcbhnjVXct81bZOJf4OfY38ICrPUumObEH8P01XpOM+QNz2FPaeX
-jDPywrE4K9s5yqjQI9eJzI0CfWGbtgRpFOjJhDQ2bPuEWMyaU3SkQr0dJRu6gsD7
-IyyQuzVLW7CY0KudYW7q6ITnp2yuGywAyw8a+OJ8/UIa4hNSx1D6Zclf7UCof0YO
-zvZWg28Ojjn4M1+D3r6+74xmrRbI7JjUsrJVZqKeJ2qE8TEH6L+np70=
------END RSA PRIVATE KEY-----
diff --git a/test/fixtures/ca/docker-ca.pem b/test/fixtures/ca/docker-ca.pem
new file mode 100644
index 00000000..ab543a31
--- /dev/null
+++ b/test/fixtures/ca/docker-ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAlmgAwIBAgIUCfQ+m0pgZ/BjYAJvxrn/bdGNZokwCgYIKoZIzj0EAwMw
+gZYxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxBMUEgQ2FyIFdhc2gxJDAiBgNVBAsT
+G0luZm9ybWF0aW9uIFRlY2hub2xvZ3kgRGVwLjEUMBIGA1UEBxMLQWxidXF1ZXJx
+dWUxEzARBgNVBAgTCk5ldyBNZXhpY28xHzAdBgNVBAMTFmRvY2tlci1saWdodC1i
+YXNlaW1hZ2UwHhcNMTUxMjIzMTM1MzAwWhcNMjAxMjIxMTM1MzAwWjCBljELMAkG
+A1UEBhMCVVMxFTATBgNVBAoTDEExQSBDYXIgV2FzaDEkMCIGA1UECxMbSW5mb3Jt
+YXRpb24gVGVjaG5vbG9neSBEZXAuMRQwEgYDVQQHEwtBbGJ1cXVlcnF1ZTETMBEG
+A1UECBMKTmV3IE1leGljbzEfMB0GA1UEAxMWZG9ja2VyLWxpZ2h0LWJhc2VpbWFn
+ZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMZf/12pupAgl8Sm+j8GmjNeNbSFAZWW
+oTmIvf2Mu4LWPHy4bTldkQgHUbBpT3xWz8f0lB/ru7596CHsGoL2A28hxuclq5hb
+Ux1yrIt3bJIY3TuiX25HGTe6kGCJPB1aLaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIG
+A1UdEwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFE+l6XolXDAYnGLTl4W6ULKHrm74
+MB8GA1UdIwQYMBaAFE+l6XolXDAYnGLTl4W6ULKHrm74MAoGCCqGSM49BAMDA2gA
+MGUCMQCXLZj8okyxW6UTL7hribUUbu63PbjuwIXnwi420DdNsvA9A7fcQEXScWFL
+XAGC8rkCMGcqwXZPSRfwuI9r+R11gTrP92hnaVxs9sjRikctpkQpOyNlIXFPopFK
+8FdfWPypvA==
+-----END CERTIFICATE-----
diff --git a/test/fixtures/openldap/retcode.ldif b/test/fixtures/ldif/06-retcode.ldif
similarity index 92%
rename from test/fixtures/openldap/retcode.ldif
rename to test/fixtures/ldif/06-retcode.ldif
index 9faffe1d..dfd12d06 100644
--- a/test/fixtures/openldap/retcode.ldif
+++ b/test/fixtures/ldif/06-retcode.ldif
@@ -1,19 +1,18 @@
-dn: cn=module,cn=config
-cn: module
-objectClass: olcModuleList
-objectClass: top
-olcModulePath: /usr/lib/ldap
-olcModuleLoad: retcode.la
+dn: cn=module{0},cn=config
+changetype: modify
+add: olcModuleLoad
+olcModuleLoad: retcode
 
 # source: http://www.opensource.apple.com/source/OpenLDAP/OpenLDAP-186/OpenLDAP/tests/data/retcode.conf?txt
 
-dn: olcOverlay={2}retcode,olcDatabase={1}hdb,cn=config
+dn: olcOverlay={2}retcode,olcDatabase={1}{{ LDAP_BACKEND }},cn=config
+changetype: add
 objectClass: olcConfig
 objectClass: olcRetcodeConfig
 objectClass: olcOverlayConfig
 objectClass: top
 olcOverlay: retcode
-olcRetcodeParent: ou=Retcodes,dc=rubyldap,dc=com
+olcRetcodeParent: ou=Retcodes,dc=example,dc=org
 olcRetcodeInDir: TRUE
 olcRetcodeSleep: 0
 olcRetcodeItem: "cn=success" 0x00
diff --git a/test/fixtures/ldif/50-seed.ldif b/test/fixtures/ldif/50-seed.ldif
new file mode 100644
index 00000000..addedf5a
--- /dev/null
+++ b/test/fixtures/ldif/50-seed.ldif
@@ -0,0 +1,374 @@
+dn: ou=People,dc=example,dc=org
+objectClass: top
+objectClass: organizationalUnit
+ou: People
+
+dn: ou=Groups,dc=example,dc=org
+objectClass: top
+objectClass: organizationalUnit
+ou: Groups
+
+# Directory Superuser
+dn: uid=admin,dc=example,dc=org
+uid: admin
+cn: system administrator
+sn: administrator
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+displayName: Directory Superuser
+userPassword: passworD1
+
+# Users 1-10
+
+dn: uid=user1,ou=People,dc=example,dc=org
+uid: user1
+cn: user1
+sn: user1
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: user1@rubyldap.com
+
+dn: uid=user2,ou=People,dc=example,dc=org
+uid: user2
+cn: user2
+sn: user2
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: user2@rubyldap.com
+
+dn: uid=user3,ou=People,dc=example,dc=org
+uid: user3
+cn: user3
+sn: user3
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: user3@rubyldap.com
+
+dn: uid=user4,ou=People,dc=example,dc=org
+uid: user4
+cn: user4
+sn: user4
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: user4@rubyldap.com
+
+dn: uid=user5,ou=People,dc=example,dc=org
+uid: user5
+cn: user5
+sn: user5
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: user5@rubyldap.com
+
+dn: uid=user6,ou=People,dc=example,dc=org
+uid: user6
+cn: user6
+sn: user6
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: user6@rubyldap.com
+
+dn: uid=user7,ou=People,dc=example,dc=org
+uid: user7
+cn: user7
+sn: user7
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: user7@rubyldap.com
+
+dn: uid=user8,ou=People,dc=example,dc=org
+uid: user8
+cn: user8
+sn: user8
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: user8@rubyldap.com
+
+dn: uid=user9,ou=People,dc=example,dc=org
+uid: user9
+cn: user9
+sn: user9
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: user9@rubyldap.com
+
+dn: uid=user10,ou=People,dc=example,dc=org
+uid: user10
+cn: user10
+sn: user10
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: user10@rubyldap.com
+
+# Emailless User
+
+dn: uid=emailless-user1,ou=People,dc=example,dc=org
+uid: emailless-user1
+cn: emailless-user1
+sn: emailless-user1
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+
+# Groupless User
+
+dn: uid=groupless-user1,ou=People,dc=example,dc=org
+uid: groupless-user1
+cn: groupless-user1
+sn: groupless-user1
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+
+# Admin User
+
+dn: uid=admin1,ou=People,dc=example,dc=org
+uid: admin1
+cn: admin1
+sn: admin1
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+userPassword: passworD1
+mail: admin1@rubyldap.com
+
+# Groups
+
+dn: cn=ghe-users,ou=Groups,dc=example,dc=org
+cn: ghe-users
+objectClass: groupOfNames
+member: uid=user1,ou=People,dc=example,dc=org
+member: uid=emailless-user1,ou=People,dc=example,dc=org
+
+dn: cn=all-users,ou=Groups,dc=example,dc=org
+cn: all-users
+objectClass: groupOfNames
+member: cn=ghe-users,ou=Groups,dc=example,dc=org
+member: uid=user1,ou=People,dc=example,dc=org
+member: uid=user2,ou=People,dc=example,dc=org
+member: uid=user3,ou=People,dc=example,dc=org
+member: uid=user4,ou=People,dc=example,dc=org
+member: uid=user5,ou=People,dc=example,dc=org
+member: uid=user6,ou=People,dc=example,dc=org
+member: uid=user7,ou=People,dc=example,dc=org
+member: uid=user8,ou=People,dc=example,dc=org
+member: uid=user9,ou=People,dc=example,dc=org
+member: uid=user10,ou=People,dc=example,dc=org
+member: uid=emailless-user1,ou=People,dc=example,dc=org
+
+dn: cn=ghe-admins,ou=Groups,dc=example,dc=org
+cn: ghe-admins
+objectClass: groupOfNames
+member: uid=admin1,ou=People,dc=example,dc=org
+
+dn: cn=all-admins,ou=Groups,dc=example,dc=org
+cn: all-admins
+objectClass: groupOfNames
+member: cn=ghe-admins,ou=Groups,dc=example,dc=org
+member: uid=admin1,ou=People,dc=example,dc=org
+
+dn: cn=n-member-group10,ou=Groups,dc=example,dc=org
+cn: n-member-group10
+objectClass: groupOfNames
+member: uid=user1,ou=People,dc=example,dc=org
+member: uid=user2,ou=People,dc=example,dc=org
+member: uid=user3,ou=People,dc=example,dc=org
+member: uid=user4,ou=People,dc=example,dc=org
+member: uid=user5,ou=People,dc=example,dc=org
+member: uid=user6,ou=People,dc=example,dc=org
+member: uid=user7,ou=People,dc=example,dc=org
+member: uid=user8,ou=People,dc=example,dc=org
+member: uid=user9,ou=People,dc=example,dc=org
+member: uid=user10,ou=People,dc=example,dc=org
+
+dn: cn=nested-group1,ou=Groups,dc=example,dc=org
+cn: nested-group1
+objectClass: groupOfNames
+member: uid=user1,ou=People,dc=example,dc=org
+member: uid=user2,ou=People,dc=example,dc=org
+member: uid=user3,ou=People,dc=example,dc=org
+member: uid=user4,ou=People,dc=example,dc=org
+member: uid=user5,ou=People,dc=example,dc=org
+
+dn: cn=nested-group2,ou=Groups,dc=example,dc=org
+cn: nested-group2
+objectClass: groupOfNames
+member: uid=user6,ou=People,dc=example,dc=org
+member: uid=user7,ou=People,dc=example,dc=org
+member: uid=user8,ou=People,dc=example,dc=org
+member: uid=user9,ou=People,dc=example,dc=org
+member: uid=user10,ou=People,dc=example,dc=org
+
+dn: cn=nested-groups,ou=Groups,dc=example,dc=org
+cn: nested-groups
+objectClass: groupOfNames
+member: cn=nested-group1,ou=Groups,dc=example,dc=org
+member: cn=nested-group2,ou=Groups,dc=example,dc=org
+
+dn: cn=n-member-nested-group1,ou=Groups,dc=example,dc=org
+cn: n-member-nested-group1
+objectClass: groupOfNames
+member: cn=nested-group1,ou=Groups,dc=example,dc=org
+
+dn: cn=deeply-nested-group0.0.0,ou=Groups,dc=example,dc=org
+cn: deeply-nested-group0.0.0
+objectClass: groupOfNames
+member: uid=user1,ou=People,dc=example,dc=org
+member: uid=user2,ou=People,dc=example,dc=org
+member: uid=user3,ou=People,dc=example,dc=org
+member: uid=user4,ou=People,dc=example,dc=org
+member: uid=user5,ou=People,dc=example,dc=org
+
+dn: cn=deeply-nested-group0.0.1,ou=Groups,dc=example,dc=org
+cn: deeply-nested-group0.0.1
+objectClass: groupOfNames
+member: uid=user6,ou=People,dc=example,dc=org
+member: uid=user7,ou=People,dc=example,dc=org
+member: uid=user8,ou=People,dc=example,dc=org
+member: uid=user9,ou=People,dc=example,dc=org
+member: uid=user10,ou=People,dc=example,dc=org
+
+dn: cn=deeply-nested-group0.0,ou=Groups,dc=example,dc=org
+cn: deeply-nested-group0.0
+objectClass: groupOfNames
+member: cn=deeply-nested-group0.0.0,ou=Groups,dc=example,dc=org
+member: cn=deeply-nested-group0.0.1,ou=Groups,dc=example,dc=org
+
+dn: cn=deeply-nested-group0,ou=Groups,dc=example,dc=org
+cn: deeply-nested-group0
+objectClass: groupOfNames
+member: cn=deeply-nested-group0.0,ou=Groups,dc=example,dc=org
+
+dn: cn=deeply-nested-groups,ou=Groups,dc=example,dc=org
+cn: deeply-nested-groups
+objectClass: groupOfNames
+member: cn=deeply-nested-group0,ou=Groups,dc=example,dc=org
+
+dn: cn=n-depth-nested-group1,ou=Groups,dc=example,dc=org
+cn: n-depth-nested-group1
+objectClass: groupOfNames
+member: cn=nested-group1,ou=Groups,dc=example,dc=org
+
+dn: cn=n-depth-nested-group2,ou=Groups,dc=example,dc=org
+cn: n-depth-nested-group2
+objectClass: groupOfNames
+member: cn=n-depth-nested-group1,ou=Groups,dc=example,dc=org
+
+dn: cn=n-depth-nested-group3,ou=Groups,dc=example,dc=org
+cn: n-depth-nested-group3
+objectClass: groupOfNames
+member: cn=n-depth-nested-group2,ou=Groups,dc=example,dc=org
+
+dn: cn=n-depth-nested-group4,ou=Groups,dc=example,dc=org
+cn: n-depth-nested-group4
+objectClass: groupOfNames
+member: cn=n-depth-nested-group3,ou=Groups,dc=example,dc=org
+
+dn: cn=n-depth-nested-group5,ou=Groups,dc=example,dc=org
+cn: n-depth-nested-group5
+objectClass: groupOfNames
+member: cn=n-depth-nested-group4,ou=Groups,dc=example,dc=org
+
+dn: cn=n-depth-nested-group6,ou=Groups,dc=example,dc=org
+cn: n-depth-nested-group6
+objectClass: groupOfNames
+member: cn=n-depth-nested-group5,ou=Groups,dc=example,dc=org
+
+dn: cn=n-depth-nested-group7,ou=Groups,dc=example,dc=org
+cn: n-depth-nested-group7
+objectClass: groupOfNames
+member: cn=n-depth-nested-group6,ou=Groups,dc=example,dc=org
+
+dn: cn=n-depth-nested-group8,ou=Groups,dc=example,dc=org
+cn: n-depth-nested-group8
+objectClass: groupOfNames
+member: cn=n-depth-nested-group7,ou=Groups,dc=example,dc=org
+
+dn: cn=n-depth-nested-group9,ou=Groups,dc=example,dc=org
+cn: n-depth-nested-group9
+objectClass: groupOfNames
+member: cn=n-depth-nested-group8,ou=Groups,dc=example,dc=org
+
+dn: cn=head-group,ou=Groups,dc=example,dc=org
+cn: head-group
+objectClass: groupOfNames
+member: cn=tail-group,ou=Groups,dc=example,dc=org
+member: uid=user1,ou=People,dc=example,dc=org
+member: uid=user2,ou=People,dc=example,dc=org
+member: uid=user3,ou=People,dc=example,dc=org
+member: uid=user4,ou=People,dc=example,dc=org
+member: uid=user5,ou=People,dc=example,dc=org
+
+dn: cn=tail-group,ou=Groups,dc=example,dc=org
+cn: tail-group
+objectClass: groupOfNames
+member: cn=head-group,ou=Groups,dc=example,dc=org
+member: uid=user6,ou=People,dc=example,dc=org
+member: uid=user7,ou=People,dc=example,dc=org
+member: uid=user8,ou=People,dc=example,dc=org
+member: uid=user9,ou=People,dc=example,dc=org
+member: uid=user10,ou=People,dc=example,dc=org
+
+dn: cn=recursively-nested-groups,ou=Groups,dc=example,dc=org
+cn: recursively-nested-groups
+objectClass: groupOfNames
+member: cn=head-group,ou=Groups,dc=example,dc=org
+member: cn=tail-group,ou=Groups,dc=example,dc=org
+
+# posixGroup
+
+dn: cn=posix-group1,ou=Groups,dc=example,dc=org
+cn: posix-group1
+objectClass: posixGroup
+gidNumber: 1001
+memberUid: user1
+memberUid: user2
+memberUid: user3
+memberUid: user4
+memberUid: user5
+
+# missing members
+
+dn: cn=missing-users,ou=Groups,dc=example,dc=org
+cn: missing-users
+objectClass: groupOfNames
+member: uid=user1,ou=People,dc=example,dc=org
+member: uid=user2,ou=People,dc=example,dc=org
+member: uid=nonexistent-user,ou=People,dc=example,dc=org
diff --git a/test/fixtures/openldap/memberof.ldif b/test/fixtures/openldap/memberof.ldif
deleted file mode 100644
index dac7c6b5..00000000
--- a/test/fixtures/openldap/memberof.ldif
+++ /dev/null
@@ -1,33 +0,0 @@
-dn: cn=module,cn=config
-cn: module
-objectClass: olcModuleList
-objectClass: top
-olcModulePath: /usr/lib/ldap
-olcModuleLoad: memberof.la
-
-dn: olcOverlay={0}memberof,olcDatabase={1}hdb,cn=config
-objectClass: olcConfig
-objectClass: olcMemberOf
-objectClass: olcOverlayConfig
-objectClass: top
-olcOverlay: memberof
-olcMemberOfDangling: ignore
-olcMemberOfRefInt: TRUE
-olcMemberOfGroupOC: groupOfNames
-olcMemberOfMemberAD: member
-olcMemberOfMemberOfAD: memberOf
-
-dn: cn=module,cn=config
-cn: module
-objectclass: olcModuleList
-objectclass: top
-olcmoduleload: refint.la
-olcmodulepath: /usr/lib/ldap
-
-dn: olcOverlay={1}refint,olcDatabase={1}hdb,cn=config
-objectClass: olcConfig
-objectClass: olcOverlayConfig
-objectClass: olcRefintConfig
-objectClass: top
-olcOverlay: {1}refint
-olcRefintAttribute: memberof member manager owner
diff --git a/test/fixtures/openldap/slapd.conf.ldif b/test/fixtures/openldap/slapd.conf.ldif
deleted file mode 100644
index 77a6af09..00000000
--- a/test/fixtures/openldap/slapd.conf.ldif
+++ /dev/null
@@ -1,67 +0,0 @@
-dn: cn=config
-objectClass: olcGlobal
-cn: config
-olcPidFile: /var/run/slapd/slapd.pid
-olcArgsFile: /var/run/slapd/slapd.args
-olcLogLevel: -1
-olcToolThreads: 1
-
-dn: olcDatabase={-1}frontend,cn=config
-objectClass: olcDatabaseConfig
-objectClass: olcFrontendConfig
-olcDatabase: {-1}frontend
-olcSizeLimit: 500
-olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
-olcAccess: {1}to dn.exact="" by * read
-olcAccess: {2}to dn.base="cn=Subschema" by * read
-
-dn: olcDatabase=config,cn=config
-objectClass: olcDatabaseConfig
-olcDatabase: config
-olcAccess: to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
-
-dn: cn=schema,cn=config
-objectClass: olcSchemaConfig
-cn: schema
-
-include: file:///etc/ldap/schema/core.ldif
-include: file:///etc/ldap/schema/cosine.ldif
-include: file:///etc/ldap/schema/nis.ldif
-include: file:///etc/ldap/schema/inetorgperson.ldif
-
-dn: cn=module{0},cn=config
-objectClass: olcModuleList
-cn: module{0}
-olcModulePath: /usr/lib/ldap
-olcModuleLoad: back_hdb
-
-dn: olcBackend=hdb,cn=config
-objectClass: olcBackendConfig
-olcBackend: hdb
-
-dn: olcDatabase=hdb,cn=config
-objectClass: olcDatabaseConfig
-objectClass: olcHdbConfig
-olcDatabase: hdb
-olcDbCheckpoint: 512 30
-olcDbConfig: set_cachesize 1 0 0
-olcDbConfig: set_lk_max_objects 1500
-olcDbConfig: set_lk_max_locks 1500
-olcDbConfig: set_lk_max_lockers 1500
-olcLastMod: TRUE
-olcSuffix: dc=rubyldap,dc=com
-olcDbDirectory: /var/lib/ldap
-olcRootDN: cn=admin,dc=rubyldap,dc=com
-# admin's password: "passworD1"
-olcRootPW: {SHA}LFSkM9eegU6j3PeGG7UuHrT/KZM=
-olcDbIndex: objectClass eq
-olcAccess: to attrs=userPassword,shadowLastChange
-  by self write
-  by anonymous auth
-  by dn="cn=admin,dc=rubyldap,dc=com" write
-  by * none
-olcAccess: to dn.base="" by * read
-olcAccess: to *
-  by self write
-  by dn="cn=admin,dc=rubyldap,dc=com" write
-  by * read
diff --git a/test/fixtures/seed.ldif b/test/fixtures/seed.ldif
deleted file mode 100644
index 3ad3e293..00000000
--- a/test/fixtures/seed.ldif
+++ /dev/null
@@ -1,374 +0,0 @@
-dn: ou=People,dc=rubyldap,dc=com
-objectClass: top
-objectClass: organizationalUnit
-ou: People
-
-dn: ou=Groups,dc=rubyldap,dc=com
-objectClass: top
-objectClass: organizationalUnit
-ou: Groups
-
-# Directory Superuser
-dn: uid=admin,dc=rubyldap,dc=com
-uid: admin
-cn: system administrator
-sn: administrator
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-displayName: Directory Superuser
-userPassword: passworD1
-
-# Users 1-10
-
-dn: uid=user1,ou=People,dc=rubyldap,dc=com
-uid: user1
-cn: user1
-sn: user1
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: user1@rubyldap.com
-
-dn: uid=user2,ou=People,dc=rubyldap,dc=com
-uid: user2
-cn: user2
-sn: user2
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: user2@rubyldap.com
-
-dn: uid=user3,ou=People,dc=rubyldap,dc=com
-uid: user3
-cn: user3
-sn: user3
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: user3@rubyldap.com
-
-dn: uid=user4,ou=People,dc=rubyldap,dc=com
-uid: user4
-cn: user4
-sn: user4
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: user4@rubyldap.com
-
-dn: uid=user5,ou=People,dc=rubyldap,dc=com
-uid: user5
-cn: user5
-sn: user5
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: user5@rubyldap.com
-
-dn: uid=user6,ou=People,dc=rubyldap,dc=com
-uid: user6
-cn: user6
-sn: user6
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: user6@rubyldap.com
-
-dn: uid=user7,ou=People,dc=rubyldap,dc=com
-uid: user7
-cn: user7
-sn: user7
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: user7@rubyldap.com
-
-dn: uid=user8,ou=People,dc=rubyldap,dc=com
-uid: user8
-cn: user8
-sn: user8
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: user8@rubyldap.com
-
-dn: uid=user9,ou=People,dc=rubyldap,dc=com
-uid: user9
-cn: user9
-sn: user9
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: user9@rubyldap.com
-
-dn: uid=user10,ou=People,dc=rubyldap,dc=com
-uid: user10
-cn: user10
-sn: user10
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: user10@rubyldap.com
-
-# Emailless User
-
-dn: uid=emailless-user1,ou=People,dc=rubyldap,dc=com
-uid: emailless-user1
-cn: emailless-user1
-sn: emailless-user1
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-
-# Groupless User
-
-dn: uid=groupless-user1,ou=People,dc=rubyldap,dc=com
-uid: groupless-user1
-cn: groupless-user1
-sn: groupless-user1
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-
-# Admin User
-
-dn: uid=admin1,ou=People,dc=rubyldap,dc=com
-uid: admin1
-cn: admin1
-sn: admin1
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: inetOrgPerson
-userPassword: passworD1
-mail: admin1@rubyldap.com
-
-# Groups
-
-dn: cn=ghe-users,ou=Groups,dc=rubyldap,dc=com
-cn: ghe-users
-objectClass: groupOfNames
-member: uid=user1,ou=People,dc=rubyldap,dc=com
-member: uid=emailless-user1,ou=People,dc=rubyldap,dc=com
-
-dn: cn=all-users,ou=Groups,dc=rubyldap,dc=com
-cn: all-users
-objectClass: groupOfNames
-member: cn=ghe-users,ou=Groups,dc=rubyldap,dc=com
-member: uid=user1,ou=People,dc=rubyldap,dc=com
-member: uid=user2,ou=People,dc=rubyldap,dc=com
-member: uid=user3,ou=People,dc=rubyldap,dc=com
-member: uid=user4,ou=People,dc=rubyldap,dc=com
-member: uid=user5,ou=People,dc=rubyldap,dc=com
-member: uid=user6,ou=People,dc=rubyldap,dc=com
-member: uid=user7,ou=People,dc=rubyldap,dc=com
-member: uid=user8,ou=People,dc=rubyldap,dc=com
-member: uid=user9,ou=People,dc=rubyldap,dc=com
-member: uid=user10,ou=People,dc=rubyldap,dc=com
-member: uid=emailless-user1,ou=People,dc=rubyldap,dc=com
-
-dn: cn=ghe-admins,ou=Groups,dc=rubyldap,dc=com
-cn: ghe-admins
-objectClass: groupOfNames
-member: uid=admin1,ou=People,dc=rubyldap,dc=com
-
-dn: cn=all-admins,ou=Groups,dc=rubyldap,dc=com
-cn: all-admins
-objectClass: groupOfNames
-member: cn=ghe-admins,ou=Groups,dc=rubyldap,dc=com
-member: uid=admin1,ou=People,dc=rubyldap,dc=com
-
-dn: cn=n-member-group10,ou=Groups,dc=rubyldap,dc=com
-cn: n-member-group10
-objectClass: groupOfNames
-member: uid=user1,ou=People,dc=rubyldap,dc=com
-member: uid=user2,ou=People,dc=rubyldap,dc=com
-member: uid=user3,ou=People,dc=rubyldap,dc=com
-member: uid=user4,ou=People,dc=rubyldap,dc=com
-member: uid=user5,ou=People,dc=rubyldap,dc=com
-member: uid=user6,ou=People,dc=rubyldap,dc=com
-member: uid=user7,ou=People,dc=rubyldap,dc=com
-member: uid=user8,ou=People,dc=rubyldap,dc=com
-member: uid=user9,ou=People,dc=rubyldap,dc=com
-member: uid=user10,ou=People,dc=rubyldap,dc=com
-
-dn: cn=nested-group1,ou=Groups,dc=rubyldap,dc=com
-cn: nested-group1
-objectClass: groupOfNames
-member: uid=user1,ou=People,dc=rubyldap,dc=com
-member: uid=user2,ou=People,dc=rubyldap,dc=com
-member: uid=user3,ou=People,dc=rubyldap,dc=com
-member: uid=user4,ou=People,dc=rubyldap,dc=com
-member: uid=user5,ou=People,dc=rubyldap,dc=com
-
-dn: cn=nested-group2,ou=Groups,dc=rubyldap,dc=com
-cn: nested-group2
-objectClass: groupOfNames
-member: uid=user6,ou=People,dc=rubyldap,dc=com
-member: uid=user7,ou=People,dc=rubyldap,dc=com
-member: uid=user8,ou=People,dc=rubyldap,dc=com
-member: uid=user9,ou=People,dc=rubyldap,dc=com
-member: uid=user10,ou=People,dc=rubyldap,dc=com
-
-dn: cn=nested-groups,ou=Groups,dc=rubyldap,dc=com
-cn: nested-groups
-objectClass: groupOfNames
-member: cn=nested-group1,ou=Groups,dc=rubyldap,dc=com
-member: cn=nested-group2,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=n-member-nested-group1,ou=Groups,dc=rubyldap,dc=com
-cn: n-member-nested-group1
-objectClass: groupOfNames
-member: cn=nested-group1,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=deeply-nested-group0.0.0,ou=Groups,dc=rubyldap,dc=com
-cn: deeply-nested-group0.0.0
-objectClass: groupOfNames
-member: uid=user1,ou=People,dc=rubyldap,dc=com
-member: uid=user2,ou=People,dc=rubyldap,dc=com
-member: uid=user3,ou=People,dc=rubyldap,dc=com
-member: uid=user4,ou=People,dc=rubyldap,dc=com
-member: uid=user5,ou=People,dc=rubyldap,dc=com
-
-dn: cn=deeply-nested-group0.0.1,ou=Groups,dc=rubyldap,dc=com
-cn: deeply-nested-group0.0.1
-objectClass: groupOfNames
-member: uid=user6,ou=People,dc=rubyldap,dc=com
-member: uid=user7,ou=People,dc=rubyldap,dc=com
-member: uid=user8,ou=People,dc=rubyldap,dc=com
-member: uid=user9,ou=People,dc=rubyldap,dc=com
-member: uid=user10,ou=People,dc=rubyldap,dc=com
-
-dn: cn=deeply-nested-group0.0,ou=Groups,dc=rubyldap,dc=com
-cn: deeply-nested-group0.0
-objectClass: groupOfNames
-member: cn=deeply-nested-group0.0.0,ou=Groups,dc=rubyldap,dc=com
-member: cn=deeply-nested-group0.0.1,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=deeply-nested-group0,ou=Groups,dc=rubyldap,dc=com
-cn: deeply-nested-group0
-objectClass: groupOfNames
-member: cn=deeply-nested-group0.0,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=deeply-nested-groups,ou=Groups,dc=rubyldap,dc=com
-cn: deeply-nested-groups
-objectClass: groupOfNames
-member: cn=deeply-nested-group0,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=n-depth-nested-group1,ou=Groups,dc=rubyldap,dc=com
-cn: n-depth-nested-group1
-objectClass: groupOfNames
-member: cn=nested-group1,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=n-depth-nested-group2,ou=Groups,dc=rubyldap,dc=com
-cn: n-depth-nested-group2
-objectClass: groupOfNames
-member: cn=n-depth-nested-group1,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=n-depth-nested-group3,ou=Groups,dc=rubyldap,dc=com
-cn: n-depth-nested-group3
-objectClass: groupOfNames
-member: cn=n-depth-nested-group2,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=n-depth-nested-group4,ou=Groups,dc=rubyldap,dc=com
-cn: n-depth-nested-group4
-objectClass: groupOfNames
-member: cn=n-depth-nested-group3,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=n-depth-nested-group5,ou=Groups,dc=rubyldap,dc=com
-cn: n-depth-nested-group5
-objectClass: groupOfNames
-member: cn=n-depth-nested-group4,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=n-depth-nested-group6,ou=Groups,dc=rubyldap,dc=com
-cn: n-depth-nested-group6
-objectClass: groupOfNames
-member: cn=n-depth-nested-group5,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=n-depth-nested-group7,ou=Groups,dc=rubyldap,dc=com
-cn: n-depth-nested-group7
-objectClass: groupOfNames
-member: cn=n-depth-nested-group6,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=n-depth-nested-group8,ou=Groups,dc=rubyldap,dc=com
-cn: n-depth-nested-group8
-objectClass: groupOfNames
-member: cn=n-depth-nested-group7,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=n-depth-nested-group9,ou=Groups,dc=rubyldap,dc=com
-cn: n-depth-nested-group9
-objectClass: groupOfNames
-member: cn=n-depth-nested-group8,ou=Groups,dc=rubyldap,dc=com
-
-dn: cn=head-group,ou=Groups,dc=rubyldap,dc=com
-cn: head-group
-objectClass: groupOfNames
-member: cn=tail-group,ou=Groups,dc=rubyldap,dc=com
-member: uid=user1,ou=People,dc=rubyldap,dc=com
-member: uid=user2,ou=People,dc=rubyldap,dc=com
-member: uid=user3,ou=People,dc=rubyldap,dc=com
-member: uid=user4,ou=People,dc=rubyldap,dc=com
-member: uid=user5,ou=People,dc=rubyldap,dc=com
-
-dn: cn=tail-group,ou=Groups,dc=rubyldap,dc=com
-cn: tail-group
-objectClass: groupOfNames
-member: cn=head-group,ou=Groups,dc=rubyldap,dc=com
-member: uid=user6,ou=People,dc=rubyldap,dc=com
-member: uid=user7,ou=People,dc=rubyldap,dc=com
-member: uid=user8,ou=People,dc=rubyldap,dc=com
-member: uid=user9,ou=People,dc=rubyldap,dc=com
-member: uid=user10,ou=People,dc=rubyldap,dc=com
-
-dn: cn=recursively-nested-groups,ou=Groups,dc=rubyldap,dc=com
-cn: recursively-nested-groups
-objectClass: groupOfNames
-member: cn=head-group,ou=Groups,dc=rubyldap,dc=com
-member: cn=tail-group,ou=Groups,dc=rubyldap,dc=com
-
-# posixGroup
-
-dn: cn=posix-group1,ou=Groups,dc=rubyldap,dc=com
-cn: posix-group1
-objectClass: posixGroup
-gidNumber: 1001
-memberUid: user1
-memberUid: user2
-memberUid: user3
-memberUid: user4
-memberUid: user5
-
-# missing members
-
-dn: cn=missing-users,ou=Groups,dc=rubyldap,dc=com
-cn: missing-users
-objectClass: groupOfNames
-member: uid=user1,ou=People,dc=rubyldap,dc=com
-member: uid=user2,ou=People,dc=rubyldap,dc=com
-member: uid=nonexistent-user,ou=People,dc=rubyldap,dc=com
diff --git a/test/integration/test_add.rb b/test/integration/test_add.rb
index dcac6149..108fd93b 100644
--- a/test/integration/test_add.rb
+++ b/test/integration/test_add.rb
@@ -3,9 +3,7 @@
 class TestAddIntegration < LDAPIntegrationTestCase
   def setup
     super
-    @ldap.authenticate "cn=admin,dc=rubyldap,dc=com", "passworD1"
-
-    @dn = "uid=added-user1,ou=People,dc=rubyldap,dc=com"
+    @dn = "uid=added-user1,ou=People,dc=example,dc=org"
   end
 
   def test_add
diff --git a/test/integration/test_ber.rb b/test/integration/test_ber.rb
index 51e93334..3b1ba09b 100644
--- a/test/integration/test_ber.rb
+++ b/test/integration/test_ber.rb
@@ -8,7 +8,7 @@ def test_true_ber_encoding
     attrs = [:dn, :uid, :cn, :mail]
 
     assert types_entry = @ldap.search(
-      base: "dc=rubyldap,dc=com",
+      base: "dc=example,dc=org",
       filter: "(uid=user1)",
       size: 1,
       attributes: attrs,
diff --git a/test/integration/test_bind.rb b/test/integration/test_bind.rb
index bd1281e2..7df263c1 100644
--- a/test/integration/test_bind.rb
+++ b/test/integration/test_bind.rb
@@ -1,13 +1,17 @@
 require_relative '../test_helper'
 
 class TestBindIntegration < LDAPIntegrationTestCase
+
+  INTEGRATION_HOSTNAME = 'ldap.example.org'.freeze
+
   def test_bind_success
     assert @ldap.bind(BIND_CREDS),
            @ldap.get_operation_result.inspect
   end
 
   def test_bind_timeout
-    @ldap.port = 8389
+    @ldap.host = "10.255.255.1" # non-routable IP
+
     error = assert_raise Net::LDAP::Error do
       @ldap.bind BIND_CREDS
     end
@@ -34,6 +38,7 @@ def test_bind_fail
   end
 
   def test_bind_tls_with_cafile
+    @ldap.host = INTEGRATION_HOSTNAME
     @ldap.encryption(
       method:      :start_tls,
       tls_options: TLS_OPTS.merge(ca_file: CA_FILE),
@@ -43,7 +48,7 @@ def test_bind_tls_with_cafile
   end
 
   def test_bind_tls_with_bad_hostname_verify_none_no_ca_passes
-    @ldap.host = '127.0.0.1'
+    @ldap.host = INTEGRATION_HOSTNAME
     @ldap.encryption(
       method:      :start_tls,
       tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE },
@@ -112,7 +117,7 @@ def test_bind_tls_with_bad_hostname_ca_no_opt_merge_fails
   end
 
   def test_bind_tls_with_valid_hostname_default_opts_passes
-    @ldap.host = 'localhost'
+    @ldap.host = INTEGRATION_HOSTNAME
     @ldap.encryption(
       method:      :start_tls,
       tls_options: TLS_OPTS.merge(verify_mode: OpenSSL::SSL::VERIFY_PEER,
@@ -123,7 +128,7 @@ def test_bind_tls_with_valid_hostname_default_opts_passes
   end
 
   def test_bind_tls_with_valid_hostname_just_verify_peer_ca_passes
-    @ldap.host = 'localhost'
+    @ldap.host = INTEGRATION_HOSTNAME
     @ldap.encryption(
       method:      :start_tls,
       tls_options: { verify_mode: OpenSSL::SSL::VERIFY_PEER,
@@ -146,13 +151,9 @@ def test_bind_tls_with_bogus_hostname_system_ca_fails
     )
   end
 
-  # The following depend on /etc/hosts hacking.
-  # We can do that on CI, but it's less than cool on people's dev boxes
   def test_bind_tls_with_multiple_hosts
-    omit_unless ENV['TRAVIS'] == 'true'
-
     @ldap.host = nil
-    @ldap.hosts = [['ldap01.example.com', 389], ['ldap02.example.com', 389]]
+    @ldap.hosts = [[INTEGRATION_HOSTNAME, 389], [INTEGRATION_HOSTNAME, 389]]
     @ldap.encryption(
       method:      :start_tls,
       tls_options: TLS_OPTS.merge(verify_mode: OpenSSL::SSL::VERIFY_PEER,
@@ -163,8 +164,6 @@ def test_bind_tls_with_multiple_hosts
   end
 
   def test_bind_tls_with_multiple_bogus_hosts
-    omit_unless ENV['TRAVIS'] == 'true'
-
     @ldap.host = nil
     @ldap.hosts = [['127.0.0.1', 389], ['bogus.example.com', 389]]
     @ldap.encryption(
@@ -181,8 +180,6 @@ def test_bind_tls_with_multiple_bogus_hosts
   end
 
   def test_bind_tls_with_multiple_bogus_hosts_no_verification
-    omit_unless ENV['TRAVIS'] == 'true'
-
     @ldap.host = nil
     @ldap.hosts = [['127.0.0.1', 389], ['bogus.example.com', 389]]
     @ldap.encryption(
@@ -194,8 +191,6 @@ def test_bind_tls_with_multiple_bogus_hosts_no_verification
   end
 
   def test_bind_tls_with_multiple_bogus_hosts_ca_check_only_fails
-    omit_unless ENV['TRAVIS'] == 'true'
-
     @ldap.host = nil
     @ldap.hosts = [['127.0.0.1', 389], ['bogus.example.com', 389]]
     @ldap.encryption(
@@ -213,8 +208,10 @@ def test_bind_tls_with_multiple_bogus_hosts_ca_check_only_fails
   # This test is CI-only because we can't add the fixture CA
   # to the system CA store on people's dev boxes.
   def test_bind_tls_valid_hostname_system_ca_on_travis_passes
+    omit "not sure how to install custom CA cert in travis"
     omit_unless ENV['TRAVIS'] == 'true'
 
+    @ldap.host = INTEGRATION_HOSTNAME
     @ldap.encryption(
       method: :start_tls,
       tls_options: { verify_mode: OpenSSL::SSL::VERIFY_PEER },
@@ -222,23 +219,4 @@ def test_bind_tls_valid_hostname_system_ca_on_travis_passes
     assert @ldap.bind(BIND_CREDS),
            @ldap.get_operation_result.inspect
   end
-
-  # Inverse of the above! Don't run this on Travis, only on Vagrant.
-  # Since Vagrant's hypervisor *won't* have the CA in the system
-  # x509 store, we can assume validation will fail
-  def test_bind_tls_valid_hostname_system_on_vagrant_fails
-    omit_if ENV['TRAVIS'] == 'true'
-
-    @ldap.encryption(
-      method: :start_tls,
-      tls_options: { verify_mode: OpenSSL::SSL::VERIFY_PEER },
-    )
-    error = assert_raise Net::LDAP::Error do
-      @ldap.bind BIND_CREDS
-    end
-    assert_equal(
-      "SSL_connect returned=1 errno=0 state=error: certificate verify failed",
-      error.message,
-    )
-  end
 end
diff --git a/test/integration/test_delete.rb b/test/integration/test_delete.rb
index 0cca32a9..cdd01366 100644
--- a/test/integration/test_delete.rb
+++ b/test/integration/test_delete.rb
@@ -3,9 +3,7 @@
 class TestDeleteIntegration < LDAPIntegrationTestCase
   def setup
     super
-    @ldap.authenticate "cn=admin,dc=rubyldap,dc=com", "passworD1"
-
-    @dn = "uid=delete-user1,ou=People,dc=rubyldap,dc=com"
+    @dn = "uid=delete-user1,ou=People,dc=example,dc=org"
 
     attrs = {
       objectclass: %w(top inetOrgPerson organizationalPerson person),
diff --git a/test/integration/test_open.rb b/test/integration/test_open.rb
index a7ac09da..9ce36d72 100644
--- a/test/integration/test_open.rb
+++ b/test/integration/test_open.rb
@@ -4,8 +4,8 @@ class TestBindIntegration < LDAPIntegrationTestCase
   def test_binds_without_open
     events = @service.subscribe "bind.net_ldap_connection"
 
-    @ldap.search(filter: "uid=user1", base: "ou=People,dc=rubyldap,dc=com", ignore_server_caps: true)
-    @ldap.search(filter: "uid=user1", base: "ou=People,dc=rubyldap,dc=com", ignore_server_caps: true)
+    @ldap.search(filter: "uid=user1", base: "ou=People,dc=example,dc=org", ignore_server_caps: true)
+    @ldap.search(filter: "uid=user1", base: "ou=People,dc=example,dc=org", ignore_server_caps: true)
 
     assert_equal 2, events.size
   end
@@ -14,8 +14,8 @@ def test_binds_with_open
     events = @service.subscribe "bind.net_ldap_connection"
 
     @ldap.open do
-      @ldap.search(filter: "uid=user1", base: "ou=People,dc=rubyldap,dc=com", ignore_server_caps: true)
-      @ldap.search(filter: "uid=user1", base: "ou=People,dc=rubyldap,dc=com", ignore_server_caps: true)
+      @ldap.search(filter: "uid=user1", base: "ou=People,dc=example,dc=org", ignore_server_caps: true)
+      @ldap.search(filter: "uid=user1", base: "ou=People,dc=example,dc=org", ignore_server_caps: true)
     end
 
     assert_equal 1, events.size
@@ -29,9 +29,9 @@ def test_nested_search_without_open
     entries = []
     nested_entry = nil
 
-    @ldap.search(filter: "(|(uid=user1)(uid=user2))", base: "ou=People,dc=rubyldap,dc=com") do |entry|
+    @ldap.search(filter: "(|(uid=user1)(uid=user2))", base: "ou=People,dc=example,dc=org") do |entry|
       entries << entry.uid.first
-      nested_entry ||= @ldap.search(filter: "uid=user3", base: "ou=People,dc=rubyldap,dc=com").first
+      nested_entry ||= @ldap.search(filter: "uid=user3", base: "ou=People,dc=example,dc=org").first
     end
 
     assert_equal "user3", nested_entry.uid.first
@@ -43,9 +43,9 @@ def test_nested_search_with_open
     nested_entry = nil
 
     @ldap.open do
-      @ldap.search(filter: "(|(uid=user1)(uid=user2))", base: "ou=People,dc=rubyldap,dc=com") do |entry|
+      @ldap.search(filter: "(|(uid=user1)(uid=user2))", base: "ou=People,dc=example,dc=org") do |entry|
         entries << entry.uid.first
-        nested_entry ||= @ldap.search(filter: "uid=user3", base: "ou=People,dc=rubyldap,dc=com").first
+        nested_entry ||= @ldap.search(filter: "uid=user3", base: "ou=People,dc=example,dc=org").first
       end
     end
 
@@ -57,7 +57,7 @@ def test_nested_add_with_open
     entries = []
     nested_entry = nil
 
-    dn = "uid=nested-open-added-user1,ou=People,dc=rubyldap,dc=com"
+    dn = "uid=nested-open-added-user1,ou=People,dc=example,dc=org"
     attrs = {
       objectclass: %w(top inetOrgPerson organizationalPerson person),
       uid:  "nested-open-added-user1",
@@ -66,11 +66,10 @@ def test_nested_add_with_open
       mail: "nested-open-added-user1@rubyldap.com",
     }
 
-    @ldap.authenticate "cn=admin,dc=rubyldap,dc=com", "passworD1"
     @ldap.delete dn: dn
 
     @ldap.open do
-      @ldap.search(filter: "(|(uid=user1)(uid=user2))", base: "ou=People,dc=rubyldap,dc=com") do |entry|
+      @ldap.search(filter: "(|(uid=user1)(uid=user2))", base: "ou=People,dc=example,dc=org") do |entry|
         entries << entry.uid.first
 
         nested_entry ||= begin
diff --git a/test/integration/test_password_modify.rb b/test/integration/test_password_modify.rb
index ed8d4f5b..8c4d8593 100644
--- a/test/integration/test_password_modify.rb
+++ b/test/integration/test_password_modify.rb
@@ -3,10 +3,10 @@
 class TestPasswordModifyIntegration < LDAPIntegrationTestCase
   def setup
     super
-    @admin_account = {dn: 'cn=admin,dc=rubyldap,dc=com', password: 'passworD1', method: :simple}
+    @admin_account = {dn: 'cn=admin,dc=example,dc=org', password: 'admin', method: :simple}
     @ldap.authenticate @admin_account[:dn], @admin_account[:password]
 
-    @dn = 'uid=modify-password-user1,ou=People,dc=rubyldap,dc=com'
+    @dn = 'uid=modify-password-user1,ou=People,dc=example,dc=org'
 
     attrs = {
       objectclass: %w(top inetOrgPerson organizationalPerson person),
@@ -14,7 +14,7 @@ def setup
       cn: 'modify-password-user1',
       sn: 'modify-password-user1',
       mail: 'modify-password-user1@rubyldap.com',
-      userPassword: 'passworD1',
+      userPassword: 'admin',
     }
     unless @ldap.search(base: @dn, scope: Net::LDAP::SearchScope_BaseObject)
       assert @ldap.add(dn: @dn, attributes: attrs), @ldap.get_operation_result.inspect
@@ -24,20 +24,20 @@ def setup
     @auth = {
       method: :simple,
       username: @dn,
-      password: 'passworD1',
+      password: 'admin',
     }
   end
 
   def test_password_modify
     assert @ldap.password_modify(dn: @dn,
                                  auth: @auth,
-                                 old_password: 'passworD1',
+                                 old_password: 'admin',
                                  new_password: 'passworD2')
 
     assert @ldap.get_operation_result.extended_response.nil?,
       'Should not have generated a new password'
 
-    refute @ldap.bind(username: @dn, password: 'passworD1', method: :simple),
+    refute @ldap.bind(username: @dn, password: 'admin', method: :simple),
       'Old password should no longer be valid'
 
     assert @ldap.bind(username: @dn, password: 'passworD2', method: :simple),
@@ -47,13 +47,13 @@ def test_password_modify
   def test_password_modify_generate
     assert @ldap.password_modify(dn: @dn,
                                  auth: @auth,
-                                 old_password: 'passworD1')
+                                 old_password: 'admin')
 
     generated_password = @ldap.get_operation_result.extended_response[0][0]
 
     assert generated_password, 'Should have generated a password'
 
-    refute @ldap.bind(username: @dn, password: 'passworD1', method: :simple),
+    refute @ldap.bind(username: @dn, password: 'admin', method: :simple),
       'Old password should no longer be valid'
 
     assert @ldap.bind(username: @dn, password: generated_password, method: :simple),
@@ -68,7 +68,7 @@ def test_password_modify_generate_no_old_password
 
     assert generated_password, 'Should have generated a password'
 
-    refute @ldap.bind(username: @dn, password: 'passworD1', method: :simple),
+    refute @ldap.bind(username: @dn, password: 'admin', method: :simple),
       'Old password should no longer be valid'
 
     assert @ldap.bind(username: @dn, password: generated_password, method: :simple),
@@ -80,7 +80,7 @@ def test_password_modify_overwrite_old_password
                                  auth: @admin_account,
                                  new_password: 'passworD3')
 
-    refute @ldap.bind(username: @dn, password: 'passworD1', method: :simple),
+    refute @ldap.bind(username: @dn, password: 'admin', method: :simple),
       'Old password should no longer be valid'
 
     assert @ldap.bind(username: @dn, password: 'passworD3', method: :simple),
diff --git a/test/integration/test_return_codes.rb b/test/integration/test_return_codes.rb
index 0e381a0a..13cb594a 100644
--- a/test/integration/test_return_codes.rb
+++ b/test/integration/test_return_codes.rb
@@ -5,7 +5,7 @@
 
 class TestReturnCodeIntegration < LDAPIntegrationTestCase
   def test_operations_error
-    refute @ldap.search(filter: "cn=operationsError", base: "ou=Retcodes,dc=rubyldap,dc=com")
+    refute @ldap.search(filter: "cn=operationsError", base: "ou=Retcodes,dc=example,dc=org")
     assert result = @ldap.get_operation_result
 
     assert_equal Net::LDAP::ResultCodeOperationsError, result.code
@@ -13,7 +13,7 @@ def test_operations_error
   end
 
   def test_protocol_error
-    refute @ldap.search(filter: "cn=protocolError", base: "ou=Retcodes,dc=rubyldap,dc=com")
+    refute @ldap.search(filter: "cn=protocolError", base: "ou=Retcodes,dc=example,dc=org")
     assert result = @ldap.get_operation_result
 
     assert_equal Net::LDAP::ResultCodeProtocolError, result.code
@@ -21,7 +21,7 @@ def test_protocol_error
   end
 
   def test_time_limit_exceeded
-    assert @ldap.search(filter: "cn=timeLimitExceeded", base: "ou=Retcodes,dc=rubyldap,dc=com")
+    assert @ldap.search(filter: "cn=timeLimitExceeded", base: "ou=Retcodes,dc=example,dc=org")
     assert result = @ldap.get_operation_result
 
     assert_equal Net::LDAP::ResultCodeTimeLimitExceeded, result.code
@@ -29,7 +29,7 @@ def test_time_limit_exceeded
   end
 
   def test_size_limit_exceeded
-    assert @ldap.search(filter: "cn=sizeLimitExceeded", base: "ou=Retcodes,dc=rubyldap,dc=com")
+    assert @ldap.search(filter: "cn=sizeLimitExceeded", base: "ou=Retcodes,dc=example,dc=org")
     assert result = @ldap.get_operation_result
 
     assert_equal Net::LDAP::ResultCodeSizeLimitExceeded, result.code
diff --git a/test/integration/test_search.rb b/test/integration/test_search.rb
index 96f9ff42..1f562c22 100644
--- a/test/integration/test_search.rb
+++ b/test/integration/test_search.rb
@@ -4,7 +4,7 @@ class TestSearchIntegration < LDAPIntegrationTestCase
   def test_search
     entries = []
 
-    result = @ldap.search(base: "dc=rubyldap,dc=com") do |entry|
+    result = @ldap.search(base: "dc=example,dc=org") do |entry|
       assert_kind_of Net::LDAP::Entry, entry
       entries << entry
     end
@@ -16,7 +16,7 @@ def test_search
   def test_search_without_result
     entries = []
 
-    result = @ldap.search(base: "dc=rubyldap,dc=com", return_result: false) do |entry|
+    result = @ldap.search(base: "dc=example,dc=org", return_result: false) do |entry|
       assert_kind_of Net::LDAP::Entry, entry
       entries << entry
     end
@@ -26,24 +26,24 @@ def test_search_without_result
   end
 
   def test_search_filter_string
-    entries = @ldap.search(base: "dc=rubyldap,dc=com", filter: "(uid=user1)")
+    entries = @ldap.search(base: "dc=example,dc=org", filter: "(uid=user1)")
     assert_equal 1, entries.size
   end
 
   def test_search_filter_object
     filter = Net::LDAP::Filter.eq("uid", "user1") | Net::LDAP::Filter.eq("uid", "user2")
-    entries = @ldap.search(base: "dc=rubyldap,dc=com", filter: filter)
+    entries = @ldap.search(base: "dc=example,dc=org", filter: filter)
     assert_equal 2, entries.size
   end
 
   def test_search_constrained_attributes
-    entry = @ldap.search(base: "uid=user1,ou=People,dc=rubyldap,dc=com", attributes: ["cn", "sn"]).first
+    entry = @ldap.search(base: "uid=user1,ou=People,dc=example,dc=org", attributes: ["cn", "sn"]).first
     assert_equal [:cn, :dn, :sn], entry.attribute_names.sort  # :dn is always included
     assert_empty entry[:mail]
   end
 
   def test_search_attributes_only
-    entry = @ldap.search(base: "uid=user1,ou=People,dc=rubyldap,dc=com", attributes_only: true).first
+    entry = @ldap.search(base: "uid=user1,ou=People,dc=example,dc=org", attributes_only: true).first
 
     assert_empty entry[:cn], "unexpected attribute value: #{entry[:cn]}"
   end
@@ -52,7 +52,7 @@ def test_search_timeout
     entries = []
     events = @service.subscribe "search.net_ldap_connection"
 
-    result = @ldap.search(base: "dc=rubyldap,dc=com", time: 5) do |entry|
+    result = @ldap.search(base: "dc=example,dc=org", time: 5) do |entry|
       assert_kind_of Net::LDAP::Entry, entry
       entries << entry
     end
@@ -66,7 +66,7 @@ def test_search_timeout
   def test_search_with_size
     entries = []
 
-    result = @ldap.search(base: "dc=rubyldap,dc=com", size: 1) do |entry|
+    result = @ldap.search(base: "dc=example,dc=org", size: 1) do |entry|
       assert_kind_of Net::LDAP::Entry, entry
       entries << entry
     end
diff --git a/test/support/vm/openldap/README.md b/test/support/vm/openldap/README.md
deleted file mode 100644
index f79f4dc6..00000000
--- a/test/support/vm/openldap/README.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# Local OpenLDAP Integration Testing
-
-Set up a [Vagrant](http://www.vagrantup.com/) VM to run integration
-tests against OpenLDAP locally. *NOTE*: To support some of the SSL tests,
-Vagrant forwards localhost port 9389 to VM host port 9389. The port mapping
-goes away when you run `vagrant destroy`.
-
-## Install Vagrant
-
-*NOTE*: The Vagrant gem (`gem install vagrant`) is
-[no longer supported](https://www.vagrantup.com/docs/installation/). If you've
-previously installed it, run `gem uninstall vagrant`. If you're an rbenv
-user, you probably want to follow that up with `rbenv rehash; hash -r`.
-
-If you use Homebrew on macOS:
-``` bash
-$ brew update
-$ brew cask install virtualbox
-$ brew cask install vagrant
-$ brew cask install vagrant-manager
-$ vagrant plugin install vagrant-vbguest
-```
-
-Installing Vagrant and virtualbox on other operating systems is left
-as an exercise to the reader. Note the `vagrant-vbguest` plugin is required
-to update the VirtualBox guest extensions in the guest VM image.
-
-## Run the tests
-
-``` bash
-# start VM (from the correct directory)
-$ cd test/support/vm/openldap/
-$ vagrant up
-
-# get the IP address of the VM
-$ ip=$(vagrant ssh -- "ifconfig eth1 | grep -o -E '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -n1")
-
-# change back to root project directory
-$ cd ../../../..
-
-# set the TCP port for testing
-$ export INTEGRATION_PORT=9389
-
-# run all tests, including integration tests
-$ time INTEGRATION=openldap INTEGRATION_HOST=$ip bundle exec rake
-
-# run a specific integration test file
-$ time INTEGRATION=openldap INTEGRATION_HOST=$ip bundle exec ruby test/integration/test_search.rb
-
-# run integration tests by default
-$ export INTEGRATION=openldap
-$ export INTEGRATION_HOST=$ip
-
-# now run tests without having to set ENV variables
-$ time bundle exec rake
-
-# Once you're all done
-$ cd test/support/vm/openldap
-$ vagrant destroy
-```
-
-If at any point your VM appears to have broken itself, `vagrant destroy`
-from the `test/support/vm/openldap` directory will blow it away. You can
-then do `vagrant up` and start over.
diff --git a/test/support/vm/openldap/Vagrantfile b/test/support/vm/openldap/Vagrantfile
deleted file mode 100644
index 1f375e76..00000000
--- a/test/support/vm/openldap/Vagrantfile
+++ /dev/null
@@ -1,34 +0,0 @@
-# -*- mode: ruby -*-
-# vi: set ft=ruby :
-
-# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
-VAGRANTFILE_API_VERSION = "2"
-
-Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
-  config.vm.hostname = "rubyldap.com"
-
-  config.vm.box = "hashicorp/precise64"
-
-  config.vm.network "private_network", type: :dhcp
-  config.vm.network "forwarded_port", guest: 389, host: 9389
-
-  config.ssh.forward_agent = true
-
-  config.vm.provision "shell", inline: "apt-get update; exec env /vagrant_data/script/install-openldap"
-
-  config.vm.synced_folder "../../../..", "/vagrant_data"
-
-  config.vm.provider "vmware_fusion" do |vb, override|
-    override.vm.box = "hashicorp/precise64"
-    vb.memory = 4596
-    vb.vmx["displayname"] = "integration tests vm"
-    vb.vmx["numvcpus"] = "2"
-  end
-
-  config.vm.provider "virtualbox" do |vb, override|
-    vb.memory = 4096
-    vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"]
-    vb.customize ["modifyvm", :id, "--chipset", "ich9"]
-    vb.customize ["modifyvm", :id, "--vram", "16"]
-  end
-end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 0a976be4..d2c2c155 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -14,14 +14,14 @@
     if File.exist?("/etc/ssl/certs/cacert.pem")
       "/etc/ssl/certs/cacert.pem"
     else
-      File.expand_path("fixtures/ca/cacert.pem", File.dirname(__FILE__))
+      File.expand_path("fixtures/ca/docker-ca.pem", File.dirname(__FILE__))
     end
   end
 
 BIND_CREDS = {
   method:   :simple,
-  username: "uid=user1,ou=People,dc=rubyldap,dc=com",
-  password: "passworD1",
+  username: "cn=admin,dc=example,dc=org",
+  password: "admin",
 }.freeze
 
 TLS_OPTS = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.merge({}).freeze
@@ -65,10 +65,9 @@ def setup
     @ldap = Net::LDAP.new \
       host:           ENV.fetch('INTEGRATION_HOST', 'localhost'),
       port:           ENV.fetch('INTEGRATION_PORT', 389),
-      admin_user:     'uid=admin,dc=rubyldap,dc=com',
-      admin_password: 'passworD1',
-      search_domains: %w(dc=rubyldap,dc=com),
+      search_domains: %w(dc=example,dc=org),
       uid:            'uid',
       instrumentation_service: @service
+    @ldap.authenticate "cn=admin,dc=example,dc=org", "admin"
   end
 end