Building a Self-Hosted Family Digital Estate with Windows, Docker, Immich, Forgejo, Kopia and Homepage

I have been gradually turning a Windows machine at home into something more useful than a server running a collection of unrelated containers (See my previous blog post here: Building a Self-Hosted GitHub Mirror and Disaster-Recovery Backup with Forgejo, Kopia, Docker Desktop and Windows).

The goal is broader than a conventional homelab.

I want a family digital estate: a system that protects our photos, source code, documents and computers; provides simple applications that my family can actually use; monitors itself; and can eventually be understood and recovered by someone other than me.

The current platform now includes:

  • Immich for our family photo and video archive
  • Forgejo as a local mirror of my GitHub repositories
  • Kopia for encrypted, versioned backups
  • Veeam Agent for bare-metal Windows recovery
  • Homepage as the central dashboard
  • Uptime Kuma for availability monitoring
  • Beszel for host resource monitoring
  • Dozzle for Docker logs
  • EasyTimesheets and DiaryBot as existing applications
  • a nightly E: → F: storage mirror
  • Docker Desktop and WSL2 as the application platform

There is still more to add — Paperless-ngx for family documents, BookStack for a family handbook, Tailscale for remote access and eventually an off-site backup — but the foundation is now functioning well enough that it is worth documenting.


The Design Principle

The most important architectural decision was that applications should not own my data.

Photos should remain photos.

Documents should remain ordinary files.

Git repositories should remain Git repositories.

Backups should be independently recoverable.

Applications such as Immich, Forgejo or Paperless are interfaces and indexes around the data. They are valuable, but they should be replaceable.

My preferred model is therefore:

Original data
    │
    ├── normal filesystem
    │
    ├── readable without the application
    │
    └── independently backed up
            │
            ▼
     application/index layer

That is very different from putting everything inside opaque Docker volumes and hoping the application database never breaks.


Overall Architecture

At the moment, the system looks roughly like this:

Conceptually there are four layers:

Family data
      ↓
Applications
      ↓
Monitoring / operations
      ↓
Backup / disaster recovery

The Hardware and Storage Layout

The server runs Windows with Docker Desktop and WSL2.

I deliberately kept Windows as the host rather than rebuilding the machine around Linux because it also performs other Windows-specific duties and because I already have a substantial amount of locally attached storage.

The main storage currently looks approximately like this:

DrivePurpose
C:Windows, Docker Desktop and application infrastructure
D:Smaller backup/storage volume
E:Main large data volume
F:Mirror of E:
G:Additional storage
H:Additional storage

The key relationship is:

E: = primary data
F: = nightly exact mirror

For example:

E:\
├── 01 - Photos
├── Immich
├── FamilyBackup
├── SystemBackups
└── ...

That gives me one simple operational rule:

E: is the master. F: is a second local copy.

The mirror is not itself a versioned backup because accidental deletion on E: can also propagate to F:. Versioning is handled separately where appropriate by systems such as Kopia.


Networking

The server has a reserved LAN address:

192.168.1.239

That turned out to be more important than I initially expected.

Docker Desktop provides the special hostname:

host.docker.internal

which is useful for communication between containers and Windows.

However, I discovered that during some Docker Desktop restarts its internal DNS/networking layer can temporarily fail with errors such as:

getaddrinfo EAI_AGAIN host.docker.internal

For long-lived monitoring links, I therefore prefer the server's fixed LAN IP where practical:

http://192.168.1.239:2283
http://192.168.1.239:3000
http://192.168.1.239:3005

No general-purpose router port forwarding is used.

Remote access will eventually be provided through Tailscale rather than exposing these services directly to the Internet.


Immich: The Family Photo Archive

Immich is probably the application that makes the server most immediately useful to the rest of the family.

The historical photo archive already existed at:

E:\01 - Photos

I did not want Immich to reorganise or take ownership of that archive.

Instead, I configured it as a read-only external library.

The architecture is:

E:\01 - Photos
       │
       │ read-only
       ▼
     Immich

New uploads handled by Immich are stored separately:

E:\Immich\Managed

So Immich has two distinct storage roles:

Historical archive
E:\01 - Photos
READ ONLY
        │
        ▼
      Immich

New managed uploads
E:\Immich\Managed
READ / WRITE

This separation is important.

If I ever decide to stop using Immich, the historical archive remains completely ordinary and untouched.


Docker Desktop and Large Windows Drives

