Multiple copies of the same website: how to organize code/architecture?

tl;dr

Code

You can easily go with a WordPress Multisite or Network install (you can read at the bottom why I recommend against that). It allows sharing a lot between installs, starting from user accounts to (parent) themes, plugins, etc. with other sites in your network.

Another option is to spin up installs using Composer. This option is what I would recommend so you can easily reuse plugins or (a parent) theme. Then add, as @s_ha_dum recommended in the comments, child themes to account for the visual differences in your installation. Off load as much functionality as you can to plugins so the difference in your installation can be handled easier.

Database

There’s not really much you can do aside from having a “base dump” from where you can start off. Importing those when spinning up a new install can easily be done, even easier when you have a deployment service/provider that allows executing (for e.g. shell) scripts in between the process. You could, depending on your detailed use case, maybe even dump tables instead of your complete database and merge the two tables.

Generalized answer

First off, you should review your complete workflow. Ask yourself some questions which you then can tackle bit by bit and answer for yourself or crowdsource.

  1. Development – How do you develop? Do you have a reliable local development environment? Can you quickly spin up test sites in case you need to test something in a plain vanilla environment?
  2. Planning & VCS – How do you handle versioning of code? Do you have a defined process that you and others can follow and share? Do you have a roadmap that you can prioritize?
  3. Deployment – How does code get onto your servers?
  4. Tests – Do you have a testing environment where you can check if things work out the expected way before they go live?
  5. Hosting – How do you provision your servers? Do you have fallback instances (a cluster) in case one or two of your servers or services fail?

Development

For development you might want to have a sharable virtual machine/box that you can hand over to 3rd party developers and that matches your production environment/servers as close as possible. This massively helps with debugging problems locally and speeds up that process. Take a look at Vagrant, Otto, Docker (Linux only or w a workaround for Win, OS X) or Rocket.

Aside from that, I would recommend against a multisite install unless you need to share data between your installations and want to share a database as well. In any other case, it just makes database backups harder (because larger) and both development as well as deployment slower.

You might want to switch to a Composer based setup, taking WP Starter from @gmazzap as base to spin up your installs, which is probably the fastest and most reliable way to start and maintain your isntall.

Planning and VCS

When starting new features, fixing bugs, releasing, you might want to use something like Git Flow, that you can tightly match to your planning process running on services and tools like GitHub issues, Trello boards or Waffle.io on top of GitHub issues. Meaning that you write your roadmap, then branch off, build your feature, test it and merge back for the next release.

When you have your composer.json as main entry point for your setups, you can easily split up code base in separate repos (if you need free private repos, consider using Bitbucket in case you don’t want to use the issue tracker). This allows to only install plugins or themes when they are needed. You can fetch plugins and themes from the official w.org repo via WPackagist as well as from self hosted or private repos on GitLab, GitHub, Bitbucket, etc.

Deployment

There are tons of services and self hosted packages out there to deploy your code in a standardized way. Doing this manually imo is a nono. Script or configure your process in a services GUI so you just have to press a button or write a single command in the terminal. Everything else is unreliable, (human) error prone and wastes your time. Spending some bucks on a reliable deployment service that allows for seamless rolebacks in case things go sideways, probably is the best decision you can make. Try to avoid combining deployments and hosting so you can switch out one without touching the other too much.

Tests

Test whatever you can do, starting from the most base logic to the highest level. Start with the lowest. Testing the most crucial business logic first and the bits that connect to other bits in your code or environment pays off. There’s Travis, Codeship, Snap CI, Circle CI and others for continuous integration tests. Some allow deployments, but again, you might want to separate that to increase interchangeability of services.

Hosting

As you already mentioned that you are on Amazons EC2 services, consider going with CoreOS to have a reliable base for your installations that include intercommunication and fallbacks. Another option would be to run NixOS instances on EC2. Both OS are containerized, which allows for much better debugging, offers more reliability and makes bits easily replaceable. The more isolated your services are, the better.

As written under development, try to move from managed hosting to a more DevOps-like approach and offload whatever you can to external services. This also makes handing over installations much easier.

Bottom line

Even when just throwing together some available theme with some plugins, having a running WordPress installation that is configured can take easily a day or two, depending on how reliable and failsafe your setup is. Investing time in the surroundings like hosting setup, deployments, repositories, etc. always pays off with the first change you need to make to an installation. Having a reliable way to build and ship installations often is worth more than removing a redundant line of code.