Begin with an operational goal
Before choosing cloud products and tools, identify what the application must withstand. An internal portal with dozens of users has different needs from a system whose outage stops payments. Record expected load, critical data flows, acceptable recovery time and the people who will maintain the service. Without those inputs, it is easy to build a complicated platform for a simple problem or a fragile environment for an important operation. Architecture should follow the consequences of failure.
The AWS Well-Architected Framework provides a way to consider operations, security, reliability, performance, cost and sustainability together. It does not require every available cloud service. A small application can run on an understandable server with Docker Compose, backups and monitoring if its risks permit that choice. Other workloads need network separation, multiple zones or a managed database. The appropriate option depends on the impact of an outage and the organisation's ability to operate it.
Separate environments and control change
Development, test and production environments serve different purposes. Test should allow a team to verify migrations, integrations and a release without affecting real users. It need not match production capacity in every detail, but important differences must be known. If tests use a different database or omit a critical external service, record the limitation when deciding to deploy. Otherwise a green test result can create misplaced confidence about production behaviour.
A change needs a record of the version deployed, who approved it, which checks passed and how to return. GitHub deployment environments can restrict branches, access to secrets and deployment approval. Equivalent boundaries can be built in other ways, but the rule should be explicit. Production secrets should not be embedded in the image or routine logs. Manual intervention may sometimes be necessary; it should be as traceable as an automated release.
CI/CD checks the journey, not only compilation
A pipeline typically builds the application, checks types and static quality, runs meaningful tests and produces a deployment artifact. Successful compilation alone does not prove a database migration is compatible, a dependency is available or configuration is correct. Define the smallest useful release gate for the risk of the product. A web application might check main journeys, authentication and one essential business flow. A data service may also need schema and malformed-message checks.
Prefer one artifact promoted between environments after verification rather than unrelated builds with hard-to-trace differences. Keep configuration separate and validate required values before accepting traffic. A release should be repeatable without one developer's memory. If the change includes a database schema, plan the order of compatible steps and the return path. Restoring old application code may not be enough when the new version has changed persistent data in a way that cannot simply be reversed.
Infrastructure as code should remain readable
Versioned server, network, container and permission configuration helps reproduce environments and review differences. Its benefit depends on clarity. Hundreds of abstractions for one server can make diagnosis and handover harder. Use the smallest level of automation that removes recurring manual errors while keeping actual state visible. Before changing production, the team should see a plan of effects, especially deletion of a resource or a broader access grant. Review the plan against the business impact.
Docker Compose can fit a straightforward VPS deployment where restart, persistent data, backup and reverse proxy access are documented. Docker's production guidance distinguishes development and production Compose configurations. A container file alone does not manage the host, updates, TLS or recovery after disk loss. Those belong in the operating procedure. If stronger orchestration later becomes necessary, the reason should be a measured limitation of the current approach, not a preference for a fashionable platform.
Observability should reflect user impact
A baseline includes availability, errors, latency and load for important components. You also need to know whether an actual task completes: for example, whether requests reach their final state, not merely whether a server responds. Logs, metrics and traces answer different questions. A log explains one error, a metric reveals a trend and a trace shows a slow step across services. Collecting everything without deciding what to act on creates cost and noise rather than insight.
Every alert needs an owner and a response. If nobody can resolve a notification, adjust the threshold, improve diagnosis or remove a measure that only interrupts work. Conversely, a critical data flow without an alert can fail silently for hours. Correlation identifiers link user actions to backend steps and integrations. Tokens and sensitive content do not belong in routine logs. Retention and access to operational data should match a defined diagnostic purpose.
A backup is not a recovery
A regular backup helps only if it can restore a usable service. Decide how much data loss is acceptable and how long recovery may take. Those decisions determine backup frequency, storage location and the restoration of both application and database. Saving only the database may be inadequate if code versions, files or encryption keys cannot be aligned with it. Protect backups from the same accident or access that could damage the original data.
Periodically restore into an isolated environment and check that essential operations work. Record the duration, failures and improvement to the procedure. The same applies to a faulty deployment: switching to an older image is only one step when schema changes or messages already in progress need attention. During an incident, a short responsibility list helps: who decides, who restores and who informs users? An untested plan often becomes improvisation at the moment it is needed.
Security and cost belong in every change
Give people and services the narrowest access they need and review it regularly. Plan operating system, library and container image updates as routine work. A large stockpile of outdated dependencies increases both risk and migration effort. Dependency scanning is a useful signal, not proof that the application is free of vulnerabilities. Safe deployment also needs configuration review, secret separation and a proportionate incident response process.
Measure cost in relation to the service delivered. Spending may come from idle capacity, long log retention or network transfer, while an apparently cheap environment can be expensive through outages and manual repair. Split the budget into baseline operation, variable demand and a reserve. An early warning about deviation is better than a monthly surprise. An architecture change is justified when measurements show a benefit for reliability, performance or total cost.
Hand over a service others can operate
Handover documentation should answer practical questions: where the code lives, how a release is made, where access is managed, how backups are restored, what alarms mean and who controls the domain or certificate. A long description of every command is not the goal. Another authorised person should be able to perform a routine change and basic recovery. Verify this with a joint exercise rather than merely handing over a repository link.
An initial conversation should cover existing applications, outages, change approval, available staff, data and contractual responsibilities. The result may be a short repair plan, a pipeline, an environment audit or a new operating model. An SLA or management price cannot be promised without seeing the actual infrastructure and responsibilities. This page describes EXCOIN's approach to technical decisions, not an unverified service level or certification. The aim is a proportionate system that can be changed safely and operated clearly.