This part became surprisingly interesting.

My first instinct was simply to bind-mount the Windows drive into Docker:

volumes:
  - E:/01 - Photos:/external/photos:ro

But Docker Desktop behaved incorrectly with this particular large drive.

Inside the container, Docker exposed something that looked like a tiny filesystem instead of the real multi-terabyte Windows volume.

Marker files created on the real E: drive were invisible inside Docker.

A write test also failed after only a small amount of data.

Rather than fighting Docker Desktop's Windows-drive translation layer, I bypassed it completely.


SMB as a Windows-to-Docker Storage Bridge

I created dedicated Windows SMB shares and mounted them into Docker as CIFS volumes.

For Immich:

Windows
E:\01 - Photos
      ↓
SMB share
ImmichExternalPhotos
      ↓
Docker CIFS volume
      ↓
/external/photos

And:

Windows
E:\Immich\Managed
      ↓
SMB share
ImmichManaged
      ↓
Docker CIFS volume
      ↓
Immich

A dedicated Windows account is used for the share permissions rather than granting broad access.

The external photo archive has read-only permissions.

The managed Immich area has write permissions.

This turned out to be substantially more reliable than direct Docker Desktop bind mounts for these drives.


Immich Database Placement

I did not put PostgreSQL on NTFS or SMB.

The Immich PostgreSQL database remains in a Docker-managed Linux volume.

That produces an important split:

Large media
→ Windows NTFS / SMB

Database
→ Docker Linux volume

This gives PostgreSQL the filesystem semantics it expects while allowing terabytes of media to remain on normal Windows storage.


Initial Immich Indexing

Once the external library was added, Immich began scanning years of photos and videos.

During the initial import it was quite resource hungry.

That is expected because Immich may simultaneously be doing:

metadata extraction
thumbnail generation
video processing
face processing
machine-learning jobs
database indexing

After the initial processing completes, the system should settle considerably.

Because the external library is a network-mounted SMB filesystem from the container's perspective, I do not rely solely on filesystem watchers.

Instead I can run periodic library scans.

That means I can continue manually adding files to:

E:\01 - Photos

and Immich discovers them during its next scan.


Forgejo: A Local GitHub Mirror

The next major part of the digital estate is source code.

GitHub remains the primary development platform.

I did not want to change my normal workflow.

The topology is:

Development machines
        │
        ▼
      GitHub
        │
        ▼
 Forgejo pull mirrors
        │
        ▼
      Kopia

Forgejo therefore acts as a local read-only replica, not as the canonical Git server.


Automated Repository Mirroring

I built a small synchronisation service that queries GitHub and compares the result with Forgejo.

It:

  • includes repositories owned by my GitHub account
  • includes private repositories
  • includes archived repositories
  • includes forks I own
  • ignores employer or organisation repositories that I do not own
  • creates missing Forgejo mirrors
  • does not automatically delete existing mirrors

The first run discovered:

358 GitHub repositories

and successfully created local mirrors.

The entire repository set consumed only around:

6 GB

which is trivial relative to the available storage.


What Git Mirroring Does Not Back Up

A Git mirror is extremely useful, but it is not a complete GitHub backup.

It preserves Git data:

commits
branches
tags
history

It does not automatically preserve everything associated with GitHub itself, including things such as:

Issues
Pull Requests
Discussions
Actions artefacts
some release assets
repository settings
secrets
packages

That distinction matters.

Forgejo provides excellent source-code resilience, but GitHub metadata would require additional export mechanisms if I wanted a truly complete archive.


Kopia: Versioned Backup for Forgejo

Forgejo itself then needs backup protection.

I chose Kopia because it provides:

encryption
deduplication
versioning
retention policies
repository validation
snapshot verification

The repository currently lives under:

E:\FamilyBackup\Kopia\HomeServer

Once again I encountered the Docker Desktop large-drive issue, so the repository is exposed through SMB/CIFS rather than a direct E: bind mount.


Creating a Consistent Forgejo Backup

Forgejo uses SQLite in my current deployment.

Simply backing up the live Docker volume while the database is being written to is not ideal.

Instead the process is:

Stop Forgejo briefly
        ↓
TAR the complete Docker volume
        ↓
Restart Forgejo immediately
        ↓
Kopia snapshots the TAR
        ↓
Kopia snapshots configuration
        ↓
Delete temporary TAR

The resulting downtime is short, while the snapshot represents a consistent application state.


