about summary refs log tree commit homepage
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/README2
-rw-r--r--examples/README.unsubscribe40
-rw-r--r--examples/logrotate.conf24
-rw-r--r--examples/public-inbox-config1
-rw-r--r--examples/public-inbox-httpd.socket10
-rw-r--r--examples/public-inbox-httpd@.service32
-rw-r--r--examples/public-inbox-nntpd.socket10
-rw-r--r--examples/public-inbox-nntpd@.service32
-rw-r--r--examples/public-inbox.psgi21
-rw-r--r--examples/unsubscribe-milter.socket10
-rw-r--r--examples/unsubscribe-milter@.service24
-rw-r--r--examples/unsubscribe-psgi.socket11
-rw-r--r--examples/unsubscribe-psgi@.service21
-rw-r--r--examples/unsubscribe.milter134
-rw-r--r--examples/unsubscribe.psgi69
-rw-r--r--examples/varnish-4.vcl68
16 files changed, 502 insertions, 7 deletions
diff --git a/examples/README b/examples/README
index 1244cb2c..1d5dcd34 100644
--- a/examples/README
+++ b/examples/README
@@ -16,4 +16,4 @@ apache2_perl.conf - intended to be the basis of a production config
 Contact
 -------
 Please send any related feedback to public-inbox: meta@public-inbox.org
