{% extends "global/layout.html" %} {% block title %}{{ _('How to Set up a Reseed Server') }}{% endblock %} {% block lastupdated %}{% trans %}February 2016{% endtrans %}{% endblock %} {% block content %}

{% trans %}Overview{% endtrans %}

{% trans -%} Thank you for volunteering to run an I2P reseed server. "Reseeding" is our term for bootstrapping new routers into the network. New routers fetch a bundle of peer references, or "router infos", from one or more of a hardcoded list of HTTPS URLs. {%- endtrans %}

{% trans %}Requirements{% endtrans %}

{% trans -%} At its simplest, a reseed server consists of a Java I2P router, an HTTPS web server, and some scripts that periodically gather router infos from the router, bundle and sign them into a custom file format, and deliver these files over HTTPS. In practice, it's a bit more complex, and a reseed operator must be fairly competent and attentive. A reseed server is not appropriate for a residential internet connection. The complexities include: {%- endtrans %}

{% trans %}Information Required{% endtrans %}

{% trans -%} When your setup is complete and ready for testing, we will need the HTTPS URL, the SSL public key certificate, and the "su3" bundle public key. After testing is complete, these will be added to the hardcoded entries in the Java and C++ routers in the next release, and you will start seeing traffic. We also will need your email address so we may continue to contact you about reseed administration issues. The email will not be made public but will be known to the other reseed operators. You should expect that your nick or name and its association with that URL or IP will become public. {%- endtrans %}

{% trans %}Privacy Policy{% endtrans %}

{% trans -%} A reseed operator is a trusted role in the network. While we do not yet have a formal privacy policy, you must ensure the privacy of our users by not publicizing logs or IPs found in those logs, except as necessary to discuss administration issues with the I2P reseed team. {%- endtrans %}

{% trans %}Getting Started{% endtrans %}

{% trans -%} Our reseed coordinator is "backup" and he may be contacted at backup@mail.i2p or backup at i2pmail.org. Unfortunately, he is not generally on IRC. The reseed setup is somewhat specialized, and you should direct most questions to him. {%- endtrans %}

{% trans -%} For actual implementation, details below. In summary, there are two solutions we have to offer: {%- endtrans %}

  1. {% trans -%} A Go implementation that includes the web server and all the scripts. This is the recommended solution. {%- endtrans %}
  2. {% trans -%} An older PHP implementation plus some shell scripts. The PHP goes into a web server that you must set up separately. {%- endtrans %}

{% trans -%} For further information, read the information at the following links, and then contact backup. Thank you! {%- endtrans %}

{% trans %}Detailed Instructions{% endtrans %}

How-to Public reseed servers - su3

Table of contents

  1. Introduction
  2. Requirements
  3. Go solution - Quick Guide
    1. Start web server
    2. Install git and golang
    3. Build and test
    4. Run reseed
    5. Backup certificates and keys
    6. Enable autostart
    7. Connect web server to reseed
    8. Test from another computer
    9. Send us your certificates
  4. Go solution -Detailed Guide
    1. Go solution - Building from source
    2. Go solution - Run the reseed server
    3. Go solution - Draft for startup script
    4. Go solution - reverse-proxy setup
    5. Go solution - Convert existing Java keystore to crt- and pem-file
  5. PHP solution - Not recommended
    1. Short overview
    2. su3-file guidelines for reseeding
    3. How to prepare your key pair for su3-files
    4. su3 server-side implementation
    5. Unix shell script for cronjob
    6. Setup cronjob
    7. PHP script for web server
    8. url rewrite rule for web server
    9. Create self-signed ssl-certificate
    10. Seamless ssl-certificate exchange
    11. reseed server domain/url/port exchange
    12. Testings
    13. Contact reseed maintainer
    14. Script - cronjob_i2p.sh
    15. Script - su3.php
    16. Optional - setup a manual reseed method

1. Introduction

Public reseed servers are necessary to bootstrap into the I2P net. New installed I2P routers needs one-time about one hundred RouterInfo's (RI) as jump start.

RI contains IP and Port from other I2P routers and are stored in dat-files in the netDB folder.

A random bunch of dat-files from the netDB are zipped, then signed to a su3-file and finally offered to I2P routers seeking reseed service.

To secure bootstrap and enable a trusted start, HTTPS/TLS and signed su3-files are mandatory.

