Skip to content
This repository has been archived by the owner on Jul 15, 2022. It is now read-only.

Add Docker support #28

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

alfonsomunozpomer
Copy link
Contributor

@alfonsomunozpomer alfonsomunozpomer commented Dec 29, 2020

To spin up a container just do:

docker build -t sitejs .
docker run -p 80:80 -p 443:443 sitejs

Since running sysctl within a Docker container is not allowed I added a flag for the serve command to skip disabling privileged ports on Linux via sudo sysctl .... I haven’t added documentation of this flag in README.md since I’m not sure how you’d like to handle this.

Regarding the Dockerfile itself, I first had in mind building Site.js in the host machine and then add it to the container via COPY. However, on my first go at it, running Site.js in the container complained about libc versions, so I decided to better build the app in the image. The biggest downside of this method is that the resulting image is a whopping 1.2 GB. Another option could be to have two containers, one that builds the app and produces the executable site and then copy it to a second container. I’ve tried it and the resulting image is ~200 MB. The downside is that the whole process isn’t self-contained in a single step.

To build Site.js in the container I had to replace your self-hosted patched version of Nexe with version 3.3.7. If I didn’t, running npm install would produce a node_modules/nexe directory which missed a required lib directory. This didn’t happen outside the container, so it’s really puzzling and if somebody has enough free time to investigate what’s going on I’d love to hear why.

A limitation is that within Docker you can’t run the command enable, again due to Docker’s limitations (no systemd or systemctl). However, since the service unit runs serve I think that’s fine, it fits with the Docker/container philosophy of one container, one process.

By default the resulting container runs site serve /var/www/html --docker but you can pass any command you like, e.g.:

docker run sitejs help

@aral I was worried about the validity of SSL certificates but I’ve seen the current behaviour is fine. I need to test globally-trusted certificates. I’ll let you know. Other than that I think the remaining point to work on is to consider whether to run it as a regular user. Any thoughts?

@alfonsomunozpomer
Copy link
Contributor Author

alfonsomunozpomer commented Dec 31, 2020

I tried setting a Site.js Docker site with globally-trusted certificates and it worked really well.

If you run it following the conventions described in Deployment and you map /home/site/public to /var/www/html you can then use the push and pull commands, which is just so nice. 😄

$ id
uid=1001(site) gid=1001(site) groups=1001(site),27(sudo),998(docker)
$ pwd
/home/site
$ docker run -p 80:80 -p 443:443 -v /home/site/public:/var/www/html sitejs /var/www/html @hostname --domain=my.domain --aliases=subdomain,my.other.domain --docker"

Lastly, when using Docker, certificates signed by the container aren’t trusted by the host. It might be worth considering mounting the host’s certificate store in the container (or sign the the certificate with the host’s key) to make the development experience friendlier. As it stands, you need to add an exception to the browser, similar to Accessing your local server over the local area network.

@alfonsomunozpomer
Copy link
Contributor Author

I’ve been working on the Dockerfile to add a site user but I’ve run into the issue of privileged ports:

   🐁    ❨site.js❩ Watching for changes to dynamic and wildcard routes.
(node:992) UnhandledPromiseRejectionWarning: Error: listen EACCES: permission denied 0.0.0.0:80
    at Server.setupListenHandle [as _listen2] (net.js:1296:21)
...

There are two ways to solve this issue:

  1. Run the container with the option --sysctl net.ipv4.ip_unprivileged_port_start=0
  2. In both auto-encrypt and auto-encrypt-localhost allow to listen to a port other than 80 (e.g. 8080) in the same way that the HTTPS port can be set to a value other than 443, and expose whatever ports we use that aren’t in the privileged range and map them to 80 and 443 in the host.

The first option has the downside of being less flexible: you must pass a sysctl option when running the container, something that should be documented. It’s got the big advantage that the code doesn’t need to change.

The second option allows for more flexibility (in principle it doesn’t even preclude you from using the defaults 80/443 provided you pass the sysctl option), but HttpServe.js in auto-encrypt and HttpServer.js in auto-encrypt-localhost should be parameterised rather than listen to port 80.

I can push the changes for the Dockerfile if that’s better than running as root or I can open it in a separate PR.

@alfonsomunozpomer
Copy link
Contributor Author

@aral If you want to check a site running with Site.js on Docker without root (user site, container running wih --sysctl parameter): https://blog.nestedcode.dev

😄

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant