diff --git a/.dev-config/nginx-https-config.sh b/.dev-config/nginx-https-config.sh
deleted file mode 100755
index 9da3b242bc08318ebb4540cd110a439c8559d4b9..0000000000000000000000000000000000000000
--- a/.dev-config/nginx-https-config.sh
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/bin/bash
-
-# Django usually listens on port 8000 without SSL.
-# Some of our projects however require SSL.
-# Run this script to set up nginx SSL proxy for Django.
-
-
-if [[ "$EUID" != 0 ]]; then
-    echo "Need to be run as root."
-    exit 1
-fi
-
-SITES_AVAILABLE="/etc/nginx/sites-available"
-SITES_ENABLED="/etc/nginx/sites-enabled"
-CONFIG_FILENAME="443-ssl-to-8000"
-
-CERT_PUB="/etc/ssl/certs/ssl-cert-snakeoil.pem"
-CERT_KEY="/etc/ssl/private/ssl-cert-snakeoil.key"
-
-set -e  # die on error
-set -u  # die if some var not set
-
-if [[ ! -d "$SITES_AVAILABLE" ]] || [[ ! -d "$SITES_AVAILABLE" ]]; then
-    echo "Is nginx installed?"
-    exit 1
-fi
-
-if [[ ! -e "$CERT_PUB" ]] || [[ ! -e "$CERT_KEY" ]]; then
-    echo "No snakeoil certs?"
-    exit 1
-fi
-
-echo "Seting up site config..."
-
-sudo cat > "$SITES_AVAILABLE/$CONFIG_FILENAME" << EOF
-
-upstream localhost8000 {
-  server localhost:8000;
-}
-
-server {
-  listen     443;
-  ssl  on;
-
-  allow 127.0.0.1;
-  allow 141.71.113.0/24;
-  deny all;
-
-  ssl_certificate                $CERT_PUB;
-  ssl_certificate_key            $CERT_KEY;
-  ssl_protocols                  TLSv1 TLSv1.1 TLSv1.2;
-  ssl_ciphers                 "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
-
-  location / {
-    proxy_pass        http://localhost8000;
-    proxy_set_header  Host \$host;
-    proxy_set_header  X-Forwarded-For \$remote_addr;
-    proxy_set_header  X-Forwarded-Proto "https";
-    proxy_set_header  REMOTE-USER \$remote_user;
-  }
-}
-
-EOF
-
-set +e  # stop dying on errors now
-
-sudo ln -f -s "$SITES_AVAILABLE/$CONFIG_FILENAME" "$SITES_ENABLED/"
-
-echo "Restarting nginx..."
-
-sudo systemctl restart nginx
-
-if [[ "`systemctl is-active nginx`" == "active" ]]; then
-    echo "http://localhost:8000 with SSL is here: https://localhost"
-else
-    echo "Oops. Seems like nginx is dead now."
-    echo
-    systemctl status nginx | cat
-    echo
-fi
-
-exit
-
-
diff --git a/README.md b/README.md
index 246d02701b7b20534aa2c729238e3bfff115a1e7..274bf800d194c55f7b32176fd692d677ff9ebcb9 100644
--- a/README.md
+++ b/README.md
@@ -14,10 +14,26 @@
 - Add the app into `INSTALLED_APPS`
 - Include the app's `urls.py` into the project `urls.py` `urlpatterns`
 - Add to the project settings
-  - ```python
+  - Development
+    ```python
+    # imports
+    import socket
+    import os
+    # SP
     SP_HOST = "141.71.foo.bar"  # your SP host or IP address
+    SP_PORT = 8000
+    SP_SSL = False
+    SP_FORCE_ENTITY_ID = "auto-{0}-{1}".format(socket.gethostname(), os.path.dirname(os.path.dirname(__file__)))
+    # IDP
     IDP_META_URL = "https://idp-test.it.hs-hannover.de/idp/shibboleth"  # development
