Added a structured “add functionality in layers” section (publishing, communication, collaboration, culture) plus a first-week launch checklist to help new operators grow safely and intentionally. Updated README.md with a clear “start here” section that points operators to the key docs for creating and extending a tilde host. Updated docs/shellserver.md to point at the new setup guide and introduced a concise “quick priorities” list for new admins.
10 KiB
Build your own tilde-style server (beginner-friendly, step-by-step)
This guide is intentionally detailed for first-time operators.
If you have never run a server before, follow this in order and do not skip ahead.
What you are building
A "tilde-style" host usually provides:
- A Linux shell account for each user
- Personal web publishing from
~/public_html - Shared Unix tools for learning, writing, coding, and socializing
- Community norms and moderation
In short: a small, friendly, multi-user Unix community.
0) Before you touch a server
0.1 Buy or prepare these things first
- A domain name (example:
domain.club) - One Linux server (VPS is fine)
- SSH client on your laptop
- A text editor you can use comfortably
0.2 Keep this safety rule in mind
Never close your current SSH session until you have confirmed a new SSH session works with your latest config changes.
This one habit prevents most accidental lockouts.
1) Provision your Linux server
You can use AWS, Hetzner, Linode, DigitalOcean, or any other provider.
Recommended minimum for a small starter community
- 2 vCPU
- 4 GB RAM
- 40 GB SSD
- Ubuntu LTS or Debian stable (easiest for beginners)
1.1 Point DNS at your server
At your DNS provider:
- Create an
Arecord fordomain.club-> your server IPv4 - Optionally create
AAAAfor IPv6
DNS can take time to propagate.
1.2 First login
From your local machine:
ssh root@domain.club
If your provider uses a default admin user (for example ubuntu), use that user and sudo.
2) Base system setup (packages, hostname, firewall)
This section includes both Debian/Ubuntu and Red Hat-family commands.
2.1 Update the system
Debian / Ubuntu
apt update
apt -y upgrade
RHEL / Rocky / Alma / Fedora
dnf -y upgrade
2.2 Install baseline tools
Debian / Ubuntu
apt -y install sudo git curl wget rsync tmux htop vim nano tree jq ufw
RHEL / Rocky / Alma / Fedora
dnf -y install sudo git curl wget rsync tmux htop vim nano tree jq
2.3 Set hostname
hostnamectl set-hostname domain.club
Check:
hostnamectl
2.4 Configure a basic firewall
If using ufw (common on Ubuntu):
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
ufw status verbose
If using firewalld (common on RHEL-family):
systemctl enable --now firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
firewall-cmd --list-services
3) Create a non-root admin account
Running daily admin tasks as root is risky.
3.1 Create admin user
adduser admin
On some distros:
useradd -m -s /bin/bash admin
passwd admin
3.2 Give sudo privileges
Debian / Ubuntu
usermod -aG sudo admin
RHEL-family
usermod -aG wheel admin
3.3 Test sudo
su - admin
sudo whoami
Expected output: root
4) SSH hardening (safe order, no lockouts)
Do this carefully.
4.1 Set up admin SSH key directory and file
install -d -m 700 /home/admin/.ssh
install -m 600 /dev/null /home/admin/.ssh/authorized_keys
chown -R admin:admin /home/admin/.ssh
4.2 Add your public key
On your local machine, show your public key:
cat ~/.ssh/id_ed25519.pub
Copy that line and paste it into:
/home/admin/.ssh/authorized_keys
Example on server:
printf '%s\n' 'ssh-ed25519 AAAA... your-key-comment' >> /home/admin/.ssh/authorized_keys
chown admin:admin /home/admin/.ssh/authorized_keys
chmod 600 /home/admin/.ssh/authorized_keys
4.3 Keep passwords ON while you test keys
Edit /etc/ssh/sshd_config:
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication yes
ChallengeResponseAuthentication no
UsePAM yes
Reload:
systemctl reload sshd
From a second local terminal, test login:
ssh admin@domain.club
If this fails, fix it now. Do not continue.
4.4 Disable password auth only after key login works
Edit /etc/ssh/sshd_config:
PasswordAuthentication no
Reload and test again from a second terminal:
systemctl reload sshd
ssh admin@domain.club
Only after success should you end your old session.
5) Install and configure Apache for user pages
This is the baseline many tilde hosts use for ~username pages.
5.1 Install Apache
Debian / Ubuntu
apt -y install apache2
systemctl enable --now apache2
RHEL-family
dnf -y install httpd
systemctl enable --now httpd
Check service status:
systemctl status apache2 --no-pager
# or
systemctl status httpd --no-pager
5.2 Enable user directories (~username URLs)
Debian / Ubuntu
a2enmod userdir
systemctl restart apache2
By default, this serves /home/USERNAME/public_html as:
http://domain.club/~USERNAME/
RHEL-family
Edit Apache config (often /etc/httpd/conf/httpd.conf) and ensure:
UserDir public_html
<Directory /home/*/public_html>
AllowOverride All
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
Require method GET POST OPTIONS
</Directory>
Then restart:
systemctl restart httpd
5.3 Create a test web user and page
useradd -m -s /bin/bash testuser
mkdir -p /home/testuser/public_html
cat > /home/testuser/public_html/index.html <<'HTML'
<!doctype html>
<html>
<head><meta charset="utf-8"><title>testuser page</title></head>
<body><h1>hello from testuser</h1></body>
</html>
HTML
chown -R testuser:testuser /home/testuser
chmod 755 /home/testuser
chmod 755 /home/testuser/public_html
chmod 644 /home/testuser/public_html/index.html
Now test locally on the server:
curl -I http://localhost/~testuser/
curl http://localhost/~testuser/
Then test from your laptop:
curl -I http://domain.club/~testuser/
If it fails, check Apache logs:
Debian / Ubuntu
tail -n 100 /var/log/apache2/error.log
RHEL-family
tail -n 100 /var/log/httpd/error_log
6) Prepare /etc/skel before inviting users
/etc/skel is copied into every new account. Set it up early.
6.1 Minimum recommended contents
.bashrcand/or.zshrcwith helpful commentspublic_html/index.htmlstarter page- A README with first commands and local rules
- Optional
public_gemini/andpublic_gopher/
6.2 Example starter files
install -d -m 755 /etc/skel/public_html
cat > /etc/skel/public_html/index.html <<'HTML'
<!doctype html>
<html>
<head><meta charset="utf-8"><title>Welcome</title></head>
<body>
<h1>It works!</h1>
<p>Edit this file to publish your page.</p>
</body>
</html>
HTML
cat > /etc/skel/README-FIRST.txt <<'TXT'
Welcome to the server.
Useful first commands:
- pwd
- ls -la
- nano ~/public_html/index.html
Your web page lives at:
http://domain.club/~YOURUSERNAME/
TXT
See also: docs/etc-skel-permissions.md.
7) Install baseline user tools
Give new users a capable, friendly default toolbox.
Debian / Ubuntu
apt -y install \
zsh fish \
emacs vim nano \
irssi weechat \
mutt alpine \
lynx w3m links \
git build-essential python3 nodejs npm
RHEL-family
dnf -y install \
zsh fish \
emacs vim nano \
irssi weechat \
mutt alpine \
lynx links \
git gcc make python3 nodejs npm
Add or remove packages based on your community.
8) Add users safely and consistently
Use a repeatable checklist every time.
8.1 Account creation checklist
useradd -m -s /bin/bash USERNAME
passwd -l USERNAME
install -d -m 700 /home/USERNAME/.ssh
install -m 600 /dev/null /home/USERNAME/.ssh/authorized_keys
install -d -m 755 /home/USERNAME/public_html
chown -R USERNAME:USERNAME /home/USERNAME
8.2 Add the user's public key
printf '%s\n' 'ssh-ed25519 AAAA... user@device' >> /home/USERNAME/.ssh/authorized_keys
chown USERNAME:USERNAME /home/USERNAME/.ssh/authorized_keys
chmod 600 /home/USERNAME/.ssh/authorized_keys
8.3 Verify login and web publishing
ssh USERNAME@domain.club
curl -I http://domain.club/~USERNAME/
9) Add "tilde functionality" in manageable layers
Do not launch everything on day one.
Layer A: personal publishing
- User web pages in
public_html - Basic HTML templates
- Optional Gemini and Gopher directories
Layer B: communication
- IRC client docs
- Local mail (postfix + local delivery)
- Server bulletin/MOTD updates
Layer C: collaboration
- Shared Git repos
- Local pastebin/snippet service
- Community docs/wiki process
Layer D: culture and learning
- New-user orientation checklist
- Mentoring or office-hours in chat
- Monthly "show your tilde" events
10) Operations, backup, and recovery
10.1 Back up the important data
At minimum, back up:
/home/etc- Web server config (
/etc/apache2or/etc/httpd) - Mail config if used
10.2 Example nightly backup script
Create /usr/local/sbin/backup-tilde.sh:
#!/usr/bin/env bash
set -euo pipefail
DEST=/var/backups/tilde
DATE=$(date +%F)
mkdir -p "$DEST/$DATE"
tar -czf "$DEST/$DATE/home.tgz" /home
tar -czf "$DEST/$DATE/etc.tgz" /etc
Make executable:
chmod 700 /usr/local/sbin/backup-tilde.sh
Run once manually:
/usr/local/sbin/backup-tilde.sh
Then automate with cron or systemd timers.
10.3 Test restore (critical)
A backup is not real until you test restoring at least one file.
11) First-week launch checklist
- DNS points to server
- Firewall allows only intended ports
- Admin key login works from a second terminal
- Password auth disabled only after key validation
- Apache running and
~testuserpage reachable /etc/skeltested by creating a new account- Backup job ran and one restore test passed
- Rules/moderation/contact info published
- At least one backup admin has emergency access
12) Where to continue in this repository
docs/shellserver.mdfor shell host operational notesdocs/etc-skel-permissions.mdfor current skeleton permissionsdocs/ssh.mdfor SSH key onboarding detailsdocs/server.orgfor historical package/setup notes