# Your Data Fortress (A Debian Server)

> Published  Apr 04 2026, last updated Jul 07 2026  
> By Ryan Fleck <hello@this-site> and written without LLMs!  
> Original post at <https://ryanfleck.ca/2026/your-data-fortress/>  
> An article of astonishing quality and insight. Happy Hacking!


Ask yourself this - where is your data? Who owns it? Who uses it? If
you've lived a typical digital life for the past few decades, your
personal information is scattered *everywhere*. The majority is
concentrated in the hands of a small set of megacorporations - Google,
Amazon, Meta, Apple, Palantir, and Microsoft - all riddled with
backdoors and spyware to ensure compliance and pro-social usage.

**Thought crime charges** are now an unfortunate reality, and can even
be applied retroactively even decades later. Even if you are operating
far within the boundaries set by law, your thoughts are your
own, and ought not to be spied on or acted upon.

While the government storing and abusing your data is unavoidable,
(not to mention sharing it with moral busybodies, consultants, and
Palantir,) control can be wrenched back into your own hands. Run a
home server, learn GNU/Linux, run your own platforms, and regain your
privacy and data autonomy today!

<!--more-->

All you need is one or more of these cheerful little boxes:

![](/claw/mini.jpg)

...and a fantastic assortment of interesting tools become available:

