diff --git a/examples/.gitignore b/examples/.gitignore
new file mode 100644
index 0000000..9f4c740
--- /dev/null
+++ b/examples/.gitignore
@@ -0,0 +1 @@
+db/
\ No newline at end of file
diff --git a/examples/httpd-ldap/README.md b/examples/httpd-ldap/README.md
new file mode 100644
index 0000000..4e7fd2d
--- /dev/null
+++ b/examples/httpd-ldap/README.md
@@ -0,0 +1,27 @@
+# Example: httpd + ldap
+
+This Example shows how to use ska with httpd and ldap using docker.
+
+## Prepare setup
+
+1. Start system using `docker-compose up -d`
+1. Visit http://localhost
+1. Login using one of the following credentials:
+
+|Username|Password|Type|
+|---|---|---|
+|rainbow|password|admin|
+|proceme|password|user|
+
+If something goes wrong, check the log using:
+```
+docker logs -f httpd-ldap_ska_1
+```
+
+## Using ska
+
+1. Login using the admin account `rainbow`.
+1. Connect to the docker container using: `docker exec -it httpd-ldap_ska-php_1 /bin/ash`
+1. Execute `/ska/scripts/ldap_update.php`. This will add the `admin` group and the `keys-sync` user
+1. Add the server `test.example.com` at http://localhost/servers#add
+1. Ska should be able to connet to the system and update its authorized_keys file. You can verify this by checking whether there is an `Synced successfully` next to the server.
diff --git a/examples/httpd-ldap/docker-compose.yml b/examples/httpd-ldap/docker-compose.yml
new file mode 100644
index 0000000..4e708a4
--- /dev/null
+++ b/examples/httpd-ldap/docker-compose.yml
@@ -0,0 +1,71 @@
+version: '2.2'
+services:
+ test:
+ image: alpine:3.8
+ command: /bin/ash -c "(id keys-sync || adduser -h /var/local/keys-sync -S -D -s /bin/sh keys-sync) && chmod 711 /var/local/keys-sync && cp /key /var/local/keys-sync/keys-sync && chown keys-sync:nogroup /var/local/keys-sync/keys-sync && chmod 644 /var/local/keys-sync/keys-sync && apk add openssh && ssh-keygen -A && sed -i -e '/#StrictModes/ s/.*/StrictModes yes/' /etc/ssh/sshd_config && sed -i -e '/AuthorizedKeysFile/ s/.*/AuthorizedKeysFile \/var\/local\/keys-sync\/%u/' /etc/ssh/sshd_config && passwd keys-sync -d test && /usr/sbin/sshd -D"
+ restart: always
+ expose:
+ - "22"
+ depends_on:
+ - ska-php
+ volumes:
+ - ../shared/config-ldap/keys-sync.pub:/key:ro
+ networks:
+ net:
+ aliases:
+ - test.example.com
+
+ mail:
+ image: mwader/postfix-relay
+ restart: always
+ environment:
+ - POSTFIX_myhostname=ska.example.de
+ - POSTFIX_mynetworks=0.0.0.0/0
+ expose:
+ - "25"
+ networks:
+ - net
+
+ ska-db:
+ image: mariadb
+ restart: always
+ environment:
+ - MYSQL_ROOT_PASSWORD=root-password
+ - MYSQL_DATABASE=ska-db
+ - MYSQL_USER=ska-user
+ - MYSQL_PASSWORD=password
+ volumes:
+ - ./db:/var/lib/mysql:rw
+ networks:
+ - net
+
+ ska-php:
+ image: alpine:3.8
+ command: /bin/ash -c "mkdir -p /var/log/keys /run/php/ && (id -u keys-sync 2> /dev/null || adduser --system --disabled-password keys-sync) && chown keys-sync:nogroup /ska/config/keys-sync && apk add php php-fpm ssmtp openssh php7-json php7-ldap php7-mbstring php7-mysqli php7-ssh2 php7-posix php7-pcntl && sed -i -e '/listen =/ s/= .*/= 0.0.0.0:9000/' /etc/php7/php-fpm.d/www.conf && crond && /ska/scripts/syncd.php --user keys-sync && php-fpm7 -F"
+ restart: always
+ depends_on:
+ - ska-db
+ - mail
+ volumes:
+ - ../../:/ska/:ro
+ - ../shared/config-ldap/:/ska/config/:rw
+ - ../shared/ssmtp.conf:/etc/ssmtp/ssmtp.conf:ro
+ - ../shared/cron/:/var/spool/cron/crontabs/:rw
+ networks:
+ - net
+
+ ska:
+ image: httpd:alpine
+ restart: always
+ ports:
+ - "80:80"
+ depends_on:
+ - ska-php
+ volumes:
+ - ../../:/ska/:ro
+ - ./httpd.conf:/usr/local/apache2/conf/httpd.conf:ro
+ networks:
+ - net
+
+networks:
+ net:
diff --git a/examples/httpd-ldap/httpd.conf b/examples/httpd-ldap/httpd.conf
new file mode 100644
index 0000000..92fdfca
--- /dev/null
+++ b/examples/httpd-ldap/httpd.conf
@@ -0,0 +1,136 @@
+LoadModule mpm_event_module modules/mod_mpm_event.so
+LoadModule authn_file_module modules/mod_authn_file.so
+LoadModule authn_core_module modules/mod_authn_core.so
+LoadModule authz_host_module modules/mod_authz_host.so
+LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
+LoadModule authz_user_module modules/mod_authz_user.so
+LoadModule authz_core_module modules/mod_authz_core.so
+LoadModule access_compat_module modules/mod_access_compat.so
+LoadModule auth_basic_module modules/mod_auth_basic.so
+LoadModule reqtimeout_module modules/mod_reqtimeout.so
+LoadModule filter_module modules/mod_filter.so
+LoadModule mime_module modules/mod_mime.so
+LoadModule log_config_module modules/mod_log_config.so
+LoadModule env_module modules/mod_env.so
+LoadModule headers_module modules/mod_headers.so
+LoadModule setenvif_module modules/mod_setenvif.so
+LoadModule version_module modules/mod_version.so
+LoadModule unixd_module modules/mod_unixd.so
+LoadModule status_module modules/mod_status.so
+LoadModule autoindex_module modules/mod_autoindex.so
+LoadModule dir_module modules/mod_dir.so
+LoadModule alias_module modules/mod_alias.so
+
+LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
+LoadModule ldap_module modules/mod_ldap.so
+LoadModule proxy_module modules/mod_proxy.so
+LoadModule proxy_html_module modules/mod_proxy_html.so
+LoadModule proxy_connect_module modules/mod_proxy_connect.so
+LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
+LoadModule proxy_http_module modules/mod_proxy_http.so
+LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
+LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
+LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
+LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so
+LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
+LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
+LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
+LoadModule proxy_express_module modules/mod_proxy_express.so
+LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so
+LoadModule proxy_http2_module modules/mod_proxy_http2.so
+LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
+LoadModule watchdog_module modules/mod_watchdog.so
+
+
+
+ User daemon
+ Group daemon
+
+
+
+ DirectoryIndex index.html
+
+
+
+ LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+ LogFormat "%h %l %u %t \"%r\" %>s %b" common
+
+
+ LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
+
+
+ CustomLog /proc/self/fd/1 common
+
+
+
+ ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
+
+
+
+ RequestHeader unset Proxy early
+
+
+
+ TypesConfig conf/mime.types
+ AddType application/x-compress .Z
+ AddType application/x-gzip .gz .tgz
+
+
+
+ Include conf/extra/proxy-html.conf
+
+
+
+ SSLRandomSeed startup builtin
+ SSLRandomSeed connect builtin
+
+
+
+ ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://ska-php:9000/ska/public_html/$1
+ SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
+
+
+
+
+ AllowOverride none
+ Require all denied
+
+
+
+ AllowOverride None
+ Options None
+ Require all granted
+
+
+
+ AuthType Basic
+ AuthName "SSH Key Authority"
+ AuthBasicProvider ldap
+
+ AuthLDAPBindDN "uid=rainbow,ou=users,dc=test,dc=itmettke,dc=de"
+ AuthLDAPBindPassword "password"
+ AuthLDAPURL "ldap://ldap-test.itmettke.de:389/ou=users,dc=test,dc=itmettke,dc=de?uid?sub?(&(objectClass=person))" STARTTLS
+
+ Require valid-user
+ AllowOverride none
+ DirectoryIndex init.php
+ FallbackResource /init.php
+ Order allow,deny
+ Allow from all
+
+
+
+ Require all denied
+
+
+
+Listen 80
+ServerAdmin admin@example.com
+ServerRoot "/usr/local/apache2"
+DocumentRoot "/ska/public_html"
+
+ErrorLog /proc/self/fd/2
+LogLevel warn
+
+LDAPVerifyServerCert off
+AllowEncodedSlashes NoDecode
diff --git a/examples/shared/config-ldap/config.ini b/examples/shared/config-ldap/config.ini
new file mode 100644
index 0000000..40080a3
--- /dev/null
+++ b/examples/shared/config-ldap/config.ini
@@ -0,0 +1,151 @@
+; SSH Key Authority config file
+[web]
+enabled = 1
+baseurl = https://ska.example.com
+logo = /logo-header-opera.png
+; footer may contain HTML. Literal & " < and > should be escaped as &
+; " < $gt;
+footer = 'Developed by Opera Software.'
+
+[general]
+; Use timeout --version to find out the current version
+; used on e.g. debian
+; timeout_util = GNU coreutils
+; used on e.g. alpine
+timeout_util = BusyBox
+
+[security]
+; It is important that SKA is able to verify that it has connected to the
+; server that it expected to connect to (otherwise it could be tricked into
+; syncing the wrong keys to a server). The simplest way to accomplish this is
+; through SSH host key verification. Setting either of the 2 options below to
+; '0' can weaken the protection that SSH host key verification provides.
+
+; Determine who can reset a server's SSH host key in SKA:
+; 0: Allow server admins to reset the SSH host key for servers that they
+; administer
+; 1: Full SKA admin access is required to reset a server's host key
+host_key_reset_restriction = 1
+
+; Determine what happens if multiple servers have the same SSH host key:
+; 0: Allow sync to proceed
+; 1: Abort sync of affected servers and report an error
+; It is not recommended to leave this set to '0' indefinitely
+host_key_collision_protection = 1
+
+
+; Hostname verification is a supplement to SSH host key verification for
+; making sure that the sync process has connected to the server that it
+; expected to.
+
+; Determine how hostname verification is performed:
+; 0: Do not perform hostname verification
+; 1: Compare with the result of `hostname -f`
+; 2: Compare with /var/local/keys-sync/.hostnames, fall back to `hostname -f`
+; if the file does not exist
+; 3: Compare with /var/local/keys-sync/.hostnames, abort sync if the file
+; does not exist
+; The last option provides the most solid verification, as a server will only
+; be synced to if it has been explicitly allowed on the server itself.
+hostname_verification = 0
+
+[defaults]
+; This setting will cause new servers to always have a managed account called
+; "root" and for that account to be automatically added into the
+; "root-accounts" group:
+;
+; account_groups[root] = "root-accounts"
+;
+; Any number of these can be specified
+account_groups[root] = "accounts-root"
+
+[email]
+enabled = 1
+; The mail address that outgoing mails will be sent from
+from_address = ska@example.com
+from_name = "SSH Key Authority system"
+; Where to mail security notifications to
+report_address = reports@example.com
+report_name = "SSH Key Authority reports"
+; Where users should contact for help
+admin_address = admin@example.com
+admin_name = "SSH Key Authority administrators"
+; You can use the reroute directive to redirect all outgoing mail to a single
+; mail address - typically for temporary testing purposes
+;reroute = test@example.com
+
+[database]
+; Connection details to the MySQL database
+hostname = ska-db
+port = 3306
+username = ska-user
+password = password
+database = ska-db
+
+[ldap]
+; Address to connect to LDAP server
+host = ldap://ldap-test.itmettke.de:389
+; Use StartTLS for connection security (recommended if using ldap:// instead
+; of ldaps:// above)
+starttls = 1
+; LDAP subtree containing USER entries
+dn_user = "ou=users,dc=test,dc=itmettke,dc=de"
+; LDAP subtree containing GROUP entries
+dn_group = "ou=groups,dc=test,dc=itmettke,dc=de"
+; Set to 1 if the LDAP library should process referrals. In most cases this
+; is not needed, and for AD servers it can cause errors when querying the
+; whole tree.
+follow_referrals = 0
+
+; Leave bind_dn empty if binding is not required
+bind_dn = "uid=rainbow,ou=users,dc=test,dc=itmettke,dc=de"
+bind_password = "password"
+
+; User attributes
+user_id = uid
+user_name = cn
+user_email = mail
+;user_superior = superioremployee
+
+; If inactive users exist in your LDAP directory, filter with the following
+; settings:
+; Field to filter on:
+;user_active = organizationalstatus
+; Use *one* of user_active_true or user_active_false
+; user_active_true means user is active if the user_active field equals its
+; value
+;user_active_true = 'current'
+; user_active_false means user is active if the user_active field does not
+; equal its value
+;user_active_false = 'former'
+
+; Group membership attributes. Examples below are for typical setups:
+;
+; POSIX groups
+; group_member = memberUid
+; group_member_value = uid
+;
+; Group-of-names groups
+; group_member = member
+; group_member_value = dn
+;
+; Attribute of group where members are stored
+group_member = member
+; User attribute to compare with
+group_member_value = dn
+
+; Members of admin_group are given full admin access to SSH Key Authority web
+; interface
+admin_group_cn = admin
+
+[inventory]
+; SSH Key Authority will read the contents of the file /etc/uuid (if it
+; exists) when syncing with a server. If a value is found, it can be used as a
+; link to an inventory system.
+; %s in the url directive will be replaced with the value found in /etc/uuid
+;url = "https://inventory.example.com/device/%s"
+
+[gpg]
+; SSH Key Authority can GPG sign outgoing emails sent from the
+; email.from_address. To do this it needs to know an appropriate key ID to use
+;key_id = 0123456789ABCDEF0123456789ABCDEF01234567
diff --git a/examples/shared/config-ldap/keys-sync b/examples/shared/config-ldap/keys-sync
new file mode 100644
index 0000000..5ec63cc
--- /dev/null
+++ b/examples/shared/config-ldap/keys-sync
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAqatsYGwteC4X+aIsNThluXZlh9SbdQTB3Zy8EoRcgKSEQdvw
+sn56e3SLCTtLVGYCD7l5bTvjuJIG0VGKGG8ZYiESHQRBqm6t0zWEJMiOC0mUt3xW
+4YJcVFhsk54WhVMWW7Irjx+wk9VbX4OellU0FZSjAs+hSernAOnVoSNXnSaC5hoq
+98QWdlUwI+pOkKfyII4YYcSaPByNA/dx4Hy4cVqIaVIvDf4SiYHnqbCCZbSZcrQD
+W/pLnq6s4e3LvYNaB2BWLlbad8YuJRBRSp9C3thV1EmYIDQdlk6sg0fkFGYi+jWF
+WKatA0u7Krt5Dh3BeeNgFqegfsb3E1P8+gUp6QIDAQABAoIBADdzCIYylGGUXs18
+jIoQFl6YLPJJL0z88waj9GrwyvJX0clcQbtzzj+OhOnNcP7yH3ZYHTDvw6pMPuIl
+jcYSeO8y86J8A6HZbgF6mecTjChwMaQNhK9KVTZTd5h+r8l+r+3juoyZxLFrpuL+
+NtPWoKD05JlEled8V2ZbBTAWRsnahepwwIdVK9kroK/Z/O91YXHxsKkW8tr0BPAR
+mJNFOZnMxKymyXZ05J9pEq+q054nDHdpOcKF6z1dNuVVpPvtPlJ+BfNZqLcQ87/3
+4AiX7hFEyiRQw6v5JXUXH1IkNuD3BpjFMAr5/g1damsWXw+rkeYk5uS44Em46LeU
+hk2J8ykCgYEA1B9eZEI/xpejcXDLTR7NihF2kk3YmiHjnqvVRPV97/JlMw1kmulb
+ga1Y4y7YLv0TT2lWTZ9U5d+aIGTLqDd2fFvUYwAojeibf8TIPxWj47IK1sG7K7/4
+fwtxzuYJ6TmehwKFLMqxW/RN8bxmXZOQyc0vdbWdc30filRpdJfkyMMCgYEAzMQG
+NIc3WObmaNzT1qlC7svba0VWpE7Tve9yUlfQUzqiEPMWKxCxoxiSdjxKh3ZeFaGM
+vb+EvvHryZVwO6Ym8YO3c7Or96/38dlpzR2USPPsE/z7q4Ai7p8s2OnpUdTN+Sbz
+rUvWFZD+aTTzYaPHiknGGE4oTt90ksXhsHKR9+MCgYBZchzIZBMmd7zI0go4K9v5
+82EvUjoazF2CA+07VdVT/79ipqwckngul10a9x7buYWR/9YPhzcyc3Y3YKlr9m81
+Azfswx1WsZYYa28RAtwH4ISniCuXyCxNzhKgbuoQ+WX6gjqL57CgGMVhQNNddCMi
+pS31Ea8iCsno9608J+ymJwKBgAupDgFnwcsaOvy1top+0QTwLuqI5EovAvfJ7uSp
+g39500jLzvNc3ADBoXWCMWxNXUY2EOGtSk3lUNwF2oJLD+So74VzMdPE/YWUL+Yy
+TQNqgIMS4PH/Nf4IqnEfwN2cFK6ffTjdHK/Vtecf0Mw6m15QnSs9KCZ1qxnAkv2N
+SKqpAoGBAKb7H7PEoBlC0SfrdQIoqKcHX62IEVSS/bzeKRgOF8dNGeJkMLJeOzgK
+uAdi8XYReKp6xkMz2KArfR55nkqGmqPHa9czxLcRh0afdccjK4kEgiCA3sGz80Hp
+2r7EBnR6AK5aBTNDnpv2TQdOCTed5QBwHUWUWlD36xDayW/+cehH
+-----END RSA PRIVATE KEY-----
diff --git a/examples/shared/config-ldap/keys-sync.pub b/examples/shared/config-ldap/keys-sync.pub
new file mode 100644
index 0000000..dce6e2a
--- /dev/null
+++ b/examples/shared/config-ldap/keys-sync.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCpq2xgbC14Lhf5oiw1OGW5dmWH1Jt1BMHdnLwShFyApIRB2/Cyfnp7dIsJO0tUZgIPuXltO+O4kgbRUYoYbxliIRIdBEGqbq3TNYQkyI4LSZS3fFbhglxUWGyTnhaFUxZbsiuPH7CT1Vtfg56WVTQVlKMCz6FJ6ucA6dWhI1edJoLmGir3xBZ2VTAj6k6Qp/IgjhhhxJo8HI0D93HgfLhxWohpUi8N/hKJgeepsIJltJlytANb+kuerqzh7cu9g1oHYFYuVtp3xi4lEFFKn0Le2FXUSZggNB2WTqyDR+QUZiL6NYVYpq0DS7squ3kOHcF542AWp6B+xvcTU/z6BSnp root@ska.example.com
diff --git a/examples/shared/cron/root b/examples/shared/cron/root
new file mode 100644
index 0000000..7ca495f
--- /dev/null
+++ b/examples/shared/cron/root
@@ -0,0 +1 @@
+0 1 * * * /ska/scripts/ldap_update.php
diff --git a/examples/shared/ssmtp.conf b/examples/shared/ssmtp.conf
new file mode 100644
index 0000000..7e1ec6b
--- /dev/null
+++ b/examples/shared/ssmtp.conf
@@ -0,0 +1,4 @@
+mailhub=mail
+rewriteDomain=example.com
+hostname="ska"
+FromLineOverride=YES