Back to blog
Infra

Self-hosting with criteria: when n8n, Docker, Redis, PostgreSQL, and Dokploy make sense

Self-hosting is neither a religion nor a technical trophy. To me, it is a sequence of decisions about control, resource distribution, operations, and limits. In this article, I explain how I organize portfolio applications, automation, and Minecraft servers — and why exposing less is usually the better decision.

9 min

Self-hosting starts when the question changes from “can I host this?” to “what should live together?”

Self-hosting is often framed as a binary choice: hand everything to a managed platform or take responsibility for every detail.

I learned that the most important question comes first: which services should share resources, which ones deserve isolation, and which failures must not spread across the environment?

My infrastructure combines a portfolio, automation, data, caching, and Minecraft servers. I do not treat all of them as the same workload. Each group has a different life cycle, priority, and way of being exposed to the internet.

The sequence is simple: understand the problem, make a decision, operate with discipline, and recognize the limits before they become surprises.

My context: portfolio, automation, and Minecraft servers

I use n8n for automation, PostgreSQL as a database, and Redis only for caching. I also maintain Minecraft servers.

In Dokploy, I organize these environments into separate projects. The Portfólio project groups applications and services related to my work. The jogar project groups the components connected to my Minecraft servers.

This separation does not automatically create complete isolation. If both projects share the same host, CPU, memory, storage, or network, they still have a common physical dependency. Even so, separating responsibilities makes operations clearer.

When a web application changes, I know which group to investigate. When a game server consumes resources, the investigation starts somewhere else. When I need to restart something, I can first consider the impact on that project instead of looking at one indistinct stack of services.

Why portfolio and Minecraft are different workloads

Web applications usually need controlled exposure, careful updates, certificates, authentication, and data protection.

Minecraft servers behave differently. They are persistent processes, depend on the game's specific protocol, and can have usage spikes unlike those of an API or website.

I may run these workloads on the same physical infrastructure, but I should not treat them as the same thing. Project separation creates an operational boundary. It helps organize updates, resources, domains, and responsibilities.

The important point is not to confuse organization with complete isolation. Real isolation still requires resource limits, networks, permissions, and security policies.

What each component does

Docker: packaging without pretending operations disappear

Docker helps me turn services into predictable execution units. With Compose, I can describe applications, dependencies, networks, volumes, and startup parameters in a structure that can be reviewed and reproduced.

That reduces the distance between “what should be running” and “what is running”. It also makes it easier to separate groups of services by project.

But a container is not a virtual machine and Docker is not a backup. Docker does not solve resource contention, persistence, accidental port exposure, image updates, log rotation, recovery, or host security by itself.

I use Docker because consistent packaging is worth the additional operational layer. I do not treat Docker as a synonym for security.

n8n: automation with responsibility for state

n8n is my automation layer. Its value is not limited to drawing workflows. Running it under my own control also means owning the data, credentials, execution history, and failure handling around those workflows.

Automation is not just interface and execution. There are credentials, history, state, and pending tasks. That is why the database choice matters.

I use n8n with PostgreSQL because of consistency, speed, and data scalability. To me, the database is not an invisible automation dependency; it is part of the system.

If a workflow matters, I also need to know how failures will be observed, how credentials will be protected, and how an execution can be replayed.

PostgreSQL: consistent storage for data that matters

I chose PostgreSQL with n8n for a practical reason: execution data needs consistency and room to grow without relying on improvised storage.

A relational database does not guarantee speed by magic. Its value appears when a system needs integrity, queryable history, and relationships between data.

The trade-off is equally real: PostgreSQL requires attention to storage, permissions, upgrades, retention, backups, and restores. Running it in a container does not remove the need to operate it.

Redis: cache, not the source of truth

In my environment, Redis is used only for caching.

That boundary matters. A cache can speed up reads and reduce repeated work, but it should not quietly become the only place where essential state exists.

The question I ask is: what happens if this data disappears or becomes stale? If it can be rebuilt, using it as a cache makes sense. If losing it breaks an essential part of the operation, the data needs another persistence strategy.

Dokploy: an administration layer

Dokploy organizes projects, applications, and composes. It gives me a clearer view of what is deployed and reduces part of the manual deployment and administration work.

But a dashboard does not replace understanding. I still need to know how the composes, volumes, networks, domains, and dependencies work behind the interface.