Backup Retention

Kopia is configured with a fairly generous retention policy:

Latest:   10
Hourly:   24
Daily:    30
Weekly:   12
Monthly:  24
Annual:   10

Storage is inexpensive compared with discovering several months later that the only usable backup was automatically deleted.


Actually Testing the Backup

A backup that has never been restored is only a theory.

I therefore performed a full recovery test.

The process was:

Kopia snapshot verification
        ↓
100% file-data verification
        ↓
Restore Forgejo TAR
        ↓
Create temporary Docker volume
        ↓
Extract restored TAR
        ↓
Start temporary Forgejo instance
        ↓
Open repository in browser

The restored instance contained all:

358 repositories

and successfully booted from the restored SQLite database.

I could browse actual source files and commit history.

That test is far more valuable than seeing:

Backup completed successfully

in a log.


Veeam: Bare-Metal Recovery

Application backups do not solve the problem of the Windows system SSD failing.

For that I use Veeam Agent for Windows.

The objective is simple:

SSD fails
   ↓
replace SSD
   ↓
boot Veeam Recovery Media
   ↓
select latest system image
   ↓
Bare Metal Recovery
   ↓
Windows + Docker + applications restored

The important distinction is that Veeam Recovery Media is only the boot environment.

The actual machine state lives in the Entire Computer backup.

The home-server Veeam job therefore protects the system/EFI/recovery partitions and Windows SSD.

Large external data disks are not part of the machine image because they have their own storage and backup strategy.


E: to F: Nightly Mirror

For many years I maintained secondary disk copies manually.

I decided to formalise that process using Robocopy.

The relationship is intentionally:

E: MASTER
   ↓
F: MIRROR

The job uses:

/MIR

because I specifically want F: to be an exact mirror of E:.

A simplified version looks like:

robocopy E:\ F:\ `
    /MIR `
    /COPY:DATS `
    /DCOPY:DAT `
    /ZB `
    /XJ `
    /R:3 `
    /W:5 `
    /MT:16

System directories such as these are excluded:

System Volume Information
$RECYCLE.BIN

Robocopy return values also need to be handled carefully.

Values from:

0–7

can indicate successful operations or acceptable differences.

Values:

8+

represent failures.

That matters when integrating Robocopy with Task Scheduler and monitoring.


Homepage: Turning Everything into One System

The biggest usability improvement came from installing Homepage.

Before Homepage, the environment consisted of a growing collection of ports:

:2283
:3000
:3005
:3006
:8080
:8088
:8090
...

That is manageable for the person who built it.

It is not a pleasant user interface.

Homepage changes that.

The main portal is:

http://192.168.1.239:3005

and becomes the front door to the environment.


Current Homepage Structure

The dashboard is organised conceptually into:

Family
Development
Applications
Infrastructure

For example:

FAMILY
┌────────────────────┐
│ Immich             │
│ Photos and videos  │
└────────────────────┘

DEVELOPMENT
┌────────────────────┐
│ Forgejo            │
│ GitHub mirrors     │
└────────────────────┘

APPLICATIONS
┌────────────────────┐
│ EasyTimesheets     │
└────────────────────┘

┌────────────────────┐
│ DiaryBot           │
└────────────────────┘

INFRASTRUCTURE
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Kuma       │ │ Beszel     │ │ Dozzle     │
└────────────┘ └────────────┘ └────────────┘

The difference is surprisingly significant.

Instead of asking:

What port was Beszel on?

I simply open the home portal.


Secure Docker Integration

Homepage can query Docker to display container status and resource information.

I did not want to give the Homepage container unrestricted access to:

/var/run/docker.sock

because Docker socket access is effectively administrative access to the host's container environment.

Instead I introduced:

docker-socket-proxy

Homepage communicates with that proxy.

The proxy permits only the API operations Homepage needs.

Conceptually:

Homepage
    │
    ▼
Docker Socket Proxy
    │
    ▼
Docker Engine

rather than:

Homepage
    │
    ▼
FULL Docker socket access

It is a small improvement, but a worthwhile one.


Uptime Kuma: Is It Actually Working?

Docker reporting:

container = running

does not mean:

application = working

A web application can be running while its database is unavailable.

A process can exist while its HTTP endpoint returns errors.

That is where Uptime Kuma fits.

I currently monitor or plan to monitor:

ServiceCheck
InternetPing
RouterPing
HomepageHTTP
ImmichHTTP
ForgejoHTTP
BeszelHTTP
DozzleHTTP
DiaryBotTCP
Windows SMBTCP
EasyTimesheetsexternal HTTP

A useful example is DiaryBot.

Its root HTTP route may not represent application health correctly, so instead of forcing an inappropriate HTTP test, Kuma can simply verify that its TCP port is listening.


Monitoring the Whole Path

For EasyTimesheets, I deliberately do not monitor only the local container.

The application is externally exposed through Cloudflare Tunnel.

The most useful monitor is therefore the actual external application URL.

That checks:

Kuma
  ↓
Internet
  ↓
Cloudflare
  ↓
Tunnel
  ↓
Application

rather than merely:

Kuma
  ↓
container

The former tests what the user actually depends upon.


Beszel: Monitoring Windows, Not Just Docker

Docker resource graphs only tell part of the story.

My storage is primarily attached to Windows.

The information I actually care about includes:

Windows CPU
Windows RAM
network utilisation
C: usage
D: usage
E: usage
F: usage
G: usage
H: usage
disk I/O

That is why Beszel runs with a native Windows agent.

The Beszel server itself runs in Docker, but the monitoring agent runs directly on Windows.

That produces this topology:

Windows host
    │
Beszel Agent
    │
    ▼
Beszel Server
    │
    ▼
Homepage

The additional drives can be exposed to the agent using:

EXTRA_FILESYSTEMS

so Beszel becomes the authoritative view of host storage and resource usage.


Dozzle: The Fastest Way to Debug Containers

Dozzle has one job:

show Docker logs

It does that extremely well.

Instead of repeatedly running commands such as:

docker logs immich_server --tail 100

I can open Dozzle and immediately switch between:

Immich
PostgreSQL
Redis
Forgejo
Homepage
Kuma
Beszel
DiaryBot
EasyTimesheets
Cloudflared

This creates a very useful operational chain:

Homepage
    ↓
something looks wrong

Uptime Kuma
    ↓
confirm whether the service is actually down

Beszel
    ↓
check CPU / RAM / disk / host health

Dozzle
    ↓
read application logs

Each tool answers a different question.


Existing Applications

The server is not only an infrastructure platform.

It also hosts applications I already use.

Two examples are:

EasyTimesheets

My timesheet application runs in Docker and is currently exposed externally through Cloudflare Tunnel.

The local application port is deliberately bound only to:

127.0.0.1

rather than exposing it to the whole LAN unnecessarily.

Cloudflared handles the external path.


DiaryBot

DiaryBot is another local application running in Docker.

It is accessible on the LAN and appears directly in Homepage alongside the infrastructure services.

As additional applications are created, I plan to make Homepage registration part of their deployment convention.

Eventually a new application should effectively mean:

docker compose up -d
        +
Homepage metadata
        +
Kuma monitor
        +
backup policy

rather than manually rediscovering the service months later.


Docker Desktop: Lessons Learned

This build has also exposed several Docker Desktop quirks.

The most significant were not application problems at all.


1. Large Windows Drive Bind Mounts

Directly mounting one of my large Windows volumes into Docker produced incorrect behaviour.

The eventual solution was:

Windows NTFS
    ↓
SMB
    ↓
Docker CIFS volume

This has been substantially more reliable.


2. Startup Networking Can Lag Behind Containers

After a Windows reboot, Docker Desktop sometimes reached a state where containers reported:

Up

but networking was not completely healthy.

Homepage logged errors such as:

getaddrinfo EAI_AGAIN

and the Docker API itself briefly returned:

500 Internal Server Error

The lesson was not to create aggressive self-healing scripts that immediately recreate containers.

I briefly experimented with such a script and discovered that automatic recovery can make an unstable Docker engine worse.

The safer strategy is:

Docker restart policies
        +
monitoring
        +
manual intervention when Docker itself is unhealthy

rather than continuously forcing container recreation.


3. Test the Application from Both Sides

At one point Uptime Kuma, Beszel and Dozzle were all inaccessible from Windows.

Inside Docker, however:

KUMA OK
DOZZLE OK
BESZEL OK

The applications were healthy.

The broken component was Docker Desktop's published-port forwarding.

This test was invaluable:

