Glenn Strycker
Glenn Strycker

Reputation: 4878

How do I deploy an AWS EC2 Flask application to HTTPS port 443 with SSL?

I am unable to get my Flask application to run on https://my.domain/, although it does successfully deploy to the regular http://my.domain/

I was able to successfully obtain and test SSL certificates and verify they work on a Jupyter Notebook instance at https://my.domain:8888/

I was able to modify /etc/httpd/conf/httpd.conf to get access to my root home directory at https://my.domain/ -> /home/username/code/

I am also able to successfully redirect http requests to https, but the landing page is just an linux explorer, not my Flask application.

That is, even after extensive editing of httpd.conf, ssl.conf, and wsgi.conf to launch the Flask application on port 443, it does not do so, but remains on port 80.

Also, I noticed that whenever I deploy my code changes via AWS CodeStar, the deployment overwrites my EC2 instance /etc/httpd/conf.d/wsgi.conf file.

Is there a setting somewhere on the Amazon side that I must configure so that my application deploys to the correct port? Or do I need to edit config files on my EC2 instance server? Or is something else wrong?

Upvotes: 2

Views: 9586

Answers (1)

Glenn Strycker
Glenn Strycker

Reputation: 4878

In order to get HTTPS/SSL to work for Flask so that Flask runs on 2 ports, you will first want to follow the tips here: Https with Http in Flask Python

However, this will only set up your Flask code to run with SSL. It won't actually launch the Flask process upon deployment. For that you will need to edit your /etc/httpd/conf.d/wsgi.conf script to launch a second instance of the wsgi daemon.

Your default script for wsgi.conf should contain a section for port 80. You want to copy this section, add your SSL parameters, and then edit the wsgi command to have a different variable name, otherwise Apache will complain when you launch. I have the following added:

  <VirtualHost *:443>
  ServerName <MY SERVER NAME>
  ServerAlias <MY SERVER NAME>
  SSLEngine on
  SSLCertificateFile    <Server PEM file>
  SSLCertificateKeyFile <Private Key PEM file>
  SSLProtocol all -SSLv2 -SSLv3
  SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
  SSLHonorCipherOrder on
  Alias /static/ /opt/python/current/app/static/
  <Directory /opt/python/current/app/static/>
  Order allow,deny
  Allow from all
  </Directory>
  WSGIScriptAlias / /opt/python/current/app/application.py
  <Directory /opt/python/current/app/>
    Require all granted
  </Directory>
  WSGIDaemonProcess wsgi2 processes=1 threads=15 display-name=%{GROUP} \
    python-path=/opt/python/current/app:/opt/python/run/venv/lib64/python3.4/site-packages:/opt/python/run/venv/lib/python3.4/site-packages user=wsgi group=wsgi \
    home=/opt/python/current/app
  WSGIProcessGroup wsgi2
  </VirtualHost>

Note that you can also edit the port 80 section at this time to remove wsgi and instead have a redirect to 443, as explained here: Redirect to Https using Elastic Beanstalk ELB and Redirect HTTP to HTTPS Apache2

Test this configuration by resetting the Apache server using

sudo service httpd restart

And then launch your development server

python application.py

or

sudo /home/ec2-user/anaconda3/bin/python application.py

You should then see Flask running on TWO ports!

However, note that if you are running this on your EC2 instance, your code may already be deployed and running, so you ports could be in-use and you will see "OSError: [Errno 98] Address already in use"

But you are not done yet... oh no, there is one more gotcha...

I discovered THIS following fact from https://forums.aws.amazon.com/thread.jspa?threadID=163369 (see also the Stackoverflow questions what is difference between commands and container commands in elasticbean talk, Configure apache on elastic beanstalk, wsgi user permissions on elastic beanstalk) ...

Evidently EC2 deployment via CodeStar and Elastic Beanstalk DOES overwrite your /etc/httpd/conf.d/wsgi.conf file. In order to prevent/correct this, you need to edit your .ebextensions configuration scripts to use your own wsgi.conf file. Note that this has the downside of not tracking updates that Amazon may be making to their default script.

First I copied the wsgi.conf file I want to keep to the .ebextensions directory.

Next, I edited my .ebextensions/sshd.config file (the only one I have in that directory) to add the following:

files:
  "/etc/httpd/conf.d/wsgi.conf" :
    mode: "000777"
    owner: root
    group: root
    content: |
      <IfModule !wsgi_module>
      LoadModule wsgi_module modules/mod_wsgi.so
      </IfModule>
      . . .
      <VirtualHost *:443>
      . . .
      </VirtualHost>
      LogFormat "%h (%{X-Forwarded-For}i) %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

Then, after the "files:" section, I add the following to the end of the configuration:

container_commands:
  02_update_wsgi:
    command: >
      cp .ebextensions/wsgi.conf ../wsgi.conf

Note that the above uses CONTAINER_COMMANDS, not COMMANDS.

The great thing about this technique is that Elastic Beanstalk automatically runs the Apache server restart command, so after you deploy you do not need to copy anything manually or re-run "sudo service httpd restart"

Following the above steps will get your Flask running on HTTPS with SSL certificates AND deploy correctly.

Upvotes: 3

Related Questions