wodby / docker4drupal

Docker-based Drupal stack
https://wodby.com/docker4drupal
MIT License
1.24k stars 531 forks source link

Drupal with https #50

Open webfordreams opened 7 years ago

webfordreams commented 7 years ago

I have installed a basic Drupal set up, using the example docker-composer.yml. For my project I need the Drupal site accessed through https, though. How can that be managed through the Docker containers of docker4drupal?

Thank you very much for clarifying.

pprishchepa commented 7 years ago

@webfordreams HTTPS isn't configurable yet, but you can override default Nginx config via Docker volumes.

spleshka commented 7 years ago

Have you got the implementation of this feature in plans? Https becomes a standard for all good & reliable web projects, and I'm sure the local dev environment should support it out of the box. Sorry to admit, but it's a bad idea to push developers to either not using https on local (which might lead to uncaught bugs related to protocol) or to ask them to do it themselves. It's certainly supposed to be quite standard functionality of all dev boxes.

pprishchepa commented 7 years ago

Yes HTTPS support is must-have feature and we plan to implement it. We plan to integrate traefik - reverse proxy tool. It'll allow to terminate HTTPS and access services via myproject.local instead of localhost:8000.

spleshka commented 7 years ago

Brilliant, both features are really needed and will add a cherry on your current pie ;) Let me know if I can help.

MXTcomunica commented 7 years ago

I need this feature too: thank you very much for your work!!!

csandanov commented 7 years ago

We now have traefik container, you can configure if you need HTTPS

alesrebec commented 7 years ago

That's nice @csandanov.

Those are now my traefik settiings in docker-compose.yml

traefik:
image: traefik
    restart: unless-stopped
    command: -c /dev/null --web --docker --logLevel=INFO
    ports:
      - '80:80'
      - '443:443'
      - '8080:8080'
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

What else do I need to set up to get that routed properly?

cbeier commented 7 years ago

To get the https to work you don't need to add the port 443 ssl to the nginx config. The ssl part is only handled by an traefik entrypoint. Traefik gives than the request to nginx via port 80.

I use the default docker4drupal and to get the ssl to work I have only adjusted the docker-compose.yml:

traefik:
    image: traefik
    restart: unless-stopped
    command: -c /dev/null --web --docker --logLevel=INFO --defaultEntryPoints='https' --entryPoints="Name:https Address::443 TLS:/certs/cert.pem,/certs/key.pem" --entryPoints="Name:http Address::80 Redirect.EntryPoint:https"
    ports:
      - '80:80'
      - '443:443'
      - '8080:8080'
    volumes:
      - ./certs:/certs/
      - /var/run/docker.sock:/var/run/docker.sock

The decisive parts are the command line and the reference to the certificate files (I've included this via a volume share).,

Please not that with this configuration all hosts needs to be requested via https. Also e.g. phpMyAdmin: "https://pma.drupal.docker.localhost".

alesrebec commented 7 years ago

Great! Thanks for that @cbeier

alesrebec commented 7 years ago

I'm getting browser errors when using traefik to route https requests:

Mixed Content: The page at 'https://example.docker.localhost/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://example.docker.localhost/home?page=1'. This request has been blocked; the content must be served over HTTPS.

Is this because nginx still uses port 80 to communicate between containers? If I set the port in nginx container config to 443 I get "Bad Gateway".

pprishchepa commented 7 years ago

@alesrebec

If I set the port in nginx container config to 443 I get "Bad Gateway".

You should revert it to 80.

Then try to add the following one in the settings.php:

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
  $_SERVER['HTTPS'] = 'on';
}

It works for D7. I'm not sure about D8.

alesrebec commented 7 years ago

$_SERVER['HTTPS'] = 'on'; was already 'on' for me. Funnily I digged into $_SERVER settings and changed $_SERVER['SERVER_PORT'] from 80 to 443 and I got rid of Mixed Content errors! Now I have to tell nginx to report port 443 for PHP SERVER_PORT variable so I can get rid of this from settings.php file. Thanks Pavel.

pprishchepa commented 7 years ago