It is essential not to publish all RI from netDB, or all RI to one client. So a cronjob will be setup providing only a part of all available RI.

A PHP script ensures that requests to the public reseed server provides only one su3-file within 24h for one client IP.

2. Requirements

Requirements for running a public reseed server:

This How-to is tested with Ubuntu/Debian The web server has to be public reachable from all over the world, an eepsite inside I2P can be setup in addition. Also frequent or infrequent attempts to scrape all your reseed files, and of course attacks on your server. The web server doesn't need to listen at default SSL/TSL port 443 - any other port can be used for obfuscation.

3. Go solution - Quick Guide

1. Fire up your favorite webserver

  1. connect a domain, sub-domain or (anonymous) third-level-domain
  2. setup a state-of-the-art TLS(SSL) certificate
  3. allow access only via HTTPS/TLS, no unencrypted HTTP
  4. allow only very good ciphers, compatible to Java 7/8/9

Note: A non default port other than 443 can be used; TLS certificate can be self signed; configure fail2ban as bot-net protection

2. Install git and golang-go (1.4.2 or higher)

	sudo apt install git
	sudo apt install golang-go

3. Switch to user running i2p, fetch the i2p-tool source code, build and test it

Note: Visit http://reseed.i2p and download a pre-build x86_64 binary, so you can skip step 2+3.

	export GOPATH=$HOME/go; mkdir $GOPATH; cd $GOPATH
	go get github.com/martin61/i2p-tools
	bin/i2p-tools -h

4. Run i2p-tools locally

	GOPATH=$HOME/go;
        cd $GOPATH;
        bin/i2p-tools reseed --signer=yourname@mail.i2p --netdb=/home/i/.i2p/netDb --port=8443 --ip=127.0.0.1 --trustProxy

5. Back up new certificates

Make a backup from the new created su3-signing key and certificate found in $GOPATH and keep it in a save password protected storage

6. enable autostart (+restart) for i2p-tools in your crontab

	@reboot   GOPATH=$HOME/go; cd $GOPATH; bin/i2p-tools reseed ... >/dev/null 2>&1
	9 * * * * GOPATH=$HOME/go; cd $GOPATH; bin/i2p-tools reseed ... >/dev/null 2>&1

7. connect your webserver via reverse-proxy-setup to the i2p-tool, examples

lighttpd configuration example:

		server.modules += ( "mod_proxy" )
		proxy.server = ( "i2pseeds.su3" => ( ( "host" => "127.0.0.1", "port" => 8443 ) ) )

nginx configuration example:

		location / {
			proxy_pass http://127.0.0.1:8443;
		}

apache (sorry: untested - feedback would be appreciated)

		ProxyRequests Off
		<Proxy *>
			Order deny,allow
			Allow from all
		</Proxy>
		ProxyPass / http://127.0.0.1:8443/
		ProxyPassReverse / http://127.0.0.1:8443/

Note: i2p-tool has also an build-in standalone webserver with tls support which can be used without a webserver.

8. Final test from another computer with i2p running

  1. place your su3-certificate (*.crt) in i2p/certificates/reseed/
  2. place your tls-certificate (*.crt) in i2p/certificates/ssl/
  3. visit with your webbrowser http://localhost:7657/configreseed
  4. enter your new reseed-url and delete all others, hit "Save changes and reseed now"
  5. check the i2p logs for "Reseed got 77 router infos from ... with 0 errors, Reseed complete, 77 received"

9. Send us your information

  1. domain/url/port
  2. su3-signing certificate
  3. tls certificate (if self signed)

4. Go solution - Detailed Instructions

1. Go solution - Overview

The previous steps for reseeding involves many steps, scripts and programs. Most of them are easy and plain straight forward, but overall you can call it a little confusing.

Here comes now an all-in-one solution from matt (Big Thanks!) for providing a reseed server which merges the following functions into one binary:

Almost all previous used scripts and described steps are not needed with this solution, but to understand the overall reseed process it is recommended to read them too :-)

Of course you need an up-to-date netDB folder with routerinfos from a running i2p router. I2P does not have to be running on the same machine as this reseed binary. In this case you can setup a cronjob to transfer the netDB from the I2P machine to the reseed machine.

Matt's go solution can be used in parallel next to an already running http-server. For this leave the http-server running at normal port 80 and 443, and configure Go solution too use another port, e.g. port 8443.

