Replaces the docker_container playbook, which bind-mounted /var/lib/nextcloud at /var/www/html on monoco and ran cron.php from root's crontab. Nextcloud now runs on emily behind the shared Caddy, with its database in the shared Postgres and its cache in the shared Valkey, each attached the way every other service attaches to them. /var/www/html is the unusual part: it holds the code as well as the state -- version.php, core/, lib/ and apps/ alongside config/config.php, data/ and custom_apps/ -- and the entrypoint's version check reads version.php from the mount. That is why the migration copies the whole tree rather than only the three irreplaceable directories (docs/backup-plan.md 2.1 lists the rest as regenerable, and they are, but only from an image that is the same version or newer). It is also what makes an image bump an in-place upgrade: a newer image rsyncs its code in and runs `occ upgrade` on first start, and an older one refuses to start at all, so the version on both hosts is worth checking before the copy. UserNS=keep-id:uid=33,gid=33. 33 is www-data, the uid the server actually writes as -- `docker exec nextcloud id -u` reports 0, because the entrypoint drops privileges after starting (docs/podman-compat-audit.md 3.2). 33 is also what the data is owned by on monoco, so the copy needs no chown pass: extracting as the connection user is already the ownership the container expects. One file is created by container-root and never chowned, the entrypoint's nextcloud-init-sync.lock, so the role pre-creates it -- the entrypoint truncates that file rather than recreating it, so its owner then never changes, and the webroot ends up with no subuid-owned file in it. The Valkey attach is not optional. config.php carries memcache.locking pointed at Redis, written by the image from REDIS_HOST, and the same variable rewrites PHP's session-handler config on every start -- so an unresolvable `redis` does not just make things slower, it fails uploads at write time. Hence the `redis` alias rather than the container name, and hence roles/valkey flushing handlers before the app starts, the same as roles/postgres. cron.php moves from root's crontab to a systemd user timer, because root cannot `podman exec` into another user's rootless containers and there is no container user to own a crontab (docs/podman-migration.md 8b). Unlike the Quadlet units this pair is plain and is genuinely enabled, which is what brings it back after a reboot; journalctl --user -u nextcloud-cron shows every run, which the crontab never did. Readiness is three gates, because no one of them is sufficient: is-active (which Restart=always satisfies even while crash-looping), `occ status` reporting installed, and status.php served over loopback by Apache rather than by the PHP CLI. The second is followed by a wait for maintenance mode to clear rather than an assert: maintenance mode is on for the whole of a first-start `occ upgrade`, so asserting it off would fail a healthy deploy halfway through. The case that never clears is a config.php copied with `maintenance => true`, which docs/backup-plan.md 3.4 tells an operator to set before a consistent dump, and which is invisible from outside because status.php is exempt from maintenance mode -- so the play names it and prints the command that clears it. Register and attach ordering is the same as the other service playbooks: register runs in pre_tasks, because the unit references nextcloud.network and Quadlet fails unit generation when that file does not exist, and both attaches flush handlers before the app starts, which is also what pulls Caddy onto the network. The Caddy snippet is unchanged, HSTS header included; only caddyfile_path moves, from /var/lib/caddy/conf/Caddyfile to ~/podman-data/caddy/conf/Caddyfile. The Docker-era roles/network is deleted rather than ported: it existed to attach an already-created container to a network with the `redis` alias, and podman_network has no connected:/appends: equivalent (docs/podman-compat-audit.md 3.3). Nothing is published host-side; Caddy reaches nextcloud:80 over nextcloud_net. The rootless-Podman prerequisites are not applied here: they are the shared task file at caddy/roles/podman, and a host that has run caddy/playbook.yml has them. valkey/playbook.yml has to have been run first, or the first Restart Valkey handler fails against a unit that does not exist yet.
Ansible Playbooks
A collection of minimalist Ansible playbooks for automating server setups, based on DigitalOcean's Community guides.
- Initial Server Setup for Ubuntu 18.04 *
- Apache on Ubuntu 18.04
- Postgres on Ubuntu 19.10
- Redis on Ubuntu 19.10
- Bitwarden Ubuntu 19.10
- Gitea on Ubuntu 19.10
*the Initial Server Setup should be your starting point for fresh servers.
Playbook Structure
The playbooks contained in this repository were created for educational purposes, and should serve as a base for you to create your own playbooks and roles.
Although we opt to not use roles, our playbooks follow a distinctive structure to facilitate reuse while keeping them mostly self-contained and straightforward.
For instance, this is how the lemp playbook is structured:
lemp_ubuntu1804
├── files
│ ├── info.php.j2
│ └── nginx.conf.j2
├── vars
│ └── default.yml
├── playbook.yml
└── readme.md
files/: directory containing templates and other files required by the playbook.vars/: directory to save variable files. Adefault.ymlvar file is included by default.playbook.yml: the playbook file.readme.md: instructions and links related to this playbook.
Getting Started
To set up your Ansible environment, please follow our guide on How to Install and Configure Ansible on Ubuntu 18.04.
Connection Test
From your local machine or Ansible control node, run:
ansible all -m ping -u remote_user
If you're able to get a "pong" reply back from your node(s), your setup works as expected and you'll be able to run both ad-hoc commands and playbooks on your nodes, using Ansible.
Guides
The following guides cover how to use the playbooks you'll find in this repository.
Initial Server Setup
Once you have executed the initial server setup, you can choose from any of the available server setup playbooks:
Web Servers
- Apache on Ubuntu 18.04
- LEMP (Linux, Nginx, MySQL, PHP) on Ubuntu 18.04
- LAMP (Linux, Apache, MySQL, PHP) on Ubuntu 18.04