@alesrebec ok, but looks like a dirty hack :) usually $_SERVER['HTTPS'] = 'on'; is enough.

alesrebec commented 7 years ago

It's for local development only... I would still prefer a better solution.

cbeier commented 7 years ago

@alesrebec

nginx must use the port 80.

You can set the $_SERVER['HTTPS'] = 'on' only for your local environment with the 'settings.local.php' file.

Uncomment in your settings.php the lines:

if (file_exists(__DIR__ . '/settings.local.php')) {
  include __DIR__ . '/settings.local.php';
}

And then set the $_SERVER['HTTPS'] = 'on' inside the settings.local.php file (/sites/default/settings.local.php).

walkero-gr commented 7 years ago

@cbeier Thank you for your solution above. I wonder how did you generate the certs? Whatever I currently tried didn't work and the traefik docker keeps restarting.

cbeier commented 7 years ago

@walkero-gr I generate the certs outside of docker. It is not a set inside of the composer build.

I use this command: openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /certs/key.pem -out /certs/cert.pem (adjust the paths to your needs)

And then I share the certs folder with the docker traefic container.

walkero-gr commented 7 years ago

@cbeier Thank you. It worked just fine on my system. In case you have many domains and one traefik container, then every domain works with the same certificates?

cbeier commented 7 years ago

@walkero-gr Great to hear. Yes, every domain works with this / the same certificate.

RobLoach commented 7 years ago

Through traefik, I had to...

  1. Update the traefik service command to:

    command: -c /dev/null --web --docker --logLevel=DEBUG --defaultEntryPoints='https' --entryPoints="Name:https Address::443 TLS:/certs/crt.txt,/certs/key.txt" --entryPoints="Name:http Address::80"
  2. Generate a cert and key and place at certs/crt.txt and certs/key.txt as cbeier outlined above. http://www.selfsignedcertificate.com worked as well.

ilibilibom commented 7 years ago

Hi I'm trying to get ssl to work. I added the values to the traefik service - but i'm getting an error (see below).

This is my yml file

version: "2"

services:
  mariadb:
    image: wodby/mariadb:10.1-2.3.3
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress

  php:
    image: wodby/wordpress-php

    environment:
      PHP_SENDMAIL_PATH: /usr/sbin/sendmail -t -i -S mailhog:1025
setting bellow
alias 10.254.254.254'
    volumes:
      - ./:/var/www/html
  nginx:
    image: wodby/wordpress-nginx:4-1.13-2.2.0
    environment:
      NGINX_STATIC_CONTENT_OPEN_FILE_CACHE: "off"
      NGINX_ERROR_LOG_LEVEL: debug
      NGINX_BACKEND_HOST: php
      NGINX_SERVER_ROOT: /var/www/html
    volumes:
      - ./:/var/www/html
    depends_on:
      - php
    labels:
      - 'traefik.backend=nginx'
      - 'traefik.port=80'
      - 'traefik.frontend.rule=Host:wp.docker.localhost'

  mailhog:
    image: mailhog/mailhog
    labels:
      - 'traefik.backend=mailhog'
      - 'traefik.port=8025'
      - 'traefik.frontend.rule=Host:mailhog.wp.docker.localhost'

  portainer:
    image: portainer/portainer
    command: --no-auth
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - 'traefik.backend=portainer'
      - 'traefik.port=9000'
      - 'traefik.frontend.rule=Host:portainer.wp.docker.localhost'

  traefik:
    image: traefik
    restart: unless-stopped
    command: -c /dev/null --web --docker --logLevel=INFO --defaultEntryPoints='https' --entryPoints="Name:https Address::443 TLS:/certs/cert.pem,/certs/key.pem" --entryPoints="Name:http Address::80 Redirect.EntryPoint:https"
    ports:
      - '80:80'
      - '443:443'
      - '8080:8080'
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./certs:/certs/
volumes:
  codebase:

After running docker-compose up -d i'm getting the following error:

ERROR: for jfrognew2_traefik_1  Cannot start service traefik: driver failed programming external connectivity on endpoint jfrognew2_traefik_1 (b31878d0f6bc7c67f7150846ee514ffd35120789c22ce6b19e9e3eae9df76d20): Error starting userland proxy: Bind for 0.0.0.0:80: unexpected error (Failure EADDRINUSE)