1. Replace Office and Google Drive with [NextCloud](https://landchad.net/nextcloud/)
1. Install [SyncThing](https://syncthing.net/) to sync your files between your laptops and phones
1. Replicate WhatsApp/Telegram with an [XMPP](https://landchad.net/prosody/) server
2. Run [e-commerce](https://awesome-selfhosted.net/tags/e-commerce.html) sites with zero overhead
1. Install [OpenClaw]({{< ref "posts/2026/openclaw.md">}}) to burn $200 in LLM tokens ordering $40 of Chinese food
1. Your own `S3`-like distributed object storage with [Garage](https://garagehq.deuxfleurs.fr/)
1. Much more [Awesome Self-Hosted](https://awesome-selfhosted.net/index.html) stuff!

Great advocates of self-hosted freedom like [LandChad.net](https://landchad.net/)
serve to raise awareness about the fantastic number of services that
are deployable by normal people.

> Starting a website is something that can be done in a lazy afternoon
> and costs pocket change. Most of the internet’s problems could be
> solved if more people had their own personal platforms, so the
> objective of this site is to guide any normal person through the
> process of installing a website.
>
> -- Chad

This confident quip does understate the responsibility that comes with
running a website. A glance over the [Securing
Debian](https://www.debian.org/doc/manuals/securing-debian-manual/index.en.html)
manual will prove that quickly. Handling personal data and
particularly the data of others should be taken seriously, and by
reading and applying the techniques in this guide, you will solve
three common security problems, those being:

1. Preventing brute-force login attempts
1. Countering physical intrusion with strong encryption
1. Protecting your own IP with a reverse proxy[^6]

*Come along with me and set up your own encrypted data enclave!*

{{< toc >}}

# Acquire Hardware

The best system for a first personal server is an old desktop or
laptop computer, and if you don't have one, a cheap office surplus
machine with a mid-range processor[^3] will do the trick. If you are
buying a surplus or refurbished computer, think in terms of compute
per watt: generally, a high-spec processor from 15 years ago will
consume much more power per instruction than a mid-spec processor from
five years later which can operate at the same speed.

A VPS from a vendor like
[DigitalOcean](https://m.do.co/c/26e13875f733)[^2] or
[Vultr](https://www.vultr.com/pricing/#cloud-compute) is also a great
option, reducing the upfront cost to zero and providing a huge
networking advantage (you don't need to mess with your router or ISP's
"smart" home networking app to make it available on the web.) The
disadvantage of a VPS is the cost. $6 a month for a shared core or two
is the price of a sandwich[^1], and you'll pay that much for power at
home, but the system you can compose could easily be ten times more
powerful and spacious (in terms of storage and memory.)

The VPS equivalent of a $200 computer would probably cost $80-120 a month
to rent!

In this programmer's opinion, the sweet spot in terms of cost, power
efficiency, ownership, ease of acquisition, and quality would be a
5-10 year old Lenovo ThinkCentre or Dell Optiplex tower. In the age of
crazy memory prices, many of these towers are priced only slightly
higher than the memory contained within if the sticks were to be sold
separately. *Ensure the motherboard has a TPM2 module, which is
crucial to protecting your data.*

Ease of installation and driver support is also great for these
machines. Smaller variants provide greater power efficiency and are
easier to hide in a laundry room or near the router. Larger towers
provide ample room for full-sized SATA hard drives for your large
databases.

Best of all, these business towers can often be found at
city/government auctions for cheap, and due to their reliability,
often need very little work to be at their peak performance!

![A shelf of reliable ThinkCentre "Tiny"-class computers](/claw/machines.jpg)

# Install Debian

If you've provisioned a VPS, this step is done for you.

Otherwise, it's time to grab the [Debian DVD
ISO](https://cdimage.debian.org/debian-cd/current/amd64/iso-dvd/) and
to burn it to a USB key (or even a real physical DVD, if you want to
pretend it's the mid-2000s.) If you'd like, you can compute the
[SHA512 checksum](https://wiki.debian.org/VerifyISOImage) to verify
the authenticity of the downloaded image.

The crucial part:<mark> **Set up encrypted LVM </mark>on your primary drive.**

Make a **really long encryption passphrase** and remember it[^5].

This is tough to fix afterwards and the installer makes it easy. Do
not worry about encrypting your secondary storage drives now, this is
something we will complete together later.

```bash
# Fully upgrade base packages and restart before continuing
> apt update
> apt full-upgrade
> reboot
```

**For local machines** install the following packages:

```bash
# Remote access via SSH and Multicast DNS packages:
> apt install openssh-server avahi-daemon avahi-utils
```

...and reboot. Your machine will now be accessible on your home
network, and can be accessed without knowing the precise IP address
like so:

```bash
# Remote-login to your server:
> ssh -C <your-user>@<hostname>.local

# If you have forgotten the hostname run:
> hostname
```

## Alternatively, Alpine Linux

I have enjoyed stable performance from Alpine Linux for about a
decade, and it offers some security perks over Debian. One of my
systems has been running a rolling alpine install for many years,
making the jump from `3.14` to `3.21` with ease,
though a Postgres install broke during that time. See [this note on using latest-stable Alpine release](https://wiki.alpinelinux.org/wiki/Upgrading_Alpine_Linux_to_a_new_release_branch)
with the `apk` package manager.

```bash
# The /etc/apk/repositories file should appear as follows:
# Contents of /etc/apk/repositories
http://dl-3.alpinelinux.org/alpine/latest-stable/main
http://dl-3.alpinelinux.org/alpine/latest-stable/community
```

**Why Alpine?** It has a drastically reduced attack surface and uses
the `musl` C compiler, leaving far fewer entry points and
vulnerabilities. It's a great alternative to Debian, which itself is a
mature and stable foundation for software deployment.

# Sudo & Password Rotation

It's a simple fix, but obvious -<mark> make sure you have a long, hard password.</mark>

**Sudo** allows you to run elevated commands while logged in as yourself.

```bash
# Install "sudo" and add your user
# As root:
> apt install sudo
> usermod -aG sudo <your-username>
> reboot

# You'll need it rarely, so set a very long root password
# As root:
> su -
> passwd

# Improve your security with a long & random password
# As yourself:
> passwd
```

You'll be able to (mostly) forget this password once we set up SSH keys.

# Basic SSH Security

Before touching or configuring anything else, securing initial access
to your server is critical to preventing all your work from being
wasted by a bot who guessed that your root password was "password" and
was immediately able to steal your environment, crypto, etc.


Generate a SSH key with [these steps]({{< relref "posts/2018/2018-12-27-git-ssh.markdown" >}}).

After logging in to your server touch `~/.ssh/authorized_keys` and use
your editor of choice to append your public key to the file.

```bash
# Edit "~/.ssh/authorized_keys" and add your RSA public key and a note:

# <Your Laptop's Name>
ssh-rsa 8Eq1jcBqaiIt7XwiVnTlZfE1W1k7Kg7I...
```

Prevent the root user from logging in via SSH.

```bash
# Edit "/etc/ssh/sshd_config" and change:
# Disable root login over SSH
PermitRootLogin no

# Disable password auth, or make your password much
# longer and tougher to guess with the "passwd" command
PasswordAuthentication no

# Disable Pluggable Authentication
UsePAM no

# Apply the changes
> systemctl restart sshd
```

Install **fail2ban** to limit brute-force attacks.

```bash
> apt install fail2ban
> cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# Edit "/etc/fail2ban/jail.local" if changes need to be made, then apply:
> systemctl restart fail2ban

# Check the status
> fail2ban-client status
Status
|- Number of jail:      1
`- Jail list:   sshd

# To un-ban an IP
fail2ban-client set sshd unbanip <ip-address>
```

Further reading: ["How To Secure Your New VPS"](https://www.kkyri.com/p/how-to-secure-your-new-vps-a-step-by-step-guide)

# NTP Time Synchronization

This will contact a NTP server to set your system time, and is crucial
for security and validating certificates. For whatever reason, Debian
neglects to set this up on install.

```bash
# Install and run
> apt install systemd-timesyncd
> systemctl enable systemd-timesyncd
> timedatectl set-ntp true

# Check status
> timedatectl status
> systemctl status systemd-timesyncd
```

# Automatic Security Patches

Ensure crucial security patches are applied automatically.

```bash
# Install the package & service
> apt install unattended-upgrades

# Edit "/etc/apt/apt.conf.d/50unattended-upgrades"
# Uncomment & make the following changes:
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "<the best time for you in HH:MM format>";
```


# Automatic Decryption with TPM2

**Full-disk encryption should be your data security baseline**.[^4]
Defense in depth should be applied to all of your personal
electronics, and even your home equipment could be stolen. Encryption
prevents the leaking of sensitive data in the event a device is taken.

This said, *nobody wants to type a long decryption key with every boot!*

Particulary for servers, which are unattended - this is where the TPM
module comes in handy. It can store an additional key allowing the
disk to be decrypted at boot, providing reasonable tamper-resistant
protection. I used [this
guide](https://blog.fernvenue.com/archives/debian-with-luks-and-tpm-auto-decryption/)
primarily when setting mine up. [dracut](https://linux.die.net/man/8/dracut)
is a key tool/package to leverage.

> The following steps are required for both methods. Choose one to your liking.
>
> 1. Add the corresponding dracut module so support is available in the initramfs at boot
> 2. Enroll / bind a LUKS secret slot tied to either the TPM2 or the FIDO key
> 3. Update /etc/crypttab with the new configuration
> 4. Rebuild the initramfs to apply the changes
>
> It is important to run dracut last to not only include new
> dependencies but also your updated crypttab in the initramfs.

```bash
# Install TPM tools and check for disk
> apt install tpm2-tools parted dracut

> systemd-cryptenroll --tpm2-device=list
# PATH         DEVICE      DRIVER
  /dev/tpmrm0  NTC0702:00  tpm_tis

# Check devices
> lsblk
NAME                 MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
nvme0n1              259:0    0 119.2G  0 disk
├─nvme0n1p1          259:1    0   976M  0 part  /boot/efi
├─nvme0n1p2          259:2    0   977M  0 part  /boot
└─nvme0n1p3          259:3    0 117.3G  0 part
  └─nvme0n1p3_crypt  254:0    0 117.3G  0 crypt
    ├─P04--vg-root   254:1    0 113.5G  0 lvm   /
    └─P04--vg-swap_1 254:2    0   3.8G  0 lvm   [SWAP]

# EXAMPLE (The device is nvme0n1p3)
> systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 /dev/nvme0n1p3

# Use "dracut" to automatically use tpm2 to unlock your encrypted drives
# Edit /etc/dracut.conf.d/tpm.conf and add this line:
add_dracutmodules+=" tpm2-tss crypt "

# Important: Disable Systemd crypttab
# Prevent double-initialization of the drive
# Comment out this line in /etc/crypttab:
nvme0n1p3_crypt UUID=****-****-**** none luks,discard

# Edit /etc/default/grub and modify this line, adding the arguments:
GRUB_CMDLINE_LINUX="rd.auto rd.luks=1"

# Apply Changes (Crucial)
> dracut -f
> update-grub
> reboot

# Ensure everything is working fine and no errors are raised
> journalctl -b | grep cryptsetup
```

**Resources**:

1. https://www.jwiltshire.org.uk/2025/01/07/using-tpm-for-automatic-disk-decryption-in-debian-12/
2. https://bugs.launchpad.net/ubuntu/+source/systemd/+bug/2001556
3. https://blog.fernvenue.com/archives/debian-with-luks-and-tpm-auto-decryption/
4. https://community.frame.work/t/guide-setup-tpm2-autodecrypt/39005
5. https://fedoramagazine.org/use-systemd-cryptenroll-with-fido-u2f-or-tpm2-to-decrypt-your-disk/
6. https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/


# Encrypt Additional Drives


After attaching the drives

```bash
# Identify the new/target hard disk
> lsblk
NAME                                          MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
sda                                             8:0    0   3.6T  0 disk
└─sda1                                          8:1    0   3.6T  0 part
nvme0n1                                       259:0    0 476.9G  0 disk
├─nvme0n1p1                                   259:1    0   976M  0 part  /boot/efi
├─nvme0n1p2                                   259:2    0   977M  0 part  /boot
└─nvme0n1p3                                   259:3    0   475G  0 part
  └─luks-0e70ec89-c8e3-433c-bbce-f5b095124e27 254:0    0   475G  0 crypt
    ├─STC01--vg-root                          254:1    0 459.1G  0 lvm   /
    └─STC01--vg-swap_1                        254:2    0  15.8G  0 lvm   [SWAP]

# Check current partitions on SDA
> parted -s /dev/sda print all
Model: ATA WDC WD4003FZEX-0 (scsi)
Disk /dev/sda: 4001GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:

Number  Start   End     Size    File system  Name               Flags
 1      1049kB  4001GB  4001GB  ext4         WD Black 4TB Data
 #                      ^^ It's one big EXT4 partition
```

We'll start from scratch assuming there is data on the drive to be cleared.

**WARNING:** The following commands will cause **irreversible data loss**.

```bash
# Erase the partition table
sfdisk --delete /dev/sda

# Set up a GPT partition table
parted -s /dev/sda mklabel gpt
parted -s /dev/sda mkpart primary 0% 100%

# Encrypt the drive with LUKS
cryptsetup luksFormat /dev/sda1

# Open the encrypted drive
cryptsetup open /dev/sda1 data1
ls /dev/mapper

# Make a filesystem on the drive with label "data"
mkfs.ext4 -L data /dev/mapper/data1

# Mount the drive to "/data"
mkdir -p /data
mount /dev/mapper/data1 /data

# Create a Read/Write/Execute superuser group "data-rwx" for the disk
groupadd data-rwx
usermod -aG data-rwx r  # add yourself
getent group data-rwx   # check the group

# Change ownership and permissions
chgrp -R data-rwx /data
chmod -R g+rwx /data
chmod g+s /data        # ensure future files use this group

> systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 /dev/sda1
# ...new TPM2 token enrolled as key slot 1.

# Apply these changes
dracut -f
update grub
reboot

# Check the UUID of your disk
> blkid
# "blkid" output with mapped name, uuid, label, etc.:
  /dev/mapper/luks-799aee84-106f-47f3-801c-d1ce58224d0f: LABEL="data"
    UUID="207d11ba-ec71-483a-9f52-13af040c3b60" BLOCK_SIZE="4096" TYPE="ext4"

# Ensure the drive is mounted when the system starts
# Edit "/etc/fstab" and add this line
UUID=207d11ba-ec71-483a-9f52-13af040c3b60  /data  ext4  defaults,noatime,nofail  0  2

# You can also add this to the options, but it may be better to fail visibly:
errors=remount-ro

# Reload Systemd to apply the filesystem tab and check the mount point:
> systemctl daemon-reexec
> findmnt /data
TARGET SOURCE                                                FSTYPE OPTIONS
/data  /dev/mapper/luks-799aee84-106f-47f3-801c-d1ce58224d0f ext4   rw,noatime

# Apply Changes & Reboot
> dracut -f
> update-grub
> reboot

# Ensure everything is working fine and no errors are raised
> journalctl -b | grep cryptsetup
```


**Resources**:

1. https://forums.debian.net/viewtopic.php?t=138035
1. https://medium.com/@allypetitt/how-to-encrypt-a-drive-in-linux-83b3001744f4
1. https://opensource.com/article/21/3/encryption-luks


# UFW Firewall

```bash
# Install and temporarily stop the firewall
> apt install ufw
> ufw disable

# List available services
> ufw app list

# Allow OpenSSH and all outgoing connections
> ufw allow OpenSSH
> ufw default deny incoming
> ufw default allow outgoing

# If you are using Nginx as a reverse proxy
> ufw allow 'Nginx Full'

# Stand up the firewall
> ufw enable

# Check the status
> ufw status verbose
```

# Nmap Scanning Your Server

For fun, you can use **Nmap** to check your server for weak points.

You'll need to use an external machine to perform this task.

```bash
# Pick a target, ensure your server is up:
> ping <server-hostname>.local
> ping <your server's IP address>

# Run NMap scripts to check for vulnerabilities
> sudo nmap -sV --script "vuln" <your-server-address>
```

Further reading: ["Vulnerability Scanning with Nmap"](https://www.blackhillsinfosec.com/vulnerability-scanning-with-nmap/)

# Install Docker

Follow the official [Install Docker on Debian](https://docs.docker.com/engine/install/debian/#install-using-the-repository)
guide.

```bash
# Remove existing Docker packages, if any:
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-doc podman-docker containerd runc | cut -f1)

# Add Docker's official GPG key:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

# Update your lists
sudo apt update

# Install Docker & Compose
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Check Engine Status
sudo systemctl status docker
```

Excellent, you are now ready to deploy stuff!
To finish up, follow the [log rotation](https://docs.docker.com/engine/logging/drivers/json-file/)
guide to protect your disk space. Edit `/etc/docker/daemon.json` and add:

```json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "5"
  }
}
```

# Connecting To Your Server

If you have set up a VPS, the hard work of networking is done - you
can add your `ipV4` address in your DNS control panel, and your domain
is now connected to your machine! You can proceed to setup [nginx](https://nginx.org/) and
web services.

For a home server, a choice must be made, and all three paths have compromises:

1. **Use DDNS** to keep your domain name pointed towards your home IP
   address, best if you are cheap and are only using this personally
   and deploying services for friends. Directly exposes your IP.
2. **Proxy your traffic through Cloudflare** and gain DDOS protection and
   a strong security layer, at the cost of having your packets
   decrypted and scanned, best overall option.
3. **Pay or beg your ISP for a static IP address**, which could be the
   most expensive option, but is certainly the best if
4. **TailScale funnel**[^7] or **Cloudflare tunnels**[^8] are a
   convenient option but require a client to be installed, a potential
   point of compromise and a direct intrusion into your secure
   enclave.

This choice is largely dependent on the number of users you are
planning to have. Option two, particularly with Cloudflare tunnels, is
also highly convenient.

## Fast: NoIP Dynamic DNS & Router

This method updates DNS records to direct traffic directly to your
home router, which will forward that traffic to your server. **This
will expose your home IP to internet traffic.**

The fastest, simple, cheap, bare-metal approach to networking is to
convince your ISP to give you a static IP (maybe not free, and
typically reserved for business-tier networking) or to use a dynamic
DNS service to keep your DNS correctly set to your home IP address as
it is changed regularly by the ISP. You'll need to fiddle with **port
forwarding** too, ensuring ports `80` and `443` are both sent to your
server. For this method in particular, ensure your router is up to
date and your firewalls are up.

[No-IP](https://www.noip.com/) offers a [Docker
container](https://github.com/noipcom/linux-update-client-docker/pkgs/container/noip-duc)
to continuously ensure your dynamic IP is correctly set at the DNS
level. You can set up a **free subdomain** that will point to your
machine. This is great for newbies looking to give networking a try,
but not a reliable long-term solution for deploying a service.

Create a new `docker-compose.yml` to hold your container definition:

```yaml
services:
  noip-duc:
    image: ghcr.io/noipcom/noip-duc:latest
    container_name: noip-duc
    restart: unless-stopped
    env_file:
      - noip.env
```

Corresponding `noip.env` file, holding your credentials:

```env
NOIP_USERNAME=supremehacker7
NOIP_PASSWORD=2lj3sd8fj...
NOIP_HOSTNAMES=supremehacker.ddns.net
```

If your port forwards are correct, your machine will now serve traffic to the
domain name you set up at [No-IP.com](https://www.noip.com/)!


## Safe: Proxy Traffic via Cloudflare & Router

This method will proxy traffic from the internet through Cloudflare,
through your router, and to your server. This is a good
middle-of-the-road option, concealing your home IP address while still
running the traffic "directly" to your machine.

Cloudflare's core business model is providing DDOS protection and
monitoring traffic for enterprise customers. Cloudflare will be able
to see and interpret your traffic, which would only be critical if you
were a threat to the American security establishment.

Adding this container in one of your compose files will start a
service to keep your home IP address up to date in Cloudflare,
ensuring that your port-forwards on `80` and `443` from your router
can be found via DNS on the open web. A DNS-only **A**-type record will be added
to your DNS control panel with the address.

```yaml
  cloudflare-ddns:
    image: oznu/cloudflare-ddns:latest
    restart: always
    environment:
      - API_KEY=8SDFks8f
      - ZONE=yoursite.com
      - SUBDOMAIN=secretlab-entry-point
      - PROXIED=false
      # ^^ Set TRUE if you only plan to use 80/443 directly
      #    For minecraft, to use other ports, or to use many subdomains, leave off.
```

After this is set up, you can add many **CNAME**-type records with fun
subdomain names and the hostname content set to
"`secretlab-entry-point.yoursite.com`", causing the traffic to be forwarded to
your preferred reverse proxy on your server.

*Note - this container is archived, I'll check out [favonia/cloudflare-ddns](https://github.com/favonia/cloudflare-ddns)
which continues to be supported, and update if it's any good.*

## Easy: Cloudflare Tunnel / Tailscale Funnel

This method will shuttle incoming traffic through a secure *outbound*
tunnel to Cloudflare's network. No port forwarding is required, and
this setup works wonderfully behind firewalls. You'll pay in latency,
throughput, and privacy.

**A very similar approach can be taken using [tailscale](https://tailscale.com/docs/features/containers/docker/how-to/connect-docker-container)
if that's your jam,** but I personally haven't proven this out. A guide can be found [here](https://tailscale.com/blog/docker-tailscale-guide).

Though this method is not my favorite security-wise, it is extremely
resilient. Your machine can sit anywhere and still serve a reliable
service to [many users](https://developers.cloudflare.com/learning-paths/replace-vpn/connect-private-network/tunnel-capacity/).
I would avoid directly installing `cloudflared` on your server and instead use a
docker container to provide the connectivity directly to your service.

```yaml
services:

  # A sample service to expose via the Cloudflare tunnel
  hello-world:
    image: ghcr.io/kljensen/hello-world-http:latest
    ports:
      - "80:8000"
    environment:
      HOST: 0.0.0.0
      PORT: 8000

  # The tunnel that will
  tunnel:
    container_name: cloudflared-tunnel
    image: cloudflare/cloudflared
    restart: unless-stopped
    command: tunnel run
    depends_on:
      - hello-world
    environment:
      - TUNNEL_TOKEN=sd8sf... <insert your tunnel token here>
```

Once this is running, jump back into Cloudflare and:

- Add a published application route
- For the service url, use the **container name** and **internal port**, not the
  port exposed on the machine's local network
- Click **Save changes** and your service should be available!

![](/pics/cloudflared-edit.png)

Further reading: ["Cloudflare Zero Trust Tunnels"](https://david.coffee/cloudflare-zero-trust-tunnels/)

# Other Handy Steps

```bash
# Remove desktop environment
> apt-get purge $(tasksel --task-packages desktop)

# Ensure your system is in "server mode" aka multi-user target
> systemctl set-default multi-user.target
```

# Conclusion & Next Steps

You've set up and secured your server - congratulations!
You can now browse the interesting services available on
[LandChad](https://landchad.net/) and [Awesome
Self-Hosted](https://awesome-selfhosted.net/index.html)
to begin building your digital enclave.

**Take backups.** No system is bulletproof. Regularly copy critical
data off-site, and don't assume that your hard disks will run until
the end of time.

Enjoy, and *happy hacking!*

***R***


<!-- Refs -->

[^1]: There are great free VPS tiers from
    [Oracle](https://www.oracle.com/ca-en/cloud/free/) with AMD and
    ARM cores, but **you pay with your soul**, and it has some usage
    [limitations](https://www.reddit.com/r/selfhosted/comments/1ma6jbt/does_oracle_cloud_free_tier_have_any_gotchas_or/)
    that could lead to an inconsistently available service.

[^2]: This is a [DigitalOcean affiliate
    link](https://m.do.co/c/26e13875f733). By signing up after and
    spending $25, I'll get a $25 credit. Even with much of my
    infrastructure deployed 'on-premises', I spend a lot on cloud
    compute, and this would help me cut down my costs!

[^3]: At the time of writing a refurbised Lenovo ThinkCentre M710q
    Tiny (Intel Core i5-7th gen Processor, 16GB DDR4, 256GB SSD) is
    $277.99 CAD on
    [amazon.ca](https://www.amazon.ca/Lenovo-ThinkCentre-M710q-Tiny-Processor/dp/B0CTMQ5Y9Z).

[^4]: Quote from "Disk Encryption: An Authoritative Guide for Linux Users", [linuxsecurity.com](https://linuxsecurity.com/features/authoritative-guide-on-linux-disk-encryption)

[^5]: Or write it and keep it with your bitcoin.

[^6]: https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/

[^7]: https://tailscale.com/docs/features/tailscale-funnel#how-funnel-works

[^8]: https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/



> Thank you for reading!  
> Find more content at <https://ryanfleck.ca/>  
> Source page: <https://ryanfleck.ca/2026/your-data-fortress/>  
> Site index: [llms.txt](https://ryanfleck.ca/llms.txt)