-Our public-inbox is: git://public-inbox.org/meta
+Our public-inbox is: https://public-inbox.org/meta/
diff --git a/examples/README.unsubscribe b/examples/README.unsubscribe
new file mode 100644
index 00000000..7c41067c
--- /dev/null
+++ b/examples/README.unsubscribe
@@ -0,0 +1,40 @@
+Unsubscribe endpoints for mlmmj users (and possibly Mailman, too)
+
+* examples/unsubscribe.milter filters outgoing messages
+  and appends an HTTPS URL to the List-Unsubscribe header.
+  This List-Unsubscribe header should point to the PSGI
+  described below.
+  Currently, this is only active for a whitelist of test
+  addresses in /etc/unsubscribe-milter.whitelist
+  with one email address per line.
+
+* examples/unsubscribe.psgi is a PSGI which needs to run
+  as the mlmmj user with permission to run mlmmj-unsub.
+  This depends on the PublicInbox::Unsubscribe module
+  which may be extracted from the rest of public-inbox.
+  It is strongly recommended to NOT run the rest of the
+  public-inbox WWW code in the same process as this PSGI.
+  (The public-inbox WWW code will never need write
+   permissions to anything besides stderr).
+
+* Both the .milter and .psgi examples are bundled with
+  systemd service and socket activation examples.
+  AFAIK no other PSGI server besides public-inbox-httpd
+  supports systemd socket activation.
+
+To wire up the milter for postfix, I use the following
+in /etc/postfix/main.cf:
+
+  # Milter configuration
+  milter_default_action = accept
+  milter_protocol = 2
+
+  # other milters may be chained here (e.g. opendkim)
+  # chroot users will need to adjust this path
+  smtpd_milters = local:/var/spool/postfix/unsubscribe/unsubscribe.sock
+
+  # This is not needed for mlmmj since mlmmj uses SMTP:
+  # non_smtpd_milters = local:/var/spool/postfix/unsubscribe/unsubscribe.sock
+
+Copyright (C) 2016 all contributors <meta@public-inbox.org>
+License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
diff --git a/examples/logrotate.conf b/examples/logrotate.conf
new file mode 100644
index 00000000..4ce08843
--- /dev/null
+++ b/examples/logrotate.conf
@@ -0,0 +1,24 @@
+# ==> /etc/logrotate.d/public-inbox <==
+#
+# See the logrotate(8) manpage for more information:
+#    http://linux.die.net/man/8/logrotate
+/var/log/public-inbox/*.log {
+        weekly
+        missingok
+        rotate 52
+        compress
+        delaycompress
+        notifempty
+        sharedscripts
+        dateext
+        # note the lack of the racy "copytruncate" option in this
+        # config.  public-inbox-*d supports the USR1 signal and
+        # we send it as our "lastaction":
+        lastaction
+                # systemd users do not need PID files,
+                # only signal the @1 process since the @2 is short-lived
+                # For systemd users, assuming you use two services
+                systemctl kill -s SIGUSR1 public-inbox-httpd@1.service
+                systemctl kill -s SIGUSR1 public-inbox-nntpd@1.service
+        endscript
+}
diff --git a/examples/public-inbox-config b/examples/public-inbox-config
index 0c1db118..7fcbe0ba 100644
--- a/examples/public-inbox-config
+++ b/examples/public-inbox-config
@@ -10,4 +10,3 @@
         address = meta@public-inbox.org
         mainrepo = /home/pi/meta-main.git
         url = http://example.com/meta
-        atomUrl = http://example.com/meta
diff --git a/examples/public-inbox-httpd.socket b/examples/public-inbox-httpd.socket
new file mode 100644
index 00000000..1a1ed735
--- /dev/null
+++ b/examples/public-inbox-httpd.socket
@@ -0,0 +1,10 @@
+# ==> /etc/systemd/system/public-inbox-httpd.socket <==
+[Unit]
+Description = public-inbox-httpd socket
+
+[Socket]
+ListenStream = 80
+Service = public-inbox-httpd@1.service
+
+[Install]
+WantedBy = sockets.target
diff --git a/examples/public-inbox-httpd@.service b/examples/public-inbox-httpd@.service
new file mode 100644
index 00000000..56117ef0
--- /dev/null
+++ b/examples/public-inbox-httpd@.service
@@ -0,0 +1,32 @@
+# ==> /etc/systemd/system/public-inbox-httpd@.service <==
+# Since SIGUSR2 upgrades do not work under systemd, this service file
+# allows starting two simultaneous services during upgrade time
+# (e.g. public-inbox-httpd@1 public-inbox-httpd@2) with the intention
+# that they take turns running in-between upgrades.  This should
+# allow upgrading without downtime.
+
+[Unit]
+Description = public-inbox PSGI server %i
+Wants = public-inbox-httpd.socket
+After = public-inbox-httpd.socket
+
+[Service]
+Environment = PI_CONFIG=/home/pi/.public-inbox/config \
+PATH=/usr/local/bin:/usr/bin:/bin \
+PERL_INLINE_DIRECTORY=/tmp/.pub-inline
+
+LimitNOFILE = 30000
+ExecStartPre = /bin/mkdir -p -m 1777 /tmp/.pub-inline
+ExecStart = /usr/local/bin/public-inbox-httpd \
+-1 /var/log/public-inbox/httpd.out.log
+StandardError = syslog
+Sockets = public-inbox-httpd.socket
+KillSignal = SIGQUIT
+User = nobody
+Group = nogroup
+ExecReload = /bin/kill -HUP $MAINPID
+TimeoutStopSec = 86400
+KillMode = process
+
+[Install]
+WantedBy = multi-user.target
diff --git a/examples/public-inbox-nntpd.socket b/examples/public-inbox-nntpd.socket
new file mode 100644
index 00000000..eeddf343
--- /dev/null
+++ b/examples/public-inbox-nntpd.socket
@@ -0,0 +1,10 @@
+# ==> /etc/systemd/system/public-inbox-nntpd.socket <==
+[Unit]
+Description = public-inbox-nntpd socket
+
+[Socket]
+ListenStream = 119
+Service = public-inbox-nntpd@1.service
+
+[Install]
+WantedBy = sockets.target
diff --git a/examples/public-inbox-nntpd@.service b/examples/public-inbox-nntpd@.service
new file mode 100644
index 00000000..62202c2f
--- /dev/null
+++ b/examples/public-inbox-nntpd@.service
@@ -0,0 +1,32 @@
+# ==> /etc/systemd/system/public-inbox-nntpd@.service <==
+# Since SIGUSR2 upgrades do not work under systemd, this service file
+# allows starting two simultaneous services during upgrade time
+# (e.g. public-inbox-nntpd@1 public-inbox-nntpd@2) with the intention
+# that they take turns running in-between upgrades.  This should
+# allow upgrading without downtime.
+
+[Unit]
+Description = public-inbox NNTP server %i
+Wants = public-inbox-nntpd.socket
+After = public-inbox-nntpd.socket
+
+[Service]
+Environment = PI_CONFIG=/home/pi/.public-inbox/config \
+PATH=/usr/local/bin:/usr/bin:/bin \
+PERL_INLINE_DIRECTORY=/tmp/.pub-inline
+
+LimitNOFILE = 30000
+ExecStartPre = /bin/mkdir -p -m 1777 /tmp/.pub-inline
+ExecStart = /usr/local/bin/public-inbox-nntpd \
+-1 /var/log/public-inbox/nntpd.out.log
+StandardError = syslog
+Sockets = public-inbox-nntpd.socket
+KillSignal = SIGQUIT
+User = nobody
+Group = nogroup
+ExecReload = /bin/kill -HUP $MAINPID
+TimeoutStopSec = 86400
+KillMode = process
+
+[Install]
+WantedBy = multi-user.target
diff --git a/examples/public-inbox.psgi b/examples/public-inbox.psgi
index 71592a7a..e97f917f 100644
--- a/examples/public-inbox.psgi
+++ b/examples/public-inbox.psgi
@@ -11,10 +11,11 @@ use PublicInbox::WWW;
 PublicInbox::WWW->preload;
 use Plack::Builder;
 my $www = PublicInbox::WWW->new;
+
+# share the public-inbox code itself:
+my $src = $ENV{SRC_GIT_DIR}; # '/path/to/public-inbox.git'
+
 builder {
-        # Chunked middleware conflicts with Starman:
-        # https://github.com/miyagawa/Starman/issues/23
-        # enable 'Chunked';
         eval {
                 enable 'Deflater',
                         content_type => [ qw(
@@ -28,7 +29,7 @@ builder {
 
         # Enable to ensure redirects and Atom feed URLs are generated
         # properly when running behind a reverse proxy server which
-        # sets X-Forwarded-For and X-Forwarded-Proto request headers.
+        # sets the X-Forwarded-Proto request header.
         # See Plack::Middleware::ReverseProxy documentation for details
         eval { enable 'ReverseProxy' };
         $@ and warn
@@ -43,5 +44,15 @@ builder {
         #        format => '%t "%r" %>s %b %D';
 
         enable 'Head';
-        sub { $www->call(@_) };
+        sub {
+                my ($env) = @_;
+                # share public-inbox.git code!
+                if ($src && $env->{PATH_INFO} =~
+                                m!\A/(?:public-inbox(?:\.git)?/)?
+                                ($PublicInbox::GitHTTPBackend::ANY)\z!xo) {
+                        PublicInbox::GitHTTPBackend::serve($env, $src, $1);
+                } else {
+                        $www->call($env);
+                }
+        };
 }
diff --git a/examples/unsubscribe-milter.socket b/examples/unsubscribe-milter.socket
new file mode 100644
index 00000000..bfaa97a1
--- /dev/null
+++ b/examples/unsubscribe-milter.socket
@@ -0,0 +1,10 @@
+# ==> /etc/systemd/system/unsubscribe-milter.socket <==
+[Unit]
+Description = unsubscribe.milter socket
+
+[Socket]
+ListenStream = /var/spool/postfix/unsubscribe/unsubscribe.sock
+Service = unsubscribe-milter@1.service
+
+[Install]
+WantedBy = sockets.target
diff --git a/examples/unsubscribe-milter@.service b/examples/unsubscribe-milter@.service
new file mode 100644
index 00000000..98e3d478
--- /dev/null
+++ b/examples/unsubscribe-milter@.service
@@ -0,0 +1,24 @@
+# ==> /etc/systemd/system/unsubscribe-milter@.service <==
+# The '@' is to allow multiple simultaneous services to start
+# and share the same socket so new code can be cycled in
+# without downtime
+
+[Unit]
+Description = unsubscribe milter %i
+Wants = unsubscribe-milter.socket
+After = unsubscribe-milter.socket
+
+[Service]
+# First 8 bytes is for the key, next 8 bytes is for the IV
+# using Blowfish.  We want as short URLs as possible to avoid
+# copy+paste errors
+# umask 077 && dd if=/dev/urandom bs=16 count=1 of=.unsubscribe.key
+ExecStart = /usr/local/sbin/unsubscribe.milter /home/mlmmj/.unsubscribe.key
+Sockets = unsubscribe-milter.socket
+
+# the corresponding PSGI app needs permissions to modify the
+# mlmmj spool, so we might as well use the same user since
+User = mlmmj
+
+[Install]
+WantedBy = multi-user.target
diff --git a/examples/unsubscribe-psgi.socket b/examples/unsubscribe-psgi.socket
new file mode 100644
index 00000000..e7ab797b
--- /dev/null
+++ b/examples/unsubscribe-psgi.socket
@@ -0,0 +1,11 @@
+# ==> /etc/systemd/system/unsubscribe-psgi.socket <==
+[Unit]
+Description = unsubscribe PSGI socket
+
+[Socket]
+# Forward to the PSGI using nginx or similar
+ListenStream = /run/unsubscribe-psgi.sock
+Service = unsubscribe-psgi@1.service
+
+[Install]
+WantedBy = sockets.target
diff --git a/examples/unsubscribe-psgi@.service b/examples/unsubscribe-psgi@.service
new file mode 100644
index 00000000..acc29e8e
--- /dev/null
+++ b/examples/unsubscribe-psgi@.service
@@ -0,0 +1,21 @@
+# ==> /etc/systemd/system/unsubscribe-psgi@.service <==
+# The '@' is to allow multiple simultaneous services to start
+# and share the same socket so new code can be cycled in
+# without downtime
+
+[Unit]
+Description = unsubscribe PSGI %i
+Wants = unsubscribe-psgi.socket
+After = unsubscribe-psgi.socket
+
+[Service]
+# any PSGI server ought to work,
+# but public-inbox-httpd supports socket activation like unsubscribe.milter
+ExecStart = /usr/local/bin/public-inbox-httpd -W0 /etc/unsubscribe.psgi
+Sockets = unsubscribe-psgi.socket
+# we need to modify the mlmmj spool
+User = mlmmj
+KillMode = process
+
+[Install]
+WantedBy = multi-user.target
diff --git a/examples/unsubscribe.milter b/examples/unsubscribe.milter
new file mode 100644
index 00000000..c245a5b8
--- /dev/null
+++ b/examples/unsubscribe.milter
@@ -0,0 +1,134 @@
+#!/usr/bin/perl -w
+# Copyright (C) 2016 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+use strict;
+use warnings;
+use Sendmail::PMilter qw(:all);
+use IO::Socket;
+use Crypt::CBC;
+use MIME::Base64 qw(encode_base64url);
+
+my $key_file = shift @ARGV or die "Usage: $0 KEY_FILE\n";
+open my $fh, '<', $key_file or die "failed to open $key_file\n";
+my ($key, $iv);
+if (read($fh, $key, 8) != 8 || read($fh, $iv, 8) != 8 ||
+                        read($fh, my $end, 8) != 0) {
+        die "KEY_FILE must be 16 bytes\n";
+}
+
+# these parameters were chosen to generate shorter parameters
+# to reduce the possibility of copy+paste errors
+my $crypt = Crypt::CBC->new(-key => $key,
+                        -iv => $iv,
+                        -header => 'none',
+                        -cipher => 'Blowfish');
+$fh = $iv = $key = undef;
+
+my %cbs;
+$cbs{connect} = sub {
+        my ($ctx) = @_;
+        eval { $ctx->setpriv({ header => {}, envrcpt => {} }) };
+        warn $@ if $@;
+        SMFIS_CONTINUE;
+};
+
+$cbs{envrcpt} = sub {
+        my ($ctx, $addr) = @_;
+        eval {
+                $addr =~ tr!<>!!d;
+                $ctx->getpriv->{envrcpt}->{$addr} = 1;
+        };
+        warn $@ if $@;
+        SMFIS_CONTINUE;
+};
+
+$cbs{header} = sub {
+        my ($ctx, $k, $v) = @_;
+        eval {
+                my $k_ = lc $k;
+                if ($k_ eq 'list-unsubscribe') {
+                        my $header = $ctx->getpriv->{header} ||= {};
+                        my $ary = $header->{$k_} ||= [];
+
+                        # we create placeholders in case there are
+                        # multiple headers of the same name
+                        my $cur = [];
+                        push @$ary, $cur;
+
+                        # This relies on mlmmj convention:
+                        #        $LIST+unsubscribe@$DOMAIN
+                        if ($v =~ /\A<mailto:([^@]+)\+unsubscribe@([^>]+)>\z/) {
+                                @$cur = ($k, $v, $1, $2);
+
+                        # Mailman convention:
+                        #        $LIST-request@$DOMAIN?subject=unsubscribe
+                        } elsif ($v =~ /\A<mailto:([^@]+)-request@
+                                        ([^\?]+)\?subject=unsubscribe>\z/x) {
+                                # @$cur = ($k, $v, $1, $2);
+                        }
+                }
+        };
+        warn $@ if $@;
+        SMFIS_CONTINUE;
+};
+
+# We don't want people unsubscribing archivers:
+sub archive_addr {
+        my ($addr) = @_;
+        return 1 if ($addr =~ /\@m\.gmane\.org\z/);
+        return 1 if ($addr eq 'archive@mail-archive.com');
+        0
+}
+
+$cbs{eom} = sub {
+        my ($ctx) = @_;
+        eval {
+                my $priv = $ctx->getpriv;
+                $ctx->setpriv({ header => {}, envrcpt => {} });
+                my @rcpt = keys %{$priv->{envrcpt}};
+
+                # one recipient, one unique HTTP(S) URL
+                return SMFIS_CONTINUE if @rcpt != 1;
+                return SMFIS_CONTINUE if archive_addr(lc($rcpt[0]));
+
+                my $unsub = $priv->{header}->{'list-unsubscribe'} || [];
+                my $n = 0;
+                foreach my $u (@$unsub) {
+                        # Milter indices are 1-based,
+                        # not 0-based like Perl arrays
+                        my $index = ++$n;
+                        my ($k, $v, $list, $domain) = @$u;
+
+                        next unless $k && $v && $list && $domain;
+                        my $u = $crypt->encrypt($rcpt[0]);
+                        $u = encode_base64url($u);
+                        $v .= ",\n <https://$domain/u/$u/$list>";
+
+                        $ctx->chgheader($k, $index, $v);
+                }
+        };
+        warn $@ if $@;
+        SMFIS_CONTINUE;
+};
+
+my $milter = Sendmail::PMilter->new;
+
+# Try to inherit a socket from systemd or similar:
+my $fds = $ENV{LISTEN_FDS};
+if ($fds && (($ENV{LISTEN_PID} || 0) == $$)) {
+        die "$0 can only listen on one FD\n" if $fds != 1;
+        my $start_fd = 3;
+        my $s = IO::Socket->new_from_fd($start_fd, 'r') or
+                die "inherited bad FD from LISTEN_FDS: $!\n";
+        $milter->set_socket($s);
+} else {
+        # fall back to binding a socket:
+        my $sock = 'unix:/var/spool/postfix/unsubscribe/unsubscribe.sock';
+        $milter->set_listen(1024);
+        my $umask = umask 0000;
+        $milter->setconn($sock);
+        umask $umask;
+}
+
+$milter->register('unsubscribe', \%cbs, SMFI_CURR_ACTS);
+$milter->main();
diff --git a/examples/unsubscribe.psgi b/examples/unsubscribe.psgi
new file mode 100644
index 00000000..5b9b16cc
--- /dev/null
+++ b/examples/unsubscribe.psgi
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -w
+# Copyright (C) 2016 all contributors <meta@public-inbox.org>
+# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
+# This should not require any other PublicInbox code, but may use
+# PublicInbox::Config if ~/.public-inbox/config exists or
+# PI_CONFIG is pointed to an appropriate location
+use strict;
+use Plack::Builder;
+use PublicInbox::Unsubscribe;
+my $app = PublicInbox::Unsubscribe->new(
+        pi_config => eval { # optional, for pointing out archives
+                require PublicInbox::Config;
+                # uses ~/.public-inbox/config by default,
+                # can override with PI_CONFIG or here since
+                # I run this .psgi as the mlmmj user while the
+                # public-inbox-mda code which actually writes to
+                # the archives runs as a different user.
+                PublicInbox::Config->new('/home/pi/.public-inbox/config')
+        },
+        # change if you fork
+        code_url => 'https://public-inbox.org/public-inbox.git',
+        owner_email => 'BOFH@example.com',
+        confirm => 0,
+
+        # First 8 bytes is for the key, next 8 bytes is for the IV
+        # using Blowfish.  We want as short URLs as possible to avoid
+        # copy+paste errors
+        # umask 077 && dd if=/dev/urandom bs=16 count=1 of=.unsubscribe.key
+        key_file => '/home/mlmmj/.unsubscribe.key',
+
+        # this runs as whatever user has perms to run /usr/bin/mlmmj-unsub
+        # users of other mailing lists.  Returns '' on success.
+        unsubscribe => sub {
+                my ($user_addr, $list_addr) = @_;
+
+                # map list_addr to mlmmj spool, I use:
+                # /home/mlmmj/spool/$LIST here
+                my ($list, $domain) = split('@', $list_addr, 2);
+                my $spool = "/home/mlmmj/spool/$list";
+
+                return "Invalid list: $list" unless -d $spool;
+
+                # -c to send a confirmation email, -s is important
+                # in case a user is click-happy and clicks twice.
+                my @cmd = (qw(/usr/bin/mlmmj-unsub -c -s),
+                                '-L', $spool, '-a', $user_addr);
+
+                # we don't know which version they're subscribed to,
+                # try both non-digest and digest
+                my $normal = system(@cmd);
+                my $digest = system(@cmd, '-d');
+
+                # success if either succeeds:
+                return '' if ($normal == 0 || $digest == 0);
+
+                # missing executable or FS error,
+                # otherwise -s always succeeds, right?
+                return 'Unknown error, contact admin';
+        },
+);
+
+builder {
+        mount '/u' => builder {
+                eval { enable 'Deflater' }; # optional
+                eval { enable 'ReverseProxy' }; # optional
+                enable 'Head';
+                sub { $app->call(@_) };
+        };
+};
diff --git a/examples/varnish-4.vcl b/examples/varnish-4.vcl
new file mode 100644
index 00000000..24296032
--- /dev/null
+++ b/examples/varnish-4.vcl
@@ -0,0 +1,68 @@
+# Example VCL for Varnish 4.0 with public-inbox WWW code
+# This is based on what shipped for 3.x a long time ago (I think)
+# and I'm hardly an expert in VCL (nor should we expect anybody
+# who maintains a public-inbox HTTP interface to be).
+#
+# It seems to work for providing some protection from traffic
+# bursts; but perhaps the public-inbox WWW interface can someday
+# provide enough out-of-the-box performance that configuration
+# of an extra component is pointless.
+
+vcl 4.0;
+backend default {
+        # this is where public-inbox-http listens
+        .host = "127.0.0.1";
+        .port = "280";
+}
+
+sub vcl_recv {
+        /* pipe POST and any other weird methods directly to backend */
+        if (req.method != "GET" && req.method != "HEAD") {
+                return (pipe);
+        }
+        if (req.http.Authorization || req.http.Cookie) {
+                /* Not cacheable by default */
+                return (pass);
+        }
+        return (hash);
+}
+
+sub vcl_pipe {
+        # By default Connection: close is set on all piped requests by varnish,
+        # but public-inbox-httpd supports persistent connections well :)
+        unset bereq.http.connection;
+        return (pipe);
+}
+
+sub vcl_hash {
+        hash_data(req.url);
+        if (req.http.host) {
+                hash_data(req.http.host);
+        } else {
+                hash_data(server.ip);
+        }
+        /* we generate fully-qualified URLs for Atom feeds and redirects */
+        if (req.http.X-Forwarded-Proto) {
+                hash_data(req.http.X-Forwarded-Proto);
+        }
+        return (lookup);
+}
+
+sub vcl_backend_response {
+        set beresp.grace = 60s;
+        set beresp.do_stream = true;
+        if (beresp.ttl <= 0s ||
+                /* no point in caching stuff git already stores on disk */
+                beresp.http.Content-Type ~ "application/x-git" ||
+                beresp.http.Set-Cookie ||
+                beresp.http.Vary == "*") {
+                /* Mark as "Hit-For-Pass" for the next 2 minutes */
+                set beresp.ttl = 120 s;
+                set beresp.uncacheable = true;
+                return (deliver);
+        } else {
+                /* short TTL for up-to-dateness, our PSGI is not that slow */
+                set beresp.ttl = 10s;
+        }
+        return (deliver);
+}