Production Operations on a Single Server · 1/10

Design a Single-Server Setup: Reverse Proxy, App, and Database

What will this help you do?

Draw the boundaries between the public entry point, reverse proxy, application, database, files, and backups so fewer ports are exposed and incidents are easier to diagnose.

Who is it for?

Readers working through this problem and checking each step.

Before you start

Check the scope of this guide, then prepare the environment and materials it actually calls for.

Updated

On this page

One server still needs clear boundaries

Running a small website on one server is reasonable. The problem is not the number of machines; it is whether the reverse proxy, application, database, and backups have distinct roles. If every process runs as root, the database is open to the internet, and application code sits beside user uploads, the first incident becomes a search through everything at once.

You do not need a diagram full of cloud-provider icons. A useful deployment sketch answers five questions: Where does a request enter? Which user runs each process? Where is persistent data stored? Where are backups kept? What symptom appears when each layer fails?

Draw the request path from the outside in

A typical path starts with DNS pointing a domain to the server's public IP. The firewall exposes only 80/443 and controlled SSH access. Caddy accepts HTTP and HTTPS, then forwards requests to an application bound to a loopback address such as 127.0.0.1:3000. The database accepts only local or private-container connections; it does not need a public 5432 or 3306 port.

text
Internet -> 80/443 -> Caddy -> 127.0.0.1:3000 -> Application
                                      |-> Database
                                      |-> Uploaded files

This path is also a troubleshooting map. A wrong destination starts with DNS. Certificate and some HTTP errors lead you to Caddy. For a 502, check the upstream address and whether the application is running. Investigate database or business-logic errors after the request has reached the application.

Give each component only the access it needs

Use separate system users for Caddy, the application, and the database. Application code can be read-only at runtime; grant write access only to the directories used for logs, uploads, or temporary data. A deployment account may use sudo to manage services, but normal application processes should not run permanently as that account or as root.

Restrict environment-file access to the users that need it. Do not place .env in a public static directory or print complete environment variables to startup logs. Make directory roles obvious: for example, /opt/myapp/releases for code, /var/lib/myapp/uploads for uploads, and /var/backups/myapp for backups, instead of putting everything under /root/app.

Separate durable data from replaceable files

Code, dependencies, and build output should be reproducible from a repository or image. Databases, user uploads, and secrets are different: losing them may be irreversible. Mark each persistent store on the diagram and document how to back it up and restore it. A container volume is not a backup, and a disk snapshot does not automatically replace a consistent application-level backup.

Logs can be regenerated, but keep enough history for incident investigation. Set rotation and disk limits so one noisy failure cannot fill the root filesystem. Temporary files belong in a known location with a safe cleanup process.

Keep a port table, not just a firewall note

Address or portUsed byPublic?Purpose
22/tcpAdministratorsRestrictedSSH; limit source addresses where practical
80/443CaddyYesThe website's public entry point
127.0.0.1:3000ApplicationNoReached through the reverse proxy
127.0.0.1:5432DatabaseNoReached by local application processes

Your exact ports may differ. The principle is a small public surface and explicit internal addresses. Use ss -lntp to check what is actually listening; configuration files alone are not proof.

Accept and plan for single-server failure

If the one machine fails, the proxy, application, and database all stop. Disk damage can affect every local copy. For a low-traffic content site, off-site backups, automatic startup, monitoring, and a clear recovery guide can make that risk manageable. If the business needs availability across data centers, do not present a single server as a fault-tolerant design.

Before launch, decide how much data you can afford to lose, how long the site may be unavailable, and who will perform recovery. Those answers should drive backup frequency and whether a second machine is warranted—not the other way around.

What counts as done?

Keep four simple records: a request path, a process-and-user list, a port table, and a persistent-data-and-backup list. Then move the application from a temporary terminal session into a systemd service so it can start automatically, run with limited privileges, and leave searchable logs.

Sources

  1. Caddy reverse_proxy directiveCaddy Documentation

Next steps

Continue with the next useful task; you do not need to read everything at once.

  1. Host Multiple Websites on One Server with Caddy →
  2. Deploy Dify with Docker Compose: A Production-minded Guide →
  3. Manage Production Secrets and Environment Files Safely →
RESOURCES I USE · REFERRAL

Two services to compare when you are ready to launch

This is not an automated ranking, and neither service is necessary for everyone. These are services I use, with the use case and limitations kept visible.

Cloud server · Used for early projects

RainYun

A practical candidate for a website or small service. Choose by user region, configuration and measured workload rather than the lowest headline price.

Referral disclosure: these links contain my referral information. I may receive a platform benefit if you sign up or order, at no additional charge from AIOOS. Check the order page for current pricing, availability, regions and terms. Read the full affiliate disclosure