Skip to content

Commit

Permalink
Add details and examples in docs for running apps with https (#3213)
Browse files Browse the repository at this point in the history
* docs(section_configuration_deployment): add details and examples for https

* chore: run pre-commit

* feat: make the https example 'executable'

* formatting

* formatting

---------

Co-authored-by: Rodja Trappe <[email protected]>
  • Loading branch information
tmlmt and rodja committed Jun 22, 2024
1 parent 1e2fd06 commit 8eeb8ac
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 2 deletions.
47 changes: 47 additions & 0 deletions examples/nginx_https/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Serving an App with HTTPS encryption behind a Reverse Proxy (NGINX)

This example shows how to serve NiceGUI with HTTPS encryption behind NGINX.
For running the App under a Subpath, have a look at https://github.com/zauberzeug/nicegui/blob/main/examples/nginx_subpath.

## Try Out

1. Create the `certs/` directory:

```bash
mkdir certs
```

2. Generate and self-sign SSL an certificate for `localhost`

```bash
openssl req -x509 -out certs/localhost.crt -keyout certs/localhost.key -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' -extensions EXT -config <( printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
```

3. Run the containerized app

```bash
docker compose up
```

4. Try to access http:https://localhost without the "s".
You will be automatically redirected to the https version.

5. Depending on your browser, you should typically receive a warning that the certificate authority is invalid.
This is perfectly normal as we issued and self-signed a simple certificate for demo use locally.
So proceed anyway, e.g. on Chrome, click on `Advanced` > `Proceed to localhost (unsafe)`

6. Note the Hello World message from the app accessed with encrypted connection

## Deploy in production in your self-hosted NGINX

- For production, you'll need your own domain and a proper SSL certificate issued by a recognized Certificate Authority (CA).
You can consider the free CA [Let's Encrypt](https://letsencrypt.org/) provided by the Internal Security Research Group, and use their [Certbox](https://certbot.eff.org/instructions) tool to generate the certicates for your own domain.

- If you already have an NGINX server running and want to add your NiceGUI app, you can reuse a stripped down version of the nginx.conf file, [nginx_site.conf](https://github.com/zauberzeug/nicegui/blob/main/example/nginx_https/nginx_site.conf)

```bash
sudo cp nginx_site.conf /etc/nginx/sites-available/my_nicegui_app.conf
sudo nano /etc/nginx/sites-available/my_nicegui_app.conf # customize your domain, certificates, port number, etc.
sudo ln -s /etc/nginx/sites-available/mynicegui_app.conf /etc/nginx/sites-enabled
sudo systemctl reload nginx
```
5 changes: 5 additions & 0 deletions examples/nginx_https/app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from nicegui import ui

ui.label('Hello HTTPS encrypted world')

ui.run()
13 changes: 13 additions & 0 deletions examples/nginx_https/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
services:
app:
image: zauberzeug/nicegui:1.4.27
volumes:
- ./app:/app # mount local app directory
proxy:
image: nginx:1.27.0-alpine
ports:
- "80:80" # map internal port 80 to external port 80
- "443:443" # map internal port 443 to external port 443
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf # use custom nginx config
- ./certs:/certs
53 changes: 53 additions & 0 deletions examples/nginx_https/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
worker_processes 1;

events {
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;


sendfile on;
keepalive_timeout 65;

server {
listen 80;
listen [::]:80;
server_name _;
resolver 127.0.0.11; # Specific to running nginx proxy in docker
# See https://github.com/docker/compose/issues/3412

# Redirect all HTTP requests to HTTPS
return 301 https://$host$request_uri;
}

server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name _;
resolver 127.0.0.11; # Specific to running nginx proxy in docker
# See https://github.com/docker/compose/issues/3412

# SSL configuration
ssl_certificate /certs/localhost.crt;
ssl_certificate_key /certs/localhost.key;
ssl_session_timeout 1d;

# Proxy pass to app:8080
location / {
proxy_pass http:https://app:8080;
proxy_redirect http:https://app:8080/ /;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
}
32 changes: 32 additions & 0 deletions examples/nginx_https/nginx_site.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
server {
listen 80;
listen [::]:80;
server_name my-domain.com;

# Redirect all HTTP requests to HTTPS
return 301 https://$host$request_uri;
}

server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name my-domain.com;

# SSL configuration
ssl_certificate /etc/letsencrypt/live/my-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/my-domain.com/privkey.pem;
ssl_session_timeout 1d;

# Proxy pass to localhost:8080
location / {
proxy_pass http:https://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
28 changes: 26 additions & 2 deletions website/documentation/content/section_configuration_deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,33 @@ def docker_compose():
There are other handy features in the Docker image like non-root user execution and signal pass-through.
For more details we recommend to have a look at our [Docker example](https://github.com/zauberzeug/nicegui/tree/main/examples/docker_image).
You can provide SSL certificates directly using [FastAPI](https://fastapi.tiangolo.com/deployment/https/).
To serve your application with [HTTPS](https://fastapi.tiangolo.com/deployment/https/) encryption, you can provide SSL certificates in multiple ways.
For instance, you can directly provide your certificates to [Uvicorn](https://www.uvicorn.org/), which NiceGUI is based on, by passing the
relevant [options](https://www.uvicorn.org/#command-line-options) to `ui.run()`:
''')


@doc.ui
def uvicorn_ssl():
with python_window('main.py', classes='max-w-lg w-full'):
ui.markdown('''
```python
from nicegui import ui
ui.run(
port=443,
ssl_certfile="<path_to_certfile>",
ssl_keyfile="<path_to_keyfile>",
)
```
''')


doc.text('', '''
In production we also like using reverse proxies like [Traefik](https://doc.traefik.io/traefik/) or [NGINX](https://www.nginx.com/) to handle these details for us.
See our development [docker-compose.yml](https://github.com/zauberzeug/nicegui/blob/main/docker-compose.yml) as an example.
See our development [docker-compose.yml](https://github.com/zauberzeug/nicegui/blob/main/docker-compose.yml) as an example based on traefik or
[this example nginx.conf file](https://github.com/zauberzeug/nicegui/blob/main/examples/nginx_https/nginx.conf) showing how NGINX can be used to handle the SSL certificates and
reverse proxy to your NiceGUI app.
You may also have a look at [our demo for using a custom FastAPI app](https://github.com/zauberzeug/nicegui/tree/main/examples/fastapi).
This will allow you to do very flexible deployments as described in the [FastAPI documentation](https://fastapi.tiangolo.com/deployment/).
Expand Down

0 comments on commit 8eeb8ac

Please sign in to comment.