The dashboard makes operations easier. Responsibility remains with the person who understands what is behind it.

DNS: the small layer that defines the route

One of my lessons was that configurable DNS is not a cosmetic detail. DNS defines how names reach services, how destination changes propagate, and how much control exists across environments.

More flexibility helps organize subdomains, separate applications, and change destinations without reconfiguring every client. It also creates more room for mistakes involving TTLs, conflicting records, proxies, certificates, and public exposure.

For me, DNS is part of the architecture. It is not just a record that I create and forget.

Resource distribution matters more than collecting tools

The main lesson was not simply hosting my own services. It was learning how to isolate and distribute resources better.

The host is finite. CPU, memory, storage, and operational attention must be divided among different workloads.

In practice, that means:

  • limiting what each service can consume when necessary;
  • preventing logs or volumes from one application from consuming everyone's storage;
  • observing continuous and intermittent workloads;
  • separating public components from dependencies that should stay on internal networks;
  • considering the impact of a restart before performing it;
  • documenting decisions so operations do not depend on one person's memory.

Visual organization helps. Real limits protect the rest of the environment.

Exposing less is an architectural decision

Another important lesson was understanding that every exposed service adds responsibility.

I use a reverse proxy with Traefik, Nginx, or Caddy to centralize HTTP/HTTPS entry, route traffic by domain, and organize certificates.

I also learned to configure origin certificates on the server and use Cloudflare in front of web applications. Whenever possible, communication between services and applications happens over internal networks. A public domain does not need to point directly to everything running in the environment.

My rule is to expose only what truly needs to be exposed. In my case, Minecraft servers are the exception: they use domains without a proxy because of the game's protocol requirements.

For every other service, the question is different: does this application really need to be public? Which protocol does it use? Which layer should handle its traffic? The answer determines whether it belongs behind a proxy, certificate, authentication, and access control — or only on an internal network.

Operations: the dashboard does not replace routine

Self-hosting requires attention. I am not talking about a specific monthly cost because I do not have those numbers closed. I am talking about the work of following updates, validating changes, investigating failures, and maintaining a recovery path.

A healthy operation needs to answer questions such as:

  • How do I know n8n, PostgreSQL, Redis, and the applications are working?
  • Which logs are retained and for how long?
  • How can an update be rolled back?
  • Who receives an alert when automation fails?
  • How are domains and certificates renewed?
  • What can be restarted without interrupting the rest?

These questions are part of the architecture, not an optional step after deployment.

Backups and security cannot remain implicit

Backups must be defined by service and data type. A PostgreSQL dump does not necessarily replace application volume backups. Redis, because it is a cache, may have a different priority. Configurations, credentials, Compose files, and game data may require different strategies.

Before calling something a backup, I need to know:

  • what is copied;
  • where the copy goes;
  • how often it runs;
  • how long it is retained;
  • whether there is a copy outside the main host;
  • whether restoration has been tested.

The same logic applies to security: public ports, authentication, volume permissions, secrets, image updates, PostgreSQL and Redis access, and the separation between internal and exposed networks.

When this decision stops making sense

Self-hosting stops being a good choice when the desired control requires more attention than the project can provide.

Docker may add too many layers for a small application. Dokploy may be unnecessary for a single service. Redis may add noise when there is no caching problem. PostgreSQL may require more operation than a simple project needs.

Separating projects improves clarity, but it does not create physical resources or remove single points of failure.

This approach makes more sense when there are multiple services, automation needs, data that deserves consistency, workloads with different behavior, and a concrete reason to control resources, DNS, and public exposure.

The criterion is not using every tool. It is knowing why each tool exists and what happens when it fails.

Conclusion

I see my infrastructure as a division of responsibilities: Docker packages, Dokploy organizes, n8n automates, PostgreSQL holds the data, and Redis handles caching.

The Portfólio project groups applications and services related to my work. The jogar project groups the Minecraft side. Reverse proxies, origin certificates, Cloudflare, and internal networks reduce unnecessary exposure. Minecraft servers remain the exception because of the protocol they need to serve.

This is not a universal recipe. It is the direction that makes sense to me while managing different workloads and trying to use the available resources better.

Pragmatic self-hosting is not about collecting components. It is about understanding the decisions, limiting each service's impact, and still knowing what is happening when the dashboard stops showing only green boxes.