More: at github, README.md, https://github.com/MDrollette/i2p-tools

2. Go solution - Building from source

Requirements:

Install go from https://golang.org/doc/install, example for 64 bit Ubuntu/Debian:

Verify go:

$ go version
which should state something like: "go version go1.4.2"

Install Go solution from https://github.com/MDrollette/i2p-tools into $HOME/go:

$ go get github.com/MDrollette/i2p-tools

This will install a binary to $GOPATH/bin/i2p-tools

Run the go solution, the usage/help should be displayed, nothing more:

$ i2p-tools

3. Go solution - Run the reseed server

$ i2p-tools reseed --tlsHost=myserver.com --signer=myemail@mail.i2p --netdb=$HOME/.i2p/netDb

Output:

2015/03/15 12:28:25 Rebuilding su3 cache...
2015/03/15 12:28:25 Building 200 su3 files each containing 75 out of 3180 routerInfos.
2015/03/15 12:28:35 Done rebuilding.
2015/03/15 12:28:35 HTTPS server started on 0.0.0.0:8443

So you can now test to reach the server at port 8443, see a previous chapter about proper testing.

Some remarks:

4. Go solution - Draft for startup script "seedserver"

The reseed server should be started automatically, so you need a init.d or some sort of startscript, here named as "seedserver". This is only a very first draft for a simple startscript (it could be done better :-))

Login as I2P user:

Update the header "# Your settings" with your individual settings.

Now you can use the shell-script:

seedserver start

And then (give it some seconds) take a look at the status:

seedserver status
seedserver showlog

Some short explanation about seedserver:

If this is working fine, you can put the script in your personal crontab, to run it by auto-start and to do logrotes simply by restarting it regularly once a week to avoid too big logfiles. If you already reboot your server regularly, you can skip of course the "restart" command line.

Login as I2P user, edit your crontab:

crontab -e

and add these 3 lines at the end:

@reboot /home/i2p/bin/seedserver startdelayed
04 14 * * 2 /home/i2p/bin/seedserver restart
#end

Save and close the editor. It would be good to check if this is properly working when you reboot your machine.

"seedserver" shell script:

######################################################################################################
#!/bin/sh

# Your settings
toolpath=/home/i2p/bin
tlsHost=myserver.com
signer=myemail@mail.i2p
netdb="/home/i2p/.i2p/netDb"


tool=i2p-tools
logpath="$toolpath/${tool}.log"
logfile="$logpath/reseed.log"
errfile="$logpath/reseed.error"

cd "$toolpath"
mkdir --parents "$logpath"


do_status() {
/bin/sleep 1
if [ -n "$(pgrep -x "$tool")" ]; then
echo "$tool running, pid $(pgrep "$tool")"
else
echo "$tool not running."
fi;
}

do_start() {
if [ -z "$(pgrep -x "$tool")" ]; then
do_logrotate
nohup "$toolpath/$tool" reseed -tlsHost="$tlsHost" --signer="$signer" --netdb="$netdb" > "$logfile" 2> "$errfile" &
fi;
do_status
}

do_stop() {
if [ -n "$(pgrep -x "$tool")" ]; then
pkill "$tool"
fi;
do_status
}

do_startdelayed() {
echo "waiting 20s..."
/bin/sleep 20
do_start
}

do_restart() {
do_status
do_stop
do_start
}

do_logrotate() {
do_status
if [ -z "$(pgrep -x "$tool")" ]; then
mv --force "${logfile}.6" "${logfile}.7" 2>/dev/null
mv --force "${logfile}.5" "${logfile}.6" 2>/dev/null
mv --force "${logfile}.4" "${logfile}.5" 2>/dev/null
mv --force "${logfile}.3" "${logfile}.4" 2>/dev/null
mv --force "${logfile}.2" "${logfile}.3" 2>/dev/null
mv --force "${logfile}.1" "${logfile}.2" 2>/dev/null
mv --force "${logfile}" "${logfile}.1" 2>/dev/null
mv --force "${errfile}.6" "${errfile}.7" 2>/dev/null
mv --force "${errfile}.5" "${errfile}.6" 2>/dev/null
mv --force "${errfile}.4" "${errfile}.5" 2>/dev/null
mv --force "${errfile}.3" "${errfile}.4" 2>/dev/null
mv --force "${errfile}.2" "${errfile}.3" 2>/dev/null
mv --force "${errfile}.1" "${errfile}.2" 2>/dev/null
mv --force "${errfile}" "${errfile}.1" 2>/dev/null
echo "log-rotate done."
else
echo "log-rotate not possible."
fi;
}

