Host Your Blog on DigitalOcean with Docker, Nginx and Let’s Encrypt
archij.com
archij.com
Please for the love of all that is holy, do not ever do this! Giving access to the host's Docker socket is equivalent to giving a container unrestricted root access to your host. Mounting the socket read-only doesn't protect you in any way either, because you can still connect to and write to the socket! Seriously, try it:
% touch /tmp/docker.sock
% mount --bind -o ro /var/run/docker.sock /tmp/docker.sock # this is -v /var/run/docker.sock:/foo:ro
% docker -H unix:///tmp/docker.sock run --privileged -v /:/host -it ubuntu bash
# # I couldn't write to it, but I can connect and write to the connection...
# cat /host/etc/shadow # whoops!
(The full container escape is left as an exercise for the reader. It's pretty trivial though.)To be fair, there are unix-like DAC controls that do restrict this somewhat but given that most people run containers as root or they don't use user namespaces this is still an issue.
Please stop doing this, please stop telling people to do this, and please stop making images that access docker.sock. I understand that this is something that a lot of people do, so it's obviously not exclusively the fault of the author for doing what the majority of people appear to be doing, but I think that this deserves to be said much stronger than it was in the past (people still expose Docker over the internet -- which is literally a free root-level RCE for anyone who figures out you're hosting it).
And yes, AuthZ plugins exist but nobody really uses them as far as I'm aware -- and personally (as someone who maintains container runtimes and other low-level container tools) I would not feel confident in depending on any AuthZ plugin's profile to protect against a container escape where you give unprivileged users access to /var/run/docker.sock. Even if I were to write one.
It seems like if the author(s) of docker-letsencrypt-nginx-proxy-companion had assumed something like docker compose or kubernetes that neatly handles sharing volumes between containers, they probably wouldn't have made the mistake of giving a docker container access to docker for such a trivial use.
I disagree that there's never a good reason to do this though. A docker control panel, or a CI or FaaS that spawns docker containers, can be a good reason to do this. https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-d...
BTW there's no escaping the container when you're doing this intentionally.
The number of cases where it is an acceptable idea to do this (compared to the number of cases where people do this because they read it on a random blog post) is so small that it is statistically insignificant. In my view, it is much better to tell people to never do something which is very rarely useful. People who know better would know when to ignore that warning (which I would hope would be the sort of people who would write a CI or FaaS), while those who don't know better likely wouldn't use it in a way that is "safe".
The blog post you link to is quite old (this was at a time when most users were well aware of what docker.sock did -- so much so that vulnerabilities I helped find in Docker from that time were not regarded vulnerabilities because they required docker.sock access!). I agree with Jerome's point which was to dissuade usage of Docker-in-Docker. His point was not that bind-mounting the docker.sock is generally an okay thing to do -- and as I said I think that we should be far more vocal about how dangerous this is (because people don't listen otherwise -- as has been shown by the fact that there are still plenty of users that have Docker listening on a TCP socket without client certificates).
> BTW there's no escaping the container when you're doing this intentionally.
I don't know what you mean by this -- if you bind-mount the docker.sock inside a container that container can trivially get root access on the host (AuthZ plugins can make it harder but as I said they are rarely used and cannot protect you from sufficiently clever attackers). My demo with 'mount --bind' was just to show how it worked, the same thing happens with '-v' (which is just a bind-mount under the hood).
Now, if you argue that the code in the container is always something you trust (which I think is a questionable assumption as it assumes that your code is not exploitable) then sure -- if all the code on your machine is safe you have no worries. But then the obvious question arises -- why do you need the isolation properties of containers in the first place? Why not just run in a chroot?
Docker containers are about more than isolation, they're also packaging. In my case, I already have a docker-compose.yaml with five services; adding another program as a chroot instead of a sixth service would significantly increase the installation complexity.
I do agree with you that mounting the Docker socket should never be recommended on a tutorial.
But I might be biased given that while I've worked on both runtimes and image tools, runtimes have a lot more interesting problems so I tend to focus more on them when discussing the benefits of containers. :P
On the second point, I mean that to call it escaping the container is incorrect. If they are given access to the docker socket intentionally, the expectation that it wouldn't be able to do anything with the server outside the container is gone.
We'll have to agree to disagree on this one. I originally wrote a longer explanation of how you need to distill an argument in order for non-domain-experts to get the gist, but if you think I'm manipulative there's not much to be said.
There is an argument to be made that any misconfiguration has a specific niche usecase (otherwise it wouldn't be configurable) -- so telling people to not do something is always "manipulative". But we have security best practices, and we tell people not to misconfigure things. There is a time when you should use 'curl --insecure' but we tell people not to use it because those who know when to use it also know when it is safe to use it.
> And your experience doesn't represent the whole of how Docker is used. [...] This is mixing different uses of Docker.
But running an node package as an unprivileged user on the host doesn't give it free root access on your machine. 'docker run -v /var/run/docker.sock:/var/run/docker.sock:ro' does, and so while you might argue that isolation is not a property everyone is interested in (which might very well be true[+]), the net result is a setup that is more insecure than the equivalent host-side setup (nobody runs node packages as root on the host in production I would hope).
> I mean that to call it escaping the container is incorrect.
It's not though. You are in a container and then you use a misconfiguration to break out of it. Just because it's trivial -- and it is very trivial -- doesn't make it not a container escape. You would use the exact same techniques to break out of a container that had a "real" container escape vulnerability -- namely `nsenter --mount=/host/proc/1/ns/mnt` or similar.
If someone misconfigured sudo on some ISO image to permit everyone to have root access, that would still be a privilege escalation vulnerability even though it caused by an intentional misconfiguration. It might not be as neat as other vulnerabilities, but it is still a vulnerability.
> If they are given access to the docker socket intentionally, the expectation that it wouldn't be able to do anything with the server outside the container is gone.
You say that from a position where you know that docker.sock access is equivalent to root host access. Many people are not aware of this, and are not told this when they are told to bind-mount docker.sock into containers that have potentially insecure software running in them. If everyone knew that this was the case, you might be right in arguing that you've already given up container (or even user) isolation at that point -- but it's not clear enough in my opinion.
[+]: Though I don't see why you should undermine it needlessly -- given that it is the most expensive and complicated parts of setting up a container. Images are effectively just tar archives.
Fortunately ducaale suggested https://hub.docker.com/r/steveltn/https-portal/.
I adapted the site and will publish a follow-up about using this image for nginx - let's encrypt configuration.
By default, docker-machine (which sets up internet-accessible docker instances) uses TLS client certificates, so no, this does not give a "free root-level RCE". This is just spreading FUD. (This does not detract from the parent's point that "access to docker.sock" == "root on the host". That part is true.)
I didn't mention TLS certificates with -H tcp:// because it wasn't really related to the main point I was making -- yes you can configure it to be secure but again security is not the default. I felt so strongly about this I pushed for having a required flag to allow insecure TCP access[2]. I am more than aware this can be done safely, it just isn't done safely often enough that you see this type of misconfiguration in blog posts.
[1]: https://kromtech.com/blog/security-center/cryptojacking-inva... [2]: https://github.com/moby/moby/pull/37299
I guess docker gives you some flexibility for rollover and load balancing, but a single droplet will handle huge amounts of traffic for static sites.
I personally fell for these posts a while back and regretted spending time on it. They don't tell you about the crazy amount of sysadmin skills that you need to get it up and running:
Do you need to worry about updates/security patches? How do you configure firewalls? How do you configure ssh settings? How would you even audit unauthorized logins? Where are logs stored? Are they rotated? Are they backed up? Are there backups? How do you restore from backups? How do you configure nginx? How do you configure certbot? How do you check if cron is running correctly? Do you ever look at access/error logs? How do you keep services running upon restart? How do you get notified of problems? How do you monitor uptime?
Each individual question will take minutes to hours to research and will open up new rabbit holes.
Most {net,dev,sec}ops engineers aren't writing blogs.
Unfortunately, in my experience this is true. It's not for lack of motivation or desire, it's because my day job is stressful and tiring. The last thing I want to do when I come home in the evening is to spend my valuable personal time writing a blog about what I did at work. I would rather spend time with my family, or do something like that.
Of course, I could try to schedule time during work hours to write a blog on the company website by talking with my manager about it. Unless this advances any strategic or political agenda, it's unlikely to happen.
I write a post on my blog about my interests once every month or two, and maybe crosspost it to Facebook, but I like that I get to write down my thoughts on a site I own.
If you don't get much enjoyment out of writing period though, not much reason to blog.
I've found it useful for myself and colleagues, but also it's really awesome seeing hits from Google and other mediums where people are obviously finding it organically and sharing around through various means. Helping others find new / better ways to do things is really awesome
That's all part of the fun for DIY projects like this. Paying someone else to handle it for you isn't really part of the hacker ethos.
I set up DO to host a half dozen websites with a standard LAMP, NginX reverse proxy, and such. Then set up email with horde, spam filtering etc., then realised that managing all of that without breaking anything was going to be a pain in the arse. The web side is relatively straight forward, the email side was really fragile.
So I switched to a shared hosting account for about the same monetary cost.
Generally I enjoy the admin, but I'd be needing a duplicate test system to trial optimisations; a part-time hobby is then looking like a full-time job.
All kidding aside, it is a lot of work, and you have two options: 1) learn these things yourself 2) pay someone else to do them for you.
I'm a fan of #1, as they are valuable skill sets that let you be on the receiving end of option #2.
I'm not a fan of the 'devops' term, generally.
There's tons of value in doing things yourself
Caddy has built-in support for Let’s Encrypt.
I use the dns module which required a little bit of extra work to enable because it’s not included by default but other than that it’s very simple like I said.
Here is the config file for one of my sites:
www.crusaders.pw {
root /var/www/pw.crusaders.www/
expires {
match .htm$ 4h
match /assets/.* 1y
}
tls {
dns cloudflare
}
}
crusaders.pw {
redir https://www.crusaders.pw{uri}
tls {
dns cloudflare
}
}
Then just stick the config file in a git repo.Until you write your first blog post or get a single comment. Then you need backups like everyone else who runs their own shit.
This is usually the most important question to ask about a tool for a project.
However, it is reasonable for the answer to be "because I"ve heard that this tool is useful, and I want to better understand how it is shaped and what things are hard/easy to do with it"
I believe this is referred to as "resume driven development".
I backup everything daily to my Synology at home.
I think that Docker is a great time saver for those who want just to play with a new piece of software, and don't have the time to learn all the details of some arcane install procedure.
That's true, but if you do that in production you're running untrusted code that could do pretty much anything.
If you don't have your own Docker registry full of containers you either made yourself or have audited yourself, you might as well let anyone in the world run their code on your servers.
And if you do have your own registry, it's a lot of work and it involves chasing down libraries and working with arcane install procedures. You can't really trust the public base images unless you fork them and audit them yourself, or just create your own.
At some point you need to take responsibility for your own stack. Docker fine for messing around on your laptop but the real work starts when you need to get past that.
One drawback with NFSN is that it requires people to be somewhat tech savvy and know how to manage sites, probably use ssh, etc. If you’re someone who can use S3 or this solution, then you’ll find NFSN easier and cheaper for this use case.
(Not much has changed since then, and I'm still a happy customer.)
host your blog on https://pages.github.com or https://www.netlify.com
I could imagine a pipeline setup in the future (with the help of web IDE) that will allow authors to write and commit new articles, for editors to edit them and sign them off to the publisher, and the publisher to publish articles to a static site without leaving the browser. Thoughts?
Yes, you can use something like Netlify CMS or Contentful with a static site to get an admin interface, but those would require additional setup or payment beyond github pages or a netlify account.
~$ docker-compose pull
~$ docker-compose up -d --build
The compose files are already using latest, so this pulls the latest images, rebuilds images with any new code, and restarts the services. ~$ git clone https://github.com/jwilder/nginx-proxy
~$ cd nginx-proxy
~$ docker build -f Dockerfile.alpine -t my-own-tag-name/nginx-proxy:alpine .
~$ cd ..
~$ sed -i -e 's/image: jwilder\/nginx-proxy.*/image: my-own-tag-name\/nginx-proxy:alpine/' docker-compose.yaml
Alternately, you could fork the nginx-proxy repo, build it, push it to your own Docker Hub account, and add the Repository Links[1] back to nginx. Then you could use TravisCI to automatically pull in and rebuild changes from the parent nginx-proxy. This way you get automated builds when base is updated, and when nginx-proxy is updated.[1] https://docs.docker.com/docker-hub/builds/#repository-links
The trouble is 9 times out of 10, the only place you find it documented is in some random forum post where cargo-cult silliness gets critiqued, rather than by the folks publishing these how-tos.
Don't get me wrong -- I'm not trying to discourage you from sharing configs and artifacts that work for you. They're valuable information to publish.
I just get terrified when I see folks regularly deploying images maintained by individuals rather than organizations.
For example, I first wrote about nginx-proxy and docker-gen 4 years ago (http://jasonwilder.com/blog/2014/03/25/automated-nginx-rever...). Since then, both projects have gone through continued releases with bug fixes, updates and new features. Between the two projects, there are about 110 different contributors and I am no longer the top contributor on one of them.
The projects are MIT licensed and free to be forked or maintained independently if neeeded.
There’s a large community of users that write blogs, help with issues, and even create derivative works inspired or derived from the project.
Finally, I’d add that a lot of orgs behind projects are really just an individual that wants to make a useful closed source project open for others. The org or company name attached doesn’t necessarily mean a company is going to support it any better than a dedicated individual or community that cares about it.
Also, why Docker and not just an Ansible script?
update:
Found this...
The example you give has 6 config files.... the linked article uses 1 config file. shrug
Since when does X[1] support system-wide configuration/deployment?
But yea, when using Docker already, why not? It's quick and easy compared to all the alternatives.
EDIT: Others are already expressing my point, that this is overkill for a blog.
You can still use a CDN in front of a very tiny VM. Some new blog engines even support running on serverless/FaaS platforms for every easier deployments, and once FaaS evolves into just running Docker containers then the circle will complete and we'll have the best of everything.
Really, you don't even need Ansible.
Just ssh into the box, apt install nginx, run the Let's Encrypt script and install Ghost.
But, sure, you could do it in a more complicated way, or a more manual and time consuming way that isn't documented or automated. I think that's called the "job security" method.
Shouldn't we also be using k8s to orchestrate all the blogs?
That heavily depends on if this is a "learn new tech" thing or not. Some people view setting up a blog as a challenge to solve, and some people just want a blog up and running so they can write. And if this does it in a simple to follow guide that is reliable, the tech behind it doesn't really matter.
For this use-case Netlify is the better option.
Setting up the renew job is also a very simple cron job.
Moreover, something that one forgets is that once you have your posts, comments and any sort of data, you need to have backups and other sysadminy stuff.
Personally, I enjoyed learning about this while setting up my blog :)
COPY ./my_static_files /usr/share/nginx/html
This alone wont get you HTTPS, but I wouldn't be surprised if you can get that working with little effort using docker volumes and certbotWas the app setup improperly, or is that expected that using Docker will make local development more complex?
On the other side you have to track down and figure out how to install or build whatever obscure old Ruby version they're using and dirty your machine installing and running services to support the app. All of which is also painful.
I do client work and I'd rather not dirty my machine installing old or random software to work on a project. So having portable local environments works well for me. But they do take some thought to set up and people often don't take enough care in either case to document the procedure for getting things set up to work on it.
Am I being too cheeky if I point out that setting up a droplet with a WordPress blog on DigitalOcean takes three minutes? :)
(They have a premade image for it)
https://www.digitalocean.com/community/tutorials/how-to-host...
"If your company uses official Caddy binaries internally, in production, or distributes Caddy, a commercial license is required."
So if you are not using the official binaries (for example a community-provided Caddy Docker image) a commercial license is not required.
https://www.digitalocean.com/community/tutorials/how-to-add-...
Dockers cool for doing dev stuff on your laptop, or for scaling out with something like kubernetes. This is just silly!
If so, I will be forever indebted xD
¹ https://github.com/bustle/mobiledoc-kit/blob/master/MOBILEDO...
(Also, the sticky headers are so damn annoying!)
also medium isn't nearly as customizable as your own blog. Can you do this on medium?
Still, there's tons of hosting options where that's not an issue. Running a VPS can be interesting and fun, but if you just want to host a simple site there's easier options that work just as well.
Edited to add: But to scratch the stupid itch I tried hard not to scratch and respond to the other people here, I do this with my own personal blog and it's totally fine. All of my self-hosted software is containerized behind an HTTP reverse proxy. I can do it any number of ways but "Rely on <external third-party service>" seems like a terrible idea to me. And there is no reason whatsoever for all the posts in this thread naysaying this particular way of doing it, any more than there's any particular reason to naysay the suggested alternatives. Do whatever you want. Learn something. Improve your skillset.