My code is usually documented in the code the doc headers have examples and links to the according rfcs or papers. The second level of documentation is in the tests where I write down how to use also explaining the why as comments.
I usually build everthing including the docker/VM images or ansible/puppet for the provisioning. So in there are certain compile steps and sometimes I add my own mirrors just for the version freeze and certain binaries are statically compiled in there as well. With an explaination of why and what should be in there.
The rest ends in the README as 'how' to use it, command examples etc. My scripts or programms are always meant to run 'out of the box'.
Also I tried writing some manuals in a markdown guide. But in my experience most people don't read it. that's why I stopped and started to put the documentation in the code or scripts. so I can generate the documentation from the code.
A rather pragmatic approach after spending weeks writing documentation that maybe one dev is skimming. I rather prefer them as MD in the repo I am creating.
Also my hashnode blog has some stuff in there. But I tend to put the information at the point where people are working with it or link it from the code.
stuff ;)