HOWTO setup a Tilde server on a Raspberry Pi


This HOWTO follows our own experience in setting up a server for web design students, so that they have access to their own web space and shells. Additionally, we wanted to have some particular features such as providing PHP.

This means that we are not (yet) planning to open this up to new users, and we know the people who are in. Your setup might require additional care if you want to create accounts for strangers. We hope to open our server up at some point, and update this document accordingly; in the meantime, keep in mind that this document presumes that you trust your users.

We’ll be actively updating this document from experience and feedback; see the Changelog at the bottom to see what’s changed.


Besides trust in your users, this guide will assume that

Base configuration

Run sudo raspi-config and go through these three steps.

Create your first user

It isn’t a great idea to keep the pi user, as most worms and novice crackers will try that as a first entry point.

In this guide, we’ll work as user luther. Change it according to your own preference when copy-pasting the below commands.

sudo adduser luther
sudo usermod -a -G adm,dialout,cdrom,sudo,audio,video,plugdev,games,users,input,netdev,gpio,i2c,spi luther

We also want our new user to have sudo access so that we can also disable the root account. Nevertheless, let’s ensure it always asks us for the password when running commands with sudo – it’s not mandatory security-wise, but doesn’t hurt your chances to keep your server safe.

Edit the /etc/sudoers.d/010_pi-nopasswd and change the line containing luther to


Copy your SSH key for password-less login

You won’t want to type in your password everytime, and you probably already have an SSH key on your computer for this. You can copy it over to your new server with one command:


Disable access to the root and pi users

For root, we’ll just disable remote SSH logins, by editing the file /etc/ssh/sshd_config and changing the option PermitRootLogin from yes to no.

If there’s no such line, type in a new one with PermitRootLogin no.

For the pi user, we’ll delete that user’s password so that login is not possible anymore.

# Delete user's password
sudo passwd -d pi
# And unset its login shell for additional peace of mind
sudo usermod -s /usr/sbin/nologin pi

Change your SSH port

Most automated exploits will stick to the default SSH port (22). You can change it so that your server won’t be bothered by most scanners. Edit the /etc/ssh/sshd_config file to change the line #Port 22 to Port 9999 or whatever number you prefer.

Do note that with this tweak, you lose the convenience of typing ssh server_address (you would now need to add -P <port_number>) and also have to highlight that additional detail for your users. On our own server we stuck with port 22 for this reason, and below you’ll find additional measures to secure and protect your server.

Install and configure base packages


sudo apt install apache2

We’ll want to enable the option to have each user’s public_html dir be served at /~username/.

sudo a2enmod userdir
sudo systemctl restart apache2

Admins should be able to edit the main site at the root domain without needing sudo. This is easy:

sudo adduser luther www-data
sudo chown -R www-data:www-data /var/www
sudo chmod -R g+rwX /var/www

Now the contents of /var/www/html can be edited by any user that you add to the www-data group.


We want our students to be able to write and run PHP scripts, and it’s rather easy to get that going.

sudo apt install php

Running PHP scripts in userdirs is disabled by default in Apache. We just have to turn it on by editing /etc/apache2/mods-enabled/php7.3.conf (the file might have another name if you’re running a different PHP version.)

The file comments tell you exactly what needs to be done:

# Running PHP scripts in user directories is disabled by default
# To re-enable PHP in user directories comment the following lines
# (from <IfModule ...> to </IfModule>.) Do NOT set it to On as it
# prevents .htaccess files from disabling it.
<IfModule mod_userdir.c>
    <Directory /home/*/public_html>
        php_admin_flag engine Off

So go ahead and comment those lines and restart Apache with sudo systemctl restart apache2.

Prepare for your new inhabitants

Make a template for new home dirs

Before creating your new users, you might want to consider creating a base template for their home directories. Since this is a Tilde-like server, users will require a public_html directory. You might also want to include a default index.html, as well as other assets such as documentation.

This is easily done by adding these elements to /etc/skel, which is a special directory in GNU/Linux systems. When a new user is created, the contents of this directory will be copied to the user’s new home directory. We can create a base public_html directory containing a default index.html file:

cd /etc/skel
sudo mkdir public_html
echo "Hello world" | sudo tee public_html/index.html

Feel free to make a more interesting default page for your users!

Create a new user


sudo adduser janedoe

Create new users in bulk from a CSV file

In a teaching context, you’ll have many users to add at once. It’s boring – and thankfully unnecessary – to create all of them by hand. We can store their information in a CSV file that we can then feed the server to create all users at once.

For this to work, you’ll need to install the csvkit package to read from CSV.

sudo apt install csvkit

Create a CSV file named accounts.csv containing columns named username and password (it can have more fields, but these are the ones we need). After filling it with your username and password combinations, just run:

csvcut accounts.csv -c username,password | tail -n +2 | sed 's/,/:/; s/$/:::::/' > users.txt
sudo newusers < users.txt
rm users.txt

Be sure to block other users from reading accounts.csv by changing its permissions:

chmod go-rw accounts.csv

[source for the bulk addition method]

Change a user’s password if they lost it

Another simple task; you won’t need their current password to be able to change it.

sudo passwd janedoe

Improvements and useful tweaks

Enable HTTPS with Let’s Encrypt

It’s now fast and simple to get HTTPS running on your server with the Let’s Encrypt initiative.

sudo apt-get install certbot python-certbot-apache
sudo certbot --apache

And follow the onscreen prompts to set up Apache with your new SSL certificates. Make sure you select the option to redirect all HTTP traffic to HTTPS!

Remove www. from URLs

Edit the /etc/apache2/sites-enabled/000-default.conf, which has already been tweaked by Certbot in the previous step. Find the lines

RewriteEngine on
RewriteCond %{SERVER_NAME}
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

and change them to

RewriteEngine on
# Remove www.
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule ^(.*)$$1 [R=301,L]
# Redirect http to https
RewriteCond %{SERVER_NAME}
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

Enable CORS in Apache

While we’re editing Apache config files, we can enable CORS to ensure that server resources can be accessed from other sites. This will allow for easy loading of assets such as fonts from other domains. We use this to be able to have JSbin code demos load their fonts from our server.

We just need to edit /etc/apache2/sites-enabled/000-default-le-ssl.conf (note that this is a different file from the previous example). Add these lines right before the </VirtualHost> line:

# Enable CORS
Header set Access-Control-Allow-Origin "*"

Finally, run

sudo a2enmod headers
sudo systemctl restart apache

Set up fail2ban to fend off attacks

Once your server is up and the domain is live, you’ll begin to get visits from worms, bots and the occasional novice cracker, who are constantly scanning the web for new servers. Raspberry Pis are a more visible target since they’re often connected to the Internet without changing the default configuration.

Try checking your server log for failed login attempts to get a clue of what’s coming at you:

cat /var/log/auth.log | grep Failed

Thankfully, we dealt with the most common attacks by deactivating the root and pi users, but the knocks on your door will keep coming until you put up a way to ban repeat login failures. This is what the fail2ban tool is really good at. It reads server logs and detects IP addresses which are trying to connect repeatedly, banning them according to the rules you set up.

Start by installing fail2ban and fetching our own config file that we built for our server. It contains sensible values and applications to monitor; be sure to take a look at that file and tweak it if needed.

sudo apt install fail2ban
sudo mv jail.local /etc/fail2ban

Now confirm that your configuration is okay with

fail2ban-server --test

And if you get no errors, go ahead and start the server. It will run at startup after you reboot too.

sudo systemctl start fail2ban

Whitelisting IP’s

You will need to ensure that you or your students don’t get blocked out accidentally by an overzealous fail2ban. This can easily happen when many people on the same school network are trying to log in. The solution for this is whitelisting, which you can set in /etc/fail2ban/jail.local:

ignoreip =

Replace by your school’s (or home) IP address, and use spaces as a separator if you want to set more than one address. Once you’re done, run sudo systemctl restart fail2ban to reload fail2ban’s configuration.

What now?

Your Tilde server is now in good shape – it’s time to have fun with it (if you haven’t already). Some ideas:


Our notes for sections that remain to be written.


This text by Ana Isabel Carvalho and Ricardo Lafuente is released under a Creative Commons-Attribution license.