do_showlog() {
echo "-------------------------------------------------------------------------------"
tail "$errfile"
echo "-------------------------------------------------------------------------------"
tail "$logfile"
echo "-------------------------------------------------------------------------------"
}


do_usage() {
echo "Usage: {start|stop|status|restart|logrotate|startdelayed|showlog}"
}

case "$1" in
start)
do_start
;;
stop)
do_stop
;;
status)
do_status
;;
restart)
do_restart
;;
startdelayed)
do_startdelayed
;;
logrotate)
do_logrotate
;;
showlog)
do_showlog
;;
*)
do_usage
;;
esac

exit 0
######################################################################################################

5. Go solution - reverse-proxy setup

You can run i2p-tools also behind your normal web-server (reverse-proxy).

The web-server handles the TLS handshake, encryption, SSL Certificate and the logfiles. But you don't need the scripts su3.php and the shell cronjob for creating su3-files. i2p-tools is running "behind" the web-server, without TLS management, only bind to local interface 127.0.0.1 and is handling complete building and handling of su3-files.

Run i2p-tools with this command:

i2p-tools reseed --signer test@test.de --key /path_to/test_at_test.de.pem --netdb /path_to/netDb --port=8443 --ip 127.0.0.1 --trustProxy
Important notes for this special setup: "trustProxy" uses the "X-Forwarded-For" to get the real client IP

lighttpd configuration example:

	server.modules += ( "mod_proxy" )
	proxy.server = ( ".su3" => ( ( "host" => "127.0.0.1", "port" => 8443 ) )  )

nginx configuration example:

	location / {
		proxy_pass http://127.0.0.1:8443;
	}

and for X-Forwarded-For:

     proxy_set_header        X-Real-IP       $remote_addr;
     proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

6. Go solution - Convert existing Java keystore to crt- and pem-file

This describes how to convert your existing Java keystore with your su3 signing key to a plain crt- and pem-file. This is only needed, when you already have a Java keystore and want to use Go solution. If you create new keys+certs with matt's solution you can skip this chapter!

Requirements:

Keep in mind: the Java keystore has two passwords:

This works in a Ubuntu/Debian shell:

######################################################################################################
file="keystore.ks"
pass_jks=changeit

# List the keystore content, show the included (email) alias
keytool -list -storepass $pass_jks -keystore $file

# Convert jks --> pkcs12, specify the correct email alias (xxxxx@mail.i2p):
keytool -importkeystore -srcalias xxxxx@mail.i2p -srckeystore $file -srcstoretype jks -srcstorepass $pass_jks -destkeystore ${file}.p12  -deststoretype pkcs12 -deststorepass $pass_jks -destkeypass $pass_jks

# Show the pkcs12 content:
openssl pkcs12 -passin pass:$pass_jks -in ${file}.p12 -nodes -info

# Convert pkcs12 --> pem
openssl pkcs12 -passin pass:$pass_jks -in ${file}.p12 -nodes -out ${file}.pem

# Decrypt the pem
openssl rsa  -in ${file}.pem -out xxxxx_at_mail.i2p.pem

# Extract the certificate
openssl x509 -in ${file}.pem -out xxxxx_at_mail.i2p.crt
######################################################################################################

5. PHP solution - Not recommended

1. Short overview

2. su3-file guidelines for reseeding

(From zzz.i2p)

3. How to prepare your key pair for su3-files

( from zzz.i2p)

Example to create your key pair:

	su - i2puser
	I2P=/home/i2puser/i2p
	cd $I2P
	java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File keygen -t RSA_SHA512_4096 backup_at_mail.i2p.crt keystore.ks backup@mail.i2p

Short usage help:

	SU3File keygen [-t type|code] publicKeyFile keystore.ks you@mail.i2p

Get more help:

	java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File

Provide a strong password for your private key. In this example two new files will be created in the working folder:

Backup and store public key, private key and your password! Remember also the used key size/type when not using default RSA_SHA512_4096. Send the public .crt key file to us, to include it into i2p/certificates/reseed/ If you have mtn privs, you may check the (you)_at_mail.i2p.crt file directly into installer/resources/certificates/reseed . The file name must be (email address used for signing).crt, with "@" replaced with "_at_". There is no requirement that it be xxx@mail.i2p, any email is fine, or for that matter any identifier.

4. su3 server-side implementation

(from zzz.i2p) This describes a mechanism for creating and distributing the RI in new su3 format. It's independent from legacy way of doing (fetching dat-files) and can be used in parallel. This idea doesn't need mysql, only some Unix shell tools and a simple web server with PHP works fine.

A requesting client gets ~75 RI packed into one zip, signed and converted to a su3-file. Don't provide unlimited RI to one clients. But don't try to keep track of million client IP's in a database, e.g think of ipv6. Keep it simple: make a fix n:m one-direction matching: n*ip --> m*su3-file by modulo. n is the unlimited IPv4+IPv6 address space, and m are e.g. 100 pre-calculated su3-files. A client with one IP gets always the same su3-file, until the su3-file is updated or the client has a new IP. A number of clients (n/m ratio) gets the same su3-file - the same set of RI, so m is subject to be monitored in I2P net grow.

Once or twice a week (or daily): pre-calculate ~100 new su3-files, each includes ~75 RI. The RI are fetched from a well running I2P router's netdb directory. Transfer the pre-calculate su3-files to your web server, e.g. by sftp or copy them locally to /var/www/su3/. In the web server a PHP script will match one client IP to one of the 100 su3-files by hash+modulo. This has the advantage to split su3-generation and publishing in web server .

Requirements for su3-file generation:

Requirements for web server : The following solution for a public reseed server consists of three parts: They are described on the following chapters in more detail.

5. Unix shell script for cronjob

This script pre-calculates n su3-files. Requirements: Unix shell, Java, I2P, zip-tool, your private reseed signing key Main Steps:

# CONFIG
# CHECK REQUIREMENT
# CREATE index files from netdB: use only 66% and max. 10h old
# CREATE zip files
# CREATE su3 files
# FINALIZE

Please check and edit #CONFIG sections, please review code before use. The resulting su3-files are placed in the "target" folder which can be changed in config section with "target". Configure file permissions and file owner e.g. 'www-data' - see deactivated example lines. The cronjob script runs ca. 10 seconds for generating 100 pre-calculated su3 files on a modern cpu. The number of dat-files per su3 package is random. If you configure 75, it results in ca. 50...100 dat-files per su3-file. The number of generated su3-files is random too, it depends on your netdb size and adapts automatically:

Only 66% of all RI from your netdb are used, netdb may be not older than 10h. It is possible to separate cronjob script from PHP script: Run the cronjob script on your I2P machine and then transfer the final su3-files via (s)ftp/ssh to your web server from time to time. su3 file-size in this setup is between 50 and 100 KB per file.

6. Setup cronjob

Please add a cronjob, e.g. to run it every few days. Add the shell script in crontab, e.g.:

	crontab -e
	23 59 * * * /usr/local/bin/cronjob_i2p.sh

The hard limit for the su3-file age is 30 days. Recommendation is to update the su3-files once every 1..10 days.

7. PHP script for web server

The su3.php script maps always one client IP to one pre-calculated su3-file. Requirements: a web server with PHP5 Main Steps:

# CONFIG
# HEALTH CHECK
# COUNT su3 files
# MAPPING Client IP to one SU3
# PROVIDE SU3

Please check and edit #CONFIG sections, please review code before use.

The date() function in the salt ensures a rotate once a day, even if su3-files are not updated daily. To avoid scraping from attackers with big IPv4 subnet resources (or even IPv6) some lower bytes of the client IP address are discarded:

Clients in the same "subnet" gets the same su3-file

A clients gets only different su3-file package in following circumstances:

8. url rewrite rule for web server

It is mandatory that clients does not have direct access to the su3-files at the web server. Please activate a rewrite rule for su3-files in your web server pointing to the su3.php file:

	*.su3 --> su3.php?file=$1

Apache in ".htaccess":

	Options +FollowSymlinks
	RewriteEngine On
	RewriteRule ^(.*\.su3)$ /su3.php?file=$1 [L]

lighttpd in "/etc/lighttpd/lighttpd.conf":

	server.modules += ( "mod_rewrite" )
	url.rewrite-once = ( "^(.*\.su3)$" => "/su3.php?file=$1" )