docker run --rm --network monitoring alpine sh -c `
  "wget -qO- http://uptime-kuma:3001 >/dev/null && echo 'KUMA OK'"

It allowed me to isolate:

application              ✓
Docker internal network  ✓
Windows port forwarding  ✗

rather than blindly reinstalling applications.


Restart Policies

All long-running infrastructure containers use:

restart: unless-stopped

For example:

services:

  homepage:
    restart: unless-stopped

  uptime-kuma:
    restart: unless-stopped

  dozzle:
    restart: unless-stopped

  beszel:
    restart: unless-stopped

This means Docker can restore them after its engine starts.

I prefer this simple Docker-native behaviour over an overly aggressive Windows scheduled script that continually manipulates containers.


The Monitoring Model

The combination of Homepage, Kuma, Beszel and Dozzle now gives me four distinct layers.

Or in plain English:

Homepage
→ Where is everything?

Kuma
→ Is it up?

Beszel
→ Is the server healthy?

Dozzle
→ Why did it fail?

That is a much better operational model than checking docker ps and assuming everything is fine.


Backup Monitoring Is the Next Step

The next improvement is to make backups first-class citizens on Homepage.

I want a section that eventually looks something like:

BACKUPS
──────────────────────────────────────────────────────

Veeam Home Server
✓ Last successful backup: 01:14

Forgejo / Kopia
✓ Last successful snapshot: 03:02

E → F Mirror
✓ Last successful mirror: 04:37

Immich Database
✓ Last database backup: 02:00

The underlying information already exists.

It can be collected from:

Windows Task Scheduler
Kopia snapshot metadata
Robocopy logs
Veeam backup files
Immich database dumps

A small local status API can expose that as JSON.

Homepage supports custom API widgets, so this should integrate cleanly.


Kuma Push Monitors for Backups

There is another useful approach.

Scheduled backups can be represented by push monitors in Uptime Kuma.

Instead of Kuma asking:

Are you alive?

the backup job tells Kuma:

I completed successfully.

The flow becomes:

Backup starts
     ↓
backup completes
     ↓
success URL called
     ↓
Kuma updates monitor

If Kuma stops receiving successful updates within the expected period, the backup monitor goes red.

That will be particularly useful for:

Veeam
Kopia
E → F mirror
Immich database backup

A backup job silently failing for three months is much more dangerous than a web application being unavailable for ten minutes.


Family Documents: Paperless-ngx Is Next

Photos are now handled well.

The next major data category is family documentation:

passports
birth certificates
insurance policies
house documents
bills
medical correspondence
school documents
receipts
contracts
warranties

The planned interface for this is Paperless-ngx.

The existing documents will remain preserved initially.

Paperless will ingest copies and provide:

OCR
full-text search
tags
document types
correspondents
user accounts
permissions

Instead of knowing the exact folder hierarchy, a family member should eventually be able to search:

Martina passport

or:

home insurance 2026

and immediately retrieve the document.


Planned Family Section

Eventually I want Homepage to look something like:

FAMILY
────────────────────────────────────────────

Immich
Photos and videos

Family Documents
Paperless-ngx

Family Handbook
BookStack

These three applications serve very different purposes.

Immich answers:

Where are our photos?

Paperless answers:

Where is the document?

BookStack answers:

How does something work?


BookStack: Documentation for Humans

This entire system should not depend on me remembering how it works.

Eventually BookStack will contain a family-oriented operational handbook.

For example:

Family Handbook

Home
├── Emergency contacts
├── House information
├── Insurance
└── Utilities

Technology
├── Home server overview
├── How to recover the server
├── How to restore photos
├── How to restore Forgejo
├── Where backups are stored
└── What to do if I am unavailable

Passwords will not be stored there.

They belong in a password manager.

BookStack should explain the system, not become another secrets database.


Tailscale: Remote Access Without Opening the Router

The next networking step will be Tailscale.

The target topology is:

Home Server
    │
Tailscale
    │
    ├── my phone
    ├── my laptop
    └── my wife's phone

That will allow secure remote access to services such as:

Homepage
Immich
Paperless

without exposing application ports directly to the public Internet.

I want the router to remain deliberately boring:

no random forwarded ports

The Remaining Weakness: Off-Site Backup

At the moment the local resilience is becoming quite strong.

I have:

primary data
        +
local mirror
        +
versioned backups
        +
bare-metal Windows recovery

But multiple disks inside the same home are still ultimately one location.

Fire, theft, electrical damage or another catastrophic event could affect several copies at once.

The final major piece therefore needs to be:

encrypted off-site copy

of the genuinely irreplaceable data.

Primarily:

family photos
important documents
critical configuration
source-code backups

That could eventually be another physical location, cloud object storage, or a combination of both.


What the Finished System Should Become

The end state I am working toward looks approximately like this:

                        CORBILLA HOME
                              │
       ┌──────────────────────┼───────────────────────┐
       │                      │                       │
       ▼                      ▼                       ▼
     FAMILY               APPLICATIONS           DEVELOPMENT
       │                      │                       │
    Immich              EasyTimesheets             Forgejo
   Paperless               DiaryBot
   BookStack
       │
       │
       ▼
      DATA
       │
       ├────────── E: Primary
       │
       └────────── F: Mirror


                     INFRASTRUCTURE
                           │
               ┌───────────┼───────────┐
               ▼           ▼           ▼
              Kuma       Beszel      Dozzle
            availability   host        logs
                          health


                        BACKUPS
                           │
          ┌────────────────┼────────────────┐
          ▼                ▼                ▼
        Kopia            Veeam          E → F Mirror
          │
          └──────── encrypted/versioned

                           │
                           ▼
                    future off-site copy

What I Like About This Architecture

The biggest success so far is that no individual component has become indispensable.

If Homepage disappears, the applications still work.

If Immich disappears, the original photos remain.

If Forgejo disappears, GitHub remains the primary source.

If GitHub disappeared, Forgejo has the Git repositories.

If the Windows SSD fails, Veeam can rebuild the machine.

If Forgejo becomes corrupted, Kopia can restore it.

If E: fails, F: contains a second local copy.

That is exactly how I want a home infrastructure system to behave.

There should not be a single magical database somewhere that suddenly contains my family's entire digital life.


Some Lessons So Far

The project has already reinforced several principles.

Keep original data boring

Ordinary directories and files are excellent long-term storage formats.

Do not make an application database the only place an important file exists.

Backup and replication are different things

Forgejo is a replica of GitHub.

F: is a replica of E:.

Neither automatically provides meaningful historical versioning.

Kopia does.

Test restores

A successful backup log is not equivalent to a successful recovery.

Boot the restored application.

Open the restored repository.

Read the restored file.

Monitor outcomes, not processes

A running container does not prove that its service works.

A scheduled task completing does not necessarily prove that the backup is recoverable.

Monitoring should get as close as practical to the actual result that matters.

Avoid exposing unnecessary services

The LAN does not need every database port.

The Internet definitely does not.

Use internal Docker networks, localhost bindings, Cloudflare Tunnel where appropriate, and eventually Tailscale.

Automation should fail safely

An automation that detects a problem is useful.

An automation that automatically rebuilds infrastructure while the underlying Docker engine is malfunctioning can make matters worse.

Recovery automation should be conservative.


Current Status

At this point the core environment is working:

✓ Immich photo archive
✓ historical photos mounted read-only
✓ managed Immich storage
✓ Forgejo GitHub mirrors
✓ automated repository discovery
✓ Kopia encrypted backup
✓ tested Forgejo disaster recovery
✓ Veeam bare-metal backup configuration
✓ E → F local mirror
✓ Homepage dashboard
✓ Uptime Kuma
✓ Beszel
✓ Dozzle
✓ EasyTimesheets
✓ DiaryBot

The next priorities are:

1. Finish Kuma monitor configuration
2. Finish Beszel Windows-host monitoring
3. Add backup-health reporting
4. Verify recurring Veeam backups
5. Configure laptop bare-metal backup
6. Deploy Paperless-ngx
7. Add Tailscale
8. Add BookStack
9. Add encrypted off-site backup

Conclusion

What started as a few Docker containers is gradually becoming a proper family infrastructure platform.

The interesting part is not any individual application.

Immich is excellent.

Forgejo is useful.

Kopia is powerful.

Homepage looks great.

But the real value comes from connecting them into a system where each component has a clear responsibility:

Immich
→ preserve and browse memories

Paperless
→ find documents

Forgejo
→ replicate source code

Kopia
→ preserve historical versions

Veeam
→ recover computers

Homepage
→ navigate everything

Kuma
→ tell me whether it works

Beszel
→ tell me whether the server is healthy

Dozzle
→ tell me what went wrong

That is the direction I want the project to continue taking.

Not simply a homelab.

A self-hosted family digital estate that is understandable, recoverable and designed to survive the failure of any single application or machine.

Comments

Popular Posts