ERROR: for traefik  Cannot start service traefik: driver failed programming external connectivity on endpoint jfrognew2_traefik_1 (b31878d0f6bc7c67f7150846ee514ffd35120789c22ce6b19e9e3eae9df76d20): Error starting userland proxy: Bind for 0.0.0.0:80: unexpected error (Failure EADDRINUSE)
ERROR: Encountered errors while bringing up the project.

Can anyone help solve this bug ?

Thanks

ilibilibom commented 7 years ago

OK - I managed to solve the issue above by stoping the local apache (I didn't know existed) on my local mac. Now after running composer-install i'm getting the following error in bowser -

This site can’t provide a secure connection

I added my cert.pem file to the trusted cert's on chrome What seems to be the issue here ?

ilibilibom commented 7 years ago

And here is the message I get in Firefox

An error occurred during a connection to wp.docker.localhost:8000. SSL received a record that exceeded the maximum permissible length. Error code: SSL_ERROR_RX_RECORD_TOO_LONG

michaelpporter commented 7 years ago

I ran in to an issue when I am using træfik in multi site mode where the same site is pulled up.

version: '2'
services:
    traefik:
        image: traefik
        restart: unless-stopped
        command: -c /dev/null --web --docker --logLevel=INFO --defaultEntryPoints='https' --entryPoints="Name:https Address::443 TLS:/certs/cert.pem,/certs/key.pem" --entryPoints="Name:http Address::80 Redirect.EntryPoint:https"
        networks:
            - sites
            - jenkins
            - site2
        ports:
            - '80:80'
            - '443:443'
            - '8080:8080'
            - '9000:9000'
        volumes:
            - '/var/run/docker.sock:/var/run/docker.sock'
            - './traefik/test:/certs'
    portainer:
        image: portainer/portainer
        command: '--no-auth'
        volumes:
            - '/var/run/docker.sock:/var/run/docker.sock'
        labels:
            - traefik.backend=portainer
            - traefik.port=9000
            - 'traefik.frontend.rule=Host:dashboard.docker.localhost,portainer.docker.localhost'
networks:
    sites:
        external:
            name: sites_default
    jenkins:
        external:
            name: jenkins_default
    site2:
        external:
            name: site2_default

Jenkins is a drupal 8 site site2 is wordpress. I get the drupal 8 site on https.

michaelpporter commented 7 years ago

I forgot to update one of the backends

traefik.backend=site2_nginx_1'

I still get redirect loops on that one but that is different from this issue queue.

SummittDweller commented 6 years ago

Hoping someone is still watching this issue. I've built a multi-site local server largely using the above .yml from @michaelpporter, and it works nicely EXCEPT that I'm unable to open my portainer, perhaps the most important piece of this puzzle at this early stage. I've got a localhost alias of portainer.docker.localhost in my /etc/hosts, among other aliases, but when I try to open https://portainer.docker.localhost:9000 I get the following...

Secure Connection Failed

The connection to portainer.docker.localhost:9000 was interrupted while the page was loading.

The page you are trying to view cannot be shown because the authenticity of the received data could not be verified.

This message includes no opportunity to allow the exception. All my other site aliases report that my self-signed cert is suspect, but they all permit me to accept the exception.

Any clue what I'm doing wrong here?

My .yml file reads...

version: '2'

services:

   traefik:
       image: traefik
       restart: unless-stopped
       command: -c /dev/null --web --docker --logLevel=INFO --defaultEntryPoints='https' --entryPoints="Name:https Address::443 TLS:/certs/cert.pem,/certs/key.pem" --entryPoints="Name:http Address::80 Redirect.EntryPoint:https"
       networks:
           - project1
           - project2
       ports:
           - '80:80'
           - '443:443'
           - '8080:8080'
           - '9000:9000'
       volumes:
           - '/var/run/docker.sock:/var/run/docker.sock'
           # - './traefik/test:/certs'
           - ./certs:/certs/     # per cbeier at https://github.com/wodby/docker4drupal/issues/50

   portainer:
       image: portainer/portainer
       command: '--no-auth'
       volumes:
           - '/var/run/docker.sock:/var/run/docker.sock'
       labels:
           - traefik.backend=portainer
           - traefik.port=9000
           - 'traefik.frontend.rule=Host:dashboard.docker.localhost,portainer.docker.localhost'

networks:
   project1:
       external:
           name: site1_default
   project2:
       external:
           name: site2_default
michaelpporter commented 6 years ago

Have you tried the URL without the port? https://portainer.docker.localhost

SummittDweller commented 6 years ago

Thanks for the reply @michaelpporter. Yes, when I try connecting via https but without the port number I consistently get a "Gateway Timeout" error after about 30 seconds.

I did find that I was not receiving an opportunity to allow the https exception apparently because some old info was stored in my Firefox profile. I switched to Chrome and was allowed to bypass the exception there; however, if I try without the port number I get the timeout message. When I include the port :9000 suffix, in either Chrome or Firefox, I get an immediate "Unable to Connect" response.

My TraefIk service IS responding at http://traefik.summittservices.com:8080/dashboard/#/ where I've pushed my local tests to a Digital Ocean droplet so others could see it. If you happen to look there you'll see that my backend services have an odd mix of 172.24..., 172.25..., and 172.26... addresses, but I don't understand Docker networking to know what I should expect to see, or how to properly control it.

Note also that I'm continuing to experiment with configuration changes so the topology of summittservices.com might be changing as you read this. Thanks again.

michaelpporter commented 6 years ago

@SummittDweller

docker-compose will create a alpha numeric network based on the folder name. I my experience it will remove dashes and underscores:

folder network
foo foo
bar bar
foo-bar foobar
foobar foobar

Each network will get it's own subnet

172.24..., 172.25..., and 172.26...

Træfik listens to all of docker

- '/var/run/docker.sock:/var/run/docker.sock'

Træfik listens on the entry points defined

--defaultEntryPoints='https,http' --EntryPoints='http'

and route to the container defined:

- 'traefik.frontend.rule=Host:portainer.docker.localhost' - 'traefik.frontend.rule=Host:drupal.docker.localhost' - 'traefik.frontend.rule=Host:foobar.docker.localhost'

The Træfik port is the port the container responds to, not the port you connect to.

Træfik backend is the name of the container to route to

Since your docker is on DigitalOcean not local try changing the frontend rules like

       - 'traefik.frontend.rule=Host:portainer.summittservices.com'
       - 'traefik.frontend.rule=Host:foobar.summittservices.com'

Then browse to https://portainer.summittservices.com

I assume you have valid wildcard certs for *.summittservices.com on your server in the ./certs folder of your træfik setup. And they are called:

SummittDweller commented 6 years ago

Thanks @michaelpporter.

I moved my Portainer container out of my general "server" stack where TraefIk lives, and parked it in parallel with the sites themselves, and now Portainer is accessible at https://portainer.summittservices.com as expected. Next step, figuring out how to properly password protect that instance of Portainer.

...And that was just a matter of flushing a cache! Whew. Glad all of that is behind me now.

Again, thanks for the guidance! Take care.

jvandenrym commented 6 years ago

To get the https to work you don't need to add the port 443 ssl to the nginx config. The ssl part is only handled by an traefik entrypoint. Traefik gives than the request to nginx via port 80.

I use the default docker4drupal and to get the ssl to work I have only adjusted the docker-compose.yml:

traefik:
    image: traefik
    restart: unless-stopped
    command: -c /dev/null --web --docker --logLevel=INFO --defaultEntryPoints='https' --entryPoints="Name:https Address::443 TLS:/certs/cert.pem,/certs/key.pem" --entryPoints="Name:http Address::80 Redirect.EntryPoint:https"
    ports:
      - '80:80'
      - '443:443'
      - '8080:8080'
    volumes:
      - ./certs:/certs/
      - /var/run/docker.sock:/var/run/docker.sock

The decisive parts are the command line and the reference to the certificate files (I've included this via a volume share).,

Where did you put the cert directory? In the root of your project How to download the cert files?

alesrebec commented 6 years ago

Check the line where word "command" is. You will see "/certs/cert.pem,/certs/key.pem" You need to create "certs" folder where your docker-compose.yml file is and put those two files in. The certificate and key. (The names may vary)

Of course that means you have to generate the ssl certificate before that. If you don't have that step, just check here how to get it. Or self-sign it if you need it for testing only.

kevinquillen commented 5 years ago

So for a project with multiple developers, are you saying someone has to generate a self signed cert for local development and commit it to the project? Then have it removed in the build process? I tried setting this up and was able to get https/443 traffic to work, but none of my CSS/JS assets would serve over https, and instead http only - which was refused. I couldn't figure out why.

Surely there must be a simpler way to set this up? For example, Lando takes care of this for you with no additional configuration needed for local dev.

kevinquillen commented 5 years ago

Gave this another shot - it worked this time without the hassle.

kevinquillen commented 5 years ago

There is more to it than this for local development. I had to use an extended command to generate a self signed cert (macOS) like so:

openssl req -newkey rsa:2048 -x509 -nodes -keyout cert.key -new -out cert.crt -subj /CN=*.docker.localhost -reqexts SAN -extensions SAN -config <(cat /etc/ssl/openssl.cnf <(printf '[SAN]\nsubjectAltName=DNS:*.docker.localhost')) -sha256 -days 3650

Chrome requires subject alternative name to be set otherwise you get an error about "CERT_COMMON_NAME_INVALID". After that, I added the generated cert to my keychain and set it to always trust (its for local dev) and now Chrome reports my site as fully secure/trusted without any SSL errors. Not sure how to get Firefox to do this yet though.

This article really helped:

https://jimfrenette.com/2018/03/ssl-certificate-authority-for-docker-and-traefik/

But IMHO, it would be fantastic if this came out of the box like Lando does for SSL:

https://docs.devwithlando.io/config/security.html

Some sort of flag for local vs deployment (where you wouldn't want them).

kevinquillen commented 5 years ago

This article also helped:

https://medium.com/@hunk/self-assigned-ssl-with-docker-for-dev-domains-1396f71c0b77

Force quitting and restarting all browsers got Firefox to accept the cert without error.

jakub-mroz commented 5 years ago

Hi guys, I am building a Drupal-powered platform (with Visual Builder) for small and medium businesses so they can also benefit from Digital Transformation.

But... I have a problem with HTTPS.

After reading the following article https://medium.com/@pentacent/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71

I started to tinker with Nginx but with Wodby everything is already built and I am not sure what's the best practice here.

  1. To use clean Docker Nginx from the hub where I can mount my own VHOST
  2. Is there a way of passing custom VHOST for Wodby's Nginx?
  3. You are writing about using a proxy with Traefik but is it the best practice or just a walk-around?

Which option is the best?

Thank you for help in advance.

jakub-mroz commented 5 years ago

You can generate certificates supported by self-spinning temp webserver with sudo certbot certonly.

iVegas commented 5 years ago

Also, you can define the configuration file for the traefik and configure https configurations there:

traefik:
    image: traefik
    restart: unless-stopped
    command: -c /traefik.toml --web --docker --logLevel=INFO
    ports:
      - '80:80'
      - '443:443'
      - '8080:8080'
    volumes:
      - ./certs:/certs/
      - ./traefik.toml:/traefik.toml
      - /var/run/docker.sock:/var/run/docker.sock

In configurations traefik.toml file use preffered trefik configuration using traefik configuration examples here: https://docs.traefik.io/user-guide/examples/#http-redirect-on-https

Mykola-Veryha commented 5 years ago

For making locally-trusted SSL certificates you can use the simple tool mkcert

devkinetic commented 5 years ago

d4d should be shipped with this config per @iVegas suggestion. Update the docs to point at installing certs for your domains. Perhaps the container could build one via script or dockerfile, so its out of the box?

artemvd commented 2 years ago

If you need just https without any features for local development then it is worth checking this comment https://github.com/wodby/docker4drupal/issues/407#issuecomment-559418553