We want only HTTPS accessible reseed server. Sorted by best solution:

9. Create self-signed ssl-certificate

How-to generate a new self-signed ssl-certificate for HTTPS/TLS with openssl. Example command line in Debian/Ubuntu for your.server.com:

$ openssl req -x509 -nodes -days 1500 -newkey rsa:4096 -sha256 -keyout your.server.com.pem -out your.server.com.pem
...
Country Name (2 letter code) [AU]:UK
State or Province Name (full name) [Some-State]:your.server.com
Locality Name (eg, city) []:your.server.com
Organization Name (eg, company) [Internet Widgits Pty Ltd]:your.server.com
Organizational Unit Name (eg, section) []:your.server.com
Common Name (e.g. server FQDN or YOUR name) []:your.server.com
Email Address []:your.server.com

The result is stored in "your.server.com.pem" file

Remarks:

Next step:

Send this to us - the .crt file with the public key section will we included in every I2P router. The .pem file with your private key is only for you and your web server.

10. Seamless ssl-certificate exchange

The update/exchange of an already existing self-signed certificates has to be correct timed on server *and* client side. Considering thousands of clients (many with older I2P version) the exchange will not be seamless possible and will have very bad impact on many clients: reseed won't work for them.

To avoid this issue and make the exchange as smooth as possible follow these simple steps:

  1. generate a new ssl-certificate NOW, but do NOT implement it on server
  2. send the new ssl-certificate to us to perform a roll-out towards clients NOW
  3. WAIT some month, e.g. 3-4 i2p-releases
  4. new ssl-certificate is now hopefully present on many clients (in parallel to the current/old one)
  5. THEN exchange the ssl-certificate on server

This idea based on the fact, that you can provide in i2p/certificates/ssl more than one crt-file for a server, e.g. server.com.crt and server.com2.crt

11. reseed server domain/url/port exchange

You are already operating a reseed server but want to change your domain/url/port? To make the exchange as smooth as possible for many clients please follow these steps if possible:

  1. Setup an additional reseed instance at the new domain/url/port
  2. we include the new url into I2P source NOW and delete the old url NOW
  3. both of your reseed instances have to run some time in parallel
  4. WAIT some month, e.g. 3-4 i2p-releases
  5. new url is now hopefully present on many clients
  6. THEN shutdown the old reseed instance

12. Tests

Some simple pre-test: test the website and fetch

	wget --user-agent="Wget/1.11.4" -O /tmp/test.su3 --no-check-certificate https://your-server.com:PORT/i2pseeds.su3
Replace "PORT" with default 443 or your chosen server setting. Inspect the fetched file.: Some simple pre-test: test the website and fetch
	zipinfo -z /tmp/test.su3

Replace "--no-check-certificate" with "--ca-certificate=~/i2p/certificates/ssl/your-server.com.crt" which contains the path to your local public ssl-certificate to check also your ssl-certificate chain.

Everything ok:

Do a real reseed test on *another* I2P router machine:

13. Contact reseed maintainer

