diff --git a/Dockerfile b/Dockerfile
index 0037322aa9db2d83bc3fe5913e4a60276808b40f..9084a98717b6c9671de2870f81bdada041efdab7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -9,11 +9,13 @@ ADD netguru /app/netguru
 ADD manage.py /app/manage.py
 ADD shares /app/shares
 ADD templates /app/templates
+ADD counting /app/counting
+ADD agent /app/agent
 ADD test.sh /app/test.sh
 RUN python manage.py collectstatic && \
     chmod ugo+x /app/test.sh
 
 VOLUME /data
 
-CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:80", "netguru.wsgi:application"]
+CMD ["gunicorn", "-w", "1", "--threads", "4", "-b", "0.0.0.0:80", "netguru.wsgi:application"]
 
diff --git a/README.md b/README.md
index 98e37f930da9148717984824b06c931cc6dd8fed..f36d79c2d5267559796862c93b1835033e406753 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,15 @@ To run locally just run:
 docker-compose up -d run_local
 ```
 
+This will expose both ports 80 (for TCP traffic)
+and ports 81 (for metrics).
+
+I expect you to terminate SSL at a reverse proxy.
+Please watch out for generated links, as they will
+invariable link to SSL, because I've got no easy way
+to detect if I've been called with SSL already, or is
+it just a reverse proxy handing over the requests.
+
 # Production
 
 ## Links
@@ -47,6 +56,15 @@ provide it, a reasonably default value is supplied,
 but since it has already been used it isn't safe anymore.
 **CHANGE IT!**
 
+You also need to provide a list of hosts from which
+this Django instance can be accessed. You do that
+by defining an environment variable called 
+ALLOWED_HOSTS and giving a list of hosts separated
+by a comma. If you don't define it, a default 
+value of `*` will be used
+
+**WARNING!!** This is not secure, don't do it!
+
 ### Volumes
 
 The application needs a volume marked at 
@@ -61,7 +79,7 @@ You will just have to forgive me that I failed
 to hook up any loggers for it. Any Python-based
 logger will do, I sincerely recommends
 [seq-log](https://github.com/tintoy/seqlog)
-- full disclosure: I'm a contributor there
+- full disclosure: I'm a [contributor](https://github.com/tintoy/seqlog/blob/master/AUTHORS.rst) there
 
 #### Metrics
 
@@ -82,4 +100,6 @@ I failed to deploy that on your test environment since I'm
 pretty much strapped for time.
 
 BTW: If you're not already doing 
-[tracing](https://opentracing.io/), you should totally consider it.
+[tracing](https://opentracing.io/), 
+you should totally consider it.
+
diff --git a/agent/__init__.py b/agent/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/agent/admin.py b/agent/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e
--- /dev/null
+++ b/agent/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/agent/apps.py b/agent/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..f1442dfc697e0fd52c368c0d1ca30c7464830cb0
--- /dev/null
+++ b/agent/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class AgentConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'agent'
diff --git a/agent/middleware.py b/agent/middleware.py
new file mode 100644
index 0000000000000000000000000000000000000000..b5efb0ed224bf5e503ac6dbac1114d2651862e85
--- /dev/null
+++ b/agent/middleware.py
@@ -0,0 +1,18 @@
+from agent.models import UserAgentStorage
+
+
+class UANotingMiddleware:
+    def __init__(self, get_response):
+        self.get_response = get_response
+
+    def __call__(self, request):
+        response = self.get_response(request)
+        if request.user.is_authenticated:
+            try:
+                ua = UserAgentStorage.objects.get(user=request.user)
+                ua.ua = request.headers.get('User-Agent')
+            except UserAgentStorage.DoesNotExist:
+                ua = UserAgentStorage(user=request.user, ua=request.headers.get('User-Agent'))
+            ua.save()
+
+        return response
diff --git a/agent/migrations/0001_initial.py b/agent/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd5b3093d7d4174fe762ea1056e3bae8f99284c4
--- /dev/null
+++ b/agent/migrations/0001_initial.py
@@ -0,0 +1,25 @@
+# Generated by Django 3.2.6 on 2021-08-26 14:26
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='UserAgentStorage',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('ua', models.TextField(blank=True, null=True, verbose_name='User agent')),
+                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='User')),
+            ],
+        ),
+    ]
diff --git a/agent/migrations/__init__.py b/agent/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/agent/models.py b/agent/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b802420d727948efee28b6269841b72687500cb
--- /dev/null
+++ b/agent/models.py
@@ -0,0 +1,7 @@
+from django.db import models
+
+
+class UserAgentStorage(models.Model):
+    user = models.ForeignKey('auth.User', verbose_name='User', db_index=True,
+                             on_delete=models.CASCADE)
+    ua = models.TextField(verbose_name='User agent', null=True, blank=True)
diff --git a/agent/tests.py b/agent/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/agent/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/agent/views.py b/agent/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..91ea44a218fbd2f408430959283f0419c921093e
--- /dev/null
+++ b/agent/views.py
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
diff --git a/counting/__init__.py b/counting/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/counting/admin.py b/counting/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e
--- /dev/null
+++ b/counting/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/counting/apps.py b/counting/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..7548273266e1495fde848e1feb0f48df524502c2
--- /dev/null
+++ b/counting/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class CountingConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'counting'
diff --git a/counting/migrations/0001_initial.py b/counting/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..8fddbec84a493f17175e52c9a9727ab886450787
--- /dev/null
+++ b/counting/migrations/0001_initial.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.6 on 2021-08-26 14:26
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='StoryOfADay',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('day', models.DateField(verbose_name='Date')),
+                ('links_visited', models.IntegerField(verbose_name='Links visited')),
+                ('files_visited', models.IntegerField(verbose_name='Files visited')),
+            ],
+        ),
+    ]
diff --git a/counting/migrations/__init__.py b/counting/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/counting/models.py b/counting/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a8760c89b0419f88efac3bc16dcd46feee82ddb
--- /dev/null
+++ b/counting/models.py
@@ -0,0 +1,7 @@
+from django.db import models
+
+
+class StoryOfADay(models.Model):
+    day = models.DateField(verbose_name='Date')
+    links_visited = models.IntegerField(verbose_name='Links visited')
+    files_visited = models.IntegerField(verbose_name='Files visited')
diff --git a/counting/tests.py b/counting/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/counting/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/counting/views.py b/counting/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..91ea44a218fbd2f408430959283f0419c921093e
--- /dev/null
+++ b/counting/views.py
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
diff --git a/netguru/settings.py b/netguru/settings.py
index 5f7a8363c856f6b23277102859b2ef9f654aa4a3..ec3f8238648829385c4cc978592afbf2a3704ec9 100644
--- a/netguru/settings.py
+++ b/netguru/settings.py
@@ -1,4 +1,5 @@
 import os
+import logging
 from satella.instrumentation.metrics import getMetric
 from satella.instrumentation.metrics.exporters import PrometheusHTTPExporterThread
 
@@ -12,8 +13,7 @@ SECRET_KEY = os.environ.get('SECRET_KEY', 'r6(!w-%glre916esjft0^lds4u)=fym=v*26$
 
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = 'DEBUG' in os.environ
-
-ALLOWED_HOSTS = ['*']
+ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '*').split(',')
 
 # Application definition
 
@@ -25,6 +25,8 @@ INSTALLED_APPS = [
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'shares.apps.SharesConfig',
+    'agent.apps.AgentConfig',
+    'counting.apps.CountingConfig',
 ]
 
 MIDDLEWARE = [
@@ -37,6 +39,7 @@ MIDDLEWARE = [
     'django.middleware.csrf.CsrfViewMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    'agent.middleware.UANotingMiddleware',
 ]
 
 ROOT_URLCONF = 'netguru.urls'
@@ -115,6 +118,7 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'media')
 FILE_SAVE_LOCATION = '/data'
 
 # Configure tracing
+# =================
 OPENTRACING_TRACE_ALL = True
 
 # Callable that returns an `opentracing.Tracer` implementation.
@@ -125,15 +129,26 @@ OPENTRACING_TRACER_PARAMETERS = {
 }
 
 # Set up metrics
+# ==============
 DJANGO_SATELLA_METRICS = {
     'summary_metric': getMetric('netguru.time.summary', 'summary'),
     'histogram_metric': getMetric('netguru.time.histogram', 'histogram'),
     'status_codes_metric': getMetric('netguru.status_codes', 'counter')
 }
 
-
-
+# Set up metric exporter thread
+# -----------------------------
 phet = PrometheusHTTPExporterThread('0.0.0.0', 81, {'service_name': 'netguru'})
 phet.start()
 
+# Configure logging
+# =================
+
+logger = logging.getLogger(__name__)
+if DEBUG:
+    logging.basicConfig(level=logging.DEBUG)
+    logger.warning('WARNING! You are running in debug mode. Don\'t do it on production!')
+else:
+    logging.basicConfig(level=logging.INFO)
+
 
diff --git a/shares/migrations/0001_initial.py b/shares/migrations/0001_initial.py
index 0c460cbb08b5116838ddbdf1bac6ce2a45201928..0242f0720ce075435b073950bc5ee5b579804448 100644
--- a/shares/migrations/0001_initial.py
+++ b/shares/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 3.2.6 on 2021-08-25 16:46
+# Generated by Django 3.2.6 on 2021-08-26 14:26
 
 import datetime
 from django.conf import settings
@@ -23,7 +23,7 @@ class Migration(migrations.Migration):
                 ('created_on', models.DateTimeField(db_index=True, default=datetime.datetime.now, verbose_name='Created on')),
                 ('pwd_hash', models.CharField(max_length=64, verbose_name='Hashed password salt')),
                 ('resource', models.TextField(verbose_name='Resource')),
-                ('views_count', models.IntegerField(default=0, verbose_name='Amount of displays')),
+                ('used', models.BooleanField(default=False, verbose_name='Has been used?')),
                 ('creator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Creator')),
             ],
         ),
diff --git a/shares/models.py b/shares/models.py
index bfadb68c31a78037dde5fd7e72dc22365c297623..0c6e9f517e91e32adb4c37ec4fe4740eb80dbd17 100644
--- a/shares/models.py
+++ b/shares/models.py
@@ -1,8 +1,12 @@
+import os
 from datetime import datetime
 
 from django.db import models
 
 # Create your models here.
+from satella.coding import silence_excs
+
+from netguru.settings import FILE_SAVE_LOCATION
 
 SHARE_URL = 0
 SHARE_FILE = 1
@@ -14,6 +18,11 @@ SHARE_TYPES = [
 
 
 class Share(models.Model):
+    """
+    A share is a single shared resource.
+
+    It is created on being added and removed upon the reaper task collecting it.
+    """
     creator = models.ForeignKey('auth.User', verbose_name='Creator', on_delete=models.CASCADE)
     share_type = models.IntegerField(choices=SHARE_TYPES, verbose_name='Share type')
     created_on = models.DateTimeField(default=datetime.now, verbose_name='Created on',
@@ -21,4 +30,35 @@ class Share(models.Model):
     pwd_hash = models.CharField(max_length=64, verbose_name='Hashed password salt')
     # this is either an URL or a f'{UUID}.real_file_name' in /data
     resource = models.TextField(verbose_name='Resource')
-    views_count = models.IntegerField(verbose_name='Amount of displays', default=0)
+    used = models.BooleanField(verbose_name='Has been used?', default=False)
+
+    @property
+    def file_name(self) -> str:
+        """
+        Return real file name (as submitted by the user).
+        Must be a SHARE_FILE
+        """
+        assert self.share_type == SHARE_FILE, 'Not a file!'
+        return self.resource.split('.', 1)[1]
+
+    @property
+    def uuid_name(self) -> str:
+        """Return file name. Must be a SHARE_FILE"""
+        assert self.share_type == SHARE_FILE, 'Not a file!'
+        return self.resource.split('.', 1)[0]
+
+    @property
+    def path(self) -> str:
+        """Return path to file"""
+        return os.path.join(FILE_SAVE_LOCATION, self.uuid_name)
+
+    def delete(self, *args, **kwargs):
+        if self.share_type == SHARE_FILE:
+            path = os.path.join(FILE_SAVE_LOCATION, self.uuid_name)
+            # Since we might have already deleted it, but our transaction was rolled
+            # back because of reasons.
+            # This is both EAFP (more Pythonic) and shorter 2 lines than a try ... catch
+            # besides it's a great showcase of my Satella
+            with silence_excs(FileNotFoundError):
+                os.unlink(path)
+        super().delete(*args, **kwargs)
diff --git a/shares/views.py b/shares/views.py
index a82e16fdf6c25bc487306de06cbe7faeb350ddc5..3ed8c745289c4f0f55101f4af592b625d9c11d5b 100644
--- a/shares/views.py
+++ b/shares/views.py
@@ -1,3 +1,4 @@
+import datetime
 import mimetypes
 import typing as tp
 import os
@@ -109,6 +110,10 @@ class PasswordForm(forms.Form):
 
 def view_share(request, share_id: str):
     share = get_object_or_404(Share, id=share_id)
+
+    if share.created_on < datetime.datetime.now() - datetime.timedelta(days=1):
+        raise Http404()
+
     if request.method == 'POST':
         form = PasswordForm(request.POST)
         if form.is_valid():
@@ -120,9 +125,7 @@ def view_share(request, share_id: str):
                     links_visited.runtime(+1)
                     return redirect(share.resource)
                 else:
-                    file_uuid, file_name = share.resource.split('.', 1)
-                    file_loc = os.path.join(FILE_SAVE_LOCATION, file_uuid)
-                    if not os.path.exists(file_loc):
+                    if not os.path.exists(share.path):
                         raise Http404()
 
                     def file_iterator(path: str) -> tp.Iterator[bytes]:
@@ -133,16 +136,16 @@ def view_share(request, share_id: str):
                                 p = f.read(1024)
 
                     # Django will have the UTF-8 mumbo jumbo for us
-                    cd = f'attachment; filename="{file_name}"'
-                    mimetype = mimetypes.guess_type(file_name)[0] or 'application/octet-stream'
+                    cd = f'attachment; filename="{share.file_name}"'
+                    mimetype = mimetypes.guess_type(share.file_name)[0] or 'application/octet-stream'
                     files_visited.runtime(+1)
-                    return StreamingHttpResponse(file_iterator(file_loc),
+                    return StreamingHttpResponse(file_iterator(share.path),
                                                  content_type=mimetype,
                                                  headers={
                                                      'Content-Disposition': cd
                                                  })
             finally:
-                share.views_count += 1
+                share.used = True
                 share.save()
     else:
         form = PasswordForm()