-    # IDP_META_URL = "https://idp.hs-hannover.de/idp/shibboleth"  # production
+    # IDP_IGNORE = True  # set to True if you experience problems with the IDP (SSO will NOT work)
+    ```
+  - Production
+    ```python
+    # SP
+    SP_HOST = "141.71.foo.bar"  # your SP host or IP address
+    # IDP
+    IDP_META_URL = "https://idp.hs-hannover.de/idp/shibboleth"  # production
     ```
 - generate a new key pair:
   - create `cert` directory:
@@ -27,15 +43,10 @@
   - `./cert/sp.key` put the private key here
   - `./cert/sp.pem` put the certificate here, signing is optional
 
-#### Development setup
-  - `sudo apt-get install nginx`
-  - run `.dev-config/nginx-https-config.sh`
-    - in case you already have port 443 busy, use your force to solve the issue :)
-
-
 #### Integrating your project into the existing SSO infrastructure
-- **Ask somebody who knows more. Seriously.**
-- **Try on the test IdP before you brick the production!**
+- **Do this only if you want to use SSO. For development it's usually enough to use the dev view instead.**
+- Ask somebody who knows more. Seriously.
+- Try on the test IdP before you brick the production!
 - Grab your meta
   - Run your project.
   - Find meta of your SP (relative path `/saml2/meta` or view name `sso-saml2-meta`)
diff --git a/ssoauth/app_settings/__init__.py b/ssoauth/app_settings/__init__.py
index b00d50eaf9b3853e144669ce5484cbb681f2a2c3..420e5a5b123ae060e35b14c8548ce6713b22e495 100644
--- a/ssoauth/app_settings/__init__.py
+++ b/ssoauth/app_settings/__init__.py
@@ -18,8 +18,7 @@ for setting_name in [k for k in globals().keys() if k.isupper()]:
 # checks
 
 assert SP_HOST and SP_PORT, "Need SP_HOST and SP_PORT configured in settings."
-assert not SP_HOST.startswith(("127.", "::1", "localhost",)), "Too many localhosts around. Need a real hostname or IP address."
-assert not SP_HOST.lower().startswith(("http:", "https:",)), "Need host name without a protocol."
+assert not SP_HOST.lower().startswith(("http:", "https:",)), "Need host name without protocol and port."
 
 
 # helpers
diff --git a/ssoauth/app_settings/defaults.py b/ssoauth/app_settings/defaults.py
index b62f97dd1e56a64262b61f140b73e3e6ac858fda..3af24256c4147287b08e241f16105e98d7621f16 100644
--- a/ssoauth/app_settings/defaults.py
+++ b/ssoauth/app_settings/defaults.py
@@ -13,19 +13,28 @@ Settings you may want to change:
 """
 
 # host and port, not what Django thinks, but what nginx serves
-SP_HOST = None  # e.g. "141.71.113.1"
+SP_HOST = None  # e.g. "141.71.foo.bar", for development can use "localhost" and set FORCE_ENTITY_ID
 SP_PORT = 443
+SP_SSL = True
 
 IDP_META_URL = "https://idp.hs-hannover.de/idp/shibboleth"  # test is "https://idp-test.it.hs-hannover.de/idp/shibboleth"
 
 SP_KEY = "{project_settings}/cert/sp.key"
 SP_CERT = "{project_settings}/cert/sp.pem"
 
+
 """
-Settings you DON'T want to change (in fact, you want to avoid even thinking about them):
+Settings you might want to change on development (don't change them for production):
 """
 
-IDP_REQUIRED = True  # die on start if cannot find IDP or parse its meta
+# development helpers
+SP_FORCE_ENTITY_ID = None  # do NOT set for production, set to some unique string on development
+IDP_IGNORE = False  # ignore IDP entirely, SSO will not function
+
+
+"""
+Settings you DON'T want to change (in fact, you want to avoid even thinking about them):
+"""
 
 SP_METADATA_LIFETIME_DAYS = 365 * 20
 
diff --git a/ssoauth/apps.py b/ssoauth/apps.py
index bad7353e4dcf70bbe3ae4a4c72bf35d0d072a24a..f9056e179d99191a0ccc14fdabe7978d8d887858 100644
--- a/ssoauth/apps.py
+++ b/ssoauth/apps.py
@@ -1,6 +1,7 @@
 from django.apps import AppConfig
 from django.core import management
 from django.db.models.signals import post_migrate
+from django import conf
 from . import logger
 from . import sso_utils
 from . import app_settings
@@ -12,13 +13,14 @@ class SSOAuthConfig(AppConfig):
     def ready(self, *args, **kwargs):
         super().ready(*args, **kwargs)
         # OneLogin settings stuff
-        try:
-            app_settings.ONELOGIN_SETTINGS = sso_utils.create_onelogin_settings(app_settings.ONELOGIN_SETTINGS_TEMPLATE)
-        except Exception as e:
-            if app_settings.IDP_REQUIRED:
-                raise e
-            else:
-                logger.error("SSO will not work. {ec}: {e}".format(ec=e.__class__.__name__, e=str(e),))
+        if app_settings.IDP_IGNORE:
+            assert conf.settings.DEBUG, "And how should SSO work on production if you ignore the IDP?"
+            logger.info("SSO will not work.")
+        else:
+            try:
+                app_settings.ONELOGIN_SETTINGS = sso_utils.create_onelogin_settings(app_settings.ONELOGIN_SETTINGS_TEMPLATE)
+            except Exception as e:
+                raise RuntimeError("SSO failed to start. {ec}: {e}".format(ec=e.__class__.__name__, e=str(e),))
         # default groups
         post_migrate.connect(self.post_migrate_callback, sender=self)
 
diff --git a/ssoauth/checks.py b/ssoauth/checks.py
index 11798c37d4c1fc10697a52da3b4dcd47a553e9b2..d7155dee6fe7b006844964a1b339a909cb929b46 100644
--- a/ssoauth/checks.py
+++ b/ssoauth/checks.py
@@ -3,6 +3,7 @@ from django.contrib.auth import get_user_model
 from django.db.utils import OperationalError, ProgrammingError
 from django import conf
 from django import urls
+from . import app_settings
 
 
 def _get_abstract_user():
@@ -90,3 +91,14 @@ def session_lifetime(app_configs, **kwargs):
         ))
     return errors
 
+
+@register(Tags.compatibility)
+def production_entity_id(app_configs, **kwargs):
+    errors = list()
+    if not conf.settings.DEBUG and app_settings.SP_FORCE_ENTITY_ID:
+        errors.append(Warning(
+            "You set SP_FORCE_ENTITY_ID. Should better avoid doing so on production.",
+            obj=conf.settings,
+        ))
+    return errors
+
diff --git a/ssoauth/sso_utils.py b/ssoauth/sso_utils.py
index 449936ee89b32f388cbae12db4188e910fc67df4..767947754fb138f9a136fa24d6bf095fe89d048b 100644
--- a/ssoauth/sso_utils.py
+++ b/ssoauth/sso_utils.py
@@ -55,18 +55,22 @@ def get_idp_runtime_info(meta_url):
 
 def create_onelogin_settings(template):
     """ This function is intended to be run only once, on app startup. Raises exceptions. """
+    # get the template
     template = copy(template)
+    # prepare some values
+    protocol = "https" if app_settings.SP_SSL else "http"
+    port_suffix = "" if app_settings.SP_PORT in [80, 443] else ":{0}".format(app_settings.SP_PORT)
+    host = app_settings.SP_HOST
+    host_full = "{protocol}://{host}{port_suffix}".format(**locals())
     # SP settings
-    this_host = "https://{host}".format(host=app_settings.SP_HOST)
-    if app_settings.SP_PORT != 443:
-        this_host += ":{}".format(app_settings.SP_PORT)
-    template["sp"]["entityId"] = this_host + urls.reverse("sso-saml2-meta")
-    template["sp"]["assertionConsumerService"]["url"] = this_host + urls.reverse("sso-saml2-acs")
+    template["sp"]["entityId"] = app_settings.SP_FORCE_ENTITY_ID or (host_full + urls.reverse("sso-saml2-meta"))
+    template["sp"]["assertionConsumerService"]["url"] = host_full + urls.reverse("sso-saml2-acs")
     # IDP settings
     idp_info = get_idp_runtime_info(app_settings.IDP_META_URL)
     template["idp"]["x509certMulti"]["signing"] = idp_info["certificates"]["signing"]
     template["idp"]["x509certMulti"]["encryption"] = idp_info["certificates"]["encryption"]
     template["idp"]["singleSignOnService"]["url"] = idp_info["bindings"]["sso_redirect"]
     template["idp"]["singleLogoutService"]["url"] = idp_info["bindings"]["slo_redirect"]
+    # done
     return OneLogin_Saml2_Settings(settings=template, sp_validation_only=True)
 
diff --git a/ssoauth/views.py b/ssoauth/views.py
index 5f8e1c56faf72cd733f54b5e6a8098bc5873f231..c1006318c1de6f372cd9740273bf2c64e15cb365 100644
--- a/ssoauth/views.py
+++ b/ssoauth/views.py
@@ -31,16 +31,21 @@ ATTRIBUTE_MAPPING = dict(
 class SAMLMixin:
     """ Merges Django runtime info and settings for OneLogin toolkit """
 
+    def __init__(self, *args, **kwargs):
+        if not app_settings.ONELOGIN_SETTINGS:
+            raise exceptions.ImproperlyConfigured("SSO is not configured.")
+        super().__init__(*args, **kwargs)
+
     @staticmethod
     def get_onelogin_request_data(request):
         return {
             # since nginx is in the way, the settings cannot be fetched from the request
-            'https': 'on',  # nginx should do it and django will never have a clue
-            'http_host': app_settings.SP_HOST,  # nginx might change it
-            'server_port': app_settings.SP_PORT,  # nginx will change it
-            'script_name': request.META['PATH_INFO'],
-            'get_data': request.GET.copy(),
-            'post_data': request.POST.copy(),
+            "https": "on" if app_settings.SP_SSL else "off",
+            "http_host": app_settings.SP_HOST,  # nginx might change it
+            "server_port": app_settings.SP_PORT,  # nginx will change it
+            "script_name": request.META["PATH_INFO"],
+            "get_data": request.GET.copy(),
+            "post_data": request.POST.copy(),
         }
 
     @classmethod