Contact us per email backup@mail.i2p (fallback is killyourtv@mail.i2p or the reseed section at zzz's forum) Provide us details about the new

Feel free to contact backup@mail.i2p in case of questions or problems or post your question at zzz's forum in the reseed section.

14. Script - cronjob_i2p.sh

###############################################################################
#!/bin/sh
version="v5"


# CONFIG
I2P="${HOME}/i2p"			# i2p installation directory
source="${HOME}/.i2p/netDb"		# valid netdb
target="${HOME}/i2pseeds.su3"		# location for the final su3-files

key_keystore="${I2P}/keystore.ks"	# your private su3 reseed key
key_password="secret"			# your password for private key of keystore.ks
key_email=yourmail@mail.i2p		# your email id for reseeding
key_type=RSA_SHA512_4096		# your key size/type for reseeding (DO NOT EDIT, unless you know why)

tool_zip="/usr/bin/zip"			# install a "zip" tool: sudo apt-get install zip
tool_i2p="$I2P/lib/i2p.jar"		# should be already there


# CONFIG (DO NOT EDIT)
ri_seed=75				# average number ri per su3-file (DO NOT EDIT)
stamp=$(date +%s)			# unique id (DO NOT EDIT)
target_tmp="/tmp/i2pseeds.${stamp}.tmp"	# temp folder with unique id (DO NOT EDIT)


# CLEAN /tmp/i2pseeds.*
find /tmp -type d -iname 'i2pseeds.*.tmp' -exec rm -rf {} \;
mkdir --parents "${target_tmp}"


# CHECK REQUIREMENT
[ ! -d "${I2P}" ]          && echo "ERROR1: path not found: ${I2P}"          && exit 1
[ ! -d "${source}" ]       && echo "ERROR2: path not found: ${source}"       && exit 1
[ ! -d "${target_tmp}" ]   && echo "ERROR3: path not found: ${target_tmp}"   && exit 1
[ ! -x "${tool_zip}" ]     && echo "ERROR4: command not found: ${tool_zip}"  && exit 1
[ ! -f "${tool_i2p}" ]     && echo "ERROR5: file not found: ${tool_i2p}"     && exit 1
[ ! -f "${key_keystore}" ] && echo "ERROR6: file not found: ${key_keystore}" && exit 1


# CREATE index-files from netdB: use only 66% and max. 10h old
find "${source}" -type f -mmin -600 -name 'routerInfo-*.dat' | awk -v ri_seed="${ri_seed}" -v target_tmp="${target_tmp}" '
	BEGIN { ri_all=0; }
	{	data[ri_all++]=$0; }
	END {	srand();
		ri_use=ri_all*0.6666;
		ri_su3=int(ri_use/10);
		stepy=ri_use/ri_all;
		stepx=ri_seed/ri_use;
		for (y=0;y<ri_all; y++) if (rand()<=stepy) {
			for (x=0; x<ri_su3; x++) if (rand()<=stepx) {
				file=target_tmp"/"x".index";
				print data[y] >> file
			}
		}
	}'


# CREATE zip-files from index-files
find "${target_tmp}" -type f -name '*.index' | sort | while read i; do
	"${tool_zip}" --update --quiet --junk-paths "${target_tmp}/$(basename "$i" .index)" -@ < "$i"
done


# CREATE su3-files from zip-files
echo "${key_password}" | java -cp "${tool_i2p}" net.i2p.crypto.SU3File bulksign -c RESEED -t "${key_type}" "${target_tmp}" "${key_keystore}" "${stamp}" "${key_email}"


# REMOVE index-files and zip-files
find "${target_tmp}" -type f -name '*.index' -exec rm -f "{}" \;
find "${target_tmp}" -type f -name '*.zip'   -exec rm -f "{}" \;


# FINAL CHECK number su3-files
c_su3=$(find "${target_tmp}" -type f -mmin -600 -name '*.su3' | wc -l)
[ "${c_su3}" -lt 25 ] && echo "ERROR7: less than 25 su3 files found: ${c_su3}" && rm -Rf "${target_tmp}" && exit 1
echo "Created: $target_tmp ${c_su3} x${ri_seed}"


# MOVE su3-files to target
chmod 755 "${target_tmp}" -R
rm -fr "${target}.old"
mv -f  "${target}"     "${target}.old"
mv -f  "${target_tmp}" "${target}"
rm -fr "${target_tmp}"


# EXIT
echo      "$(basename "$0")" "${version} ${target} ${c_su3} x${ri_seed}"
logger -t "$(basename "$0")" "${version} ${target} ${c_su3} x${ri_seed}"
exit 0
###############################################################################

15. Script - su3.php

###############################################################################
<?php
$version="v5";


# CONFIG
$path_su3="/home/i2p/i2pseeds.su3";		# path to pre-calculated su3 files
$salt="change_to_something";			# change salt to something random
$salt=$salt . date("Y-m-d");			# date() ensures a rotate once a day, even if su3 are not updated daily (DO NOT EDIT)
$file_su3  = "i2pseeds.su3";			# static (DO NOT EDIT)
$user_agent= "Wget/1.11.4";			# static (DO NOT EDIT)


# INSIDE i2p-net ? If yes: convert DESTB32 into pseudo IPv6 as valid REMOTE_ADDR
if (	$_SERVER["REMOTE_ADDR"]=="127.0.0.1"
	&& isset($_SERVER["HTTP_X_I2P_DESTB32"])
  ) {	$_SERVER["REMOTE_ADDR"]=inet_ntop(substr(md5($_SERVER["HTTP_X_I2P_DESTB32"]),0,16)); }


# HEALTH CHECK 1
if (	!isset($_SERVER['HTTP_USER_AGENT'])
	|| !isset($_SERVER['REMOTE_ADDR'])
	|| !isset($_GET['file'])
    ) { header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); die(); }


# COUNT su3 files
$count_su3 = count(glob($path_su3."/*.su3"));


# HEALTH CHECK 2
if (	empty($_SERVER['HTTP_USER_AGENT'])
	|| empty($_SERVER['REMOTE_ADDR'])
	|| empty($_GET['file'])
	|| (strcmp(basename($_GET['file']), $file_su3) != 0)
	|| (strcmp($_SERVER['HTTP_USER_AGENT'], $user_agent) != 0)
	|| !filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP)
	|| $count_su3<1
    ) { header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); die(); }


# MAPPING Client IP to one su3-file
$remote_id = inet_pton($_SERVER['REMOTE_ADDR']);
$shrink=3; if (strlen($remote_id)>8) { $shrink=8; };
$remote_id = abs(crc32(md5(substr($remote_id,0,$shrink).$salt))) % $count_su3;
$file_id = $path_su3."/".$remote_id.".su3";


# HEALTH CHECK 3
if (!file_exists($file_id)) { header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); die(); }


# PROVIDE su3-file
header('Content-Description: File Transfer');
header("Content-Type: application/zip");
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file_id));
header('Content-Disposition: attachment; filename='.$file_su3);
ob_clean(); flush();
if (!readfile($file_id)) { header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); die(); }
exit;
?>
###############################################################################

16. Optional - setup a manual reseed method

For some users the automated reseeding may not work. This is an alternate way for users to get a valid reseed file with a normal web-browser, e.g. from another machine or maybe a friend. It is secured by a captcha to prevent abuse.

With this optional code users can visit https://your.reseedserver.com/reseed.php with any web-browser to download a su3-file after they solved the captcha.

Since 0.9.18-9 I2P has support to use reseed files from other sources: http://localhost:7657/configreseed

Visit https://geti2p.net/en/faq#manual_reseed to read how it works for users and see some example url's. [NOT DONE YET: read here: zzz.i2p or test here anonymously: reseed.i2p]

The changes for an exiting reseed server with the previous setup are simple:

Quote from https://www.phpcaptcha.org (2015-03): "Securimage is an open-source free PHP CAPTCHA script for generating complex images and CAPTCHA codes to protect forms from spam and abuse. It can be easily added into existing forms on your website to provide protection from spam bots. It can run on most any web server as long as you have PHP installed, and GD support within PHP. Securimage does everything from generating the CAPTCHA images to validating the typed code."

Short overview about installing Securimage:

  1. download at https://www.phpcaptcha.org/download/
  2. extract to /var/www/securimage
  3. download and extract the "Test Script" (securimage_test.php) from the same url
  4. test your server and visit https://.../securimage_test.php with your browser

The "Test Script" verifies your ability to run and display the captcha code, and can be deleted after the test.

The reseed.php contains only the captcha generation and verification of the users input. It is based on the Quickstart Guide from Securimage. When the user solved the captcha, reseed.php sets two http variables and then includes the external su3.php to start the su3-file download.

The name "reseed.php" is not fixed, you can name it unremarkable/unobtrusive as you like, enter.php start.php go.php... but you have to stick with it, when it is published :-)

reseed.php:

################################################################################################
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"></head><body>
<?php
session_start();
include_once $_SERVER['DOCUMENT_ROOT'] . '/securimage/securimage.php';
$securimage = new Securimage();

if (!isset($_POST['captcha_code']) || $securimage->check($_POST['captcha_code']) == false) {?>
	<form method="post" action="<?php echo(basename($_SERVER['PHP_SELF'])); ?>">
	<img id="captcha" src="/securimage/securimage_show.php" alt="CAPTCHA Image" />
	<p>Enter Code: <input type="text" name="captcha_code" size="10" maxlength="6" />
	<input type="submit" value="Check Code" />
	</form>
<?php } else {
	$_SERVER['HTTP_USER_AGENT']="Wget/1.11.4";
	$_GET['file']="i2pseeds.su3";
	include_once $_SERVER['DOCUMENT_ROOT'] . "/su3.php";
} ?>
</body></html>
################################################################################################
{% endblock %}