Putting a shell or a desktop in your Django app

This video features Florian Haas and Maari Tamm at DjangoCon Europe 2021 in Online.

Putting a shell or a desktop in your Django app
0:22:37
Published June 27, 2021
979 views

In our City Cloud Academy (https://academy.citycloud.com) learning platform, we enable learners to interact with real-world hands-on lab environments, so that they can learn complex technologies like OpenStack, Kubernetes, Terraform, Ceph, Ansible, and others. To do that, we use Apache Guacamole (https://guacamole.apache.org/)'s guacd service to provide learners with interactive shell terminals — or even full desktop environments — that run right in people's browsers, no additional software required.

The Guacamole platform is normally deployed in conjunction with a Java servlet environment (https://guacamole.apache.org/doc/gug/guacamole-architecture.html#web-application) (commonly Apache Tomcat). But the Guacamole protocol is not tied to the Java language in any way, and a Python websocket proxy (pyguacamole (https://pypi.org/project/pyguacamole/)) is readily available under an open source (MIT) license.

In this talk, we discuss how we implemented a learning platform (based on Open edX (https://open.edx.org)) that deploys an ASGI service under Daphne (https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/daphne/), uses pyguacamole to provide an asynchronous websocket connection to a Guacamole service, and thus creates a highly scalable, interactive, and immersive learning environment that helps people learn complex technology with no hardware or cloud investment at all.

Slides

The slides (with full speaker notes) are up at https://fghaas.github.io/djceu2021 and https://mrtmm.github.io/djceu2021.

Summary

Interactive terminals and desktops can be embedded in a Django learning platform so learners practise on real, distributed cloud labs rather than just reading or watching demonstrations. The speakers explain Apache Guacamole’s architecture: guacd connects to SSH or RDP targets and converts their traffic to the Guacamole protocol, while a client converts that stream to WebSockets for browser-side JavaScript. They show how PyGuacamole and Django Channels provide a pure-Python asynchronous client and WebSocket consumer, allowing connection details such as credentials and keys to come directly from Django models without introducing a Java servlet application. The example is deployed with Daphne, Supervisor, and Nginx alongside conventional Django/Gunicorn services, with browser events travelling back through the same layers to the remote system.

Key takeaways

  • Cloud-hosted interactive labs let learners practise distributed technologies on real environments without relying on scarce hardware labs.
  • Apache Guacamole translates SSH, RDP, or VNC traffic into a browser-friendly event stream, with JavaScript rendering the remote session.
  • PyGuacamole replaces Guacamole’s usual Java servlet client with a Python client that can access Django models directly.
  • A Django Channels asynchronous WebSocket consumer forwards data between PyGuacamole and the browser in fewer than 100 lines of code.
  • Daphne serves the WebSocket application while Nginx proxies it alongside regular Django applications running through Gunicorn and WSGI.

Summarised automatically from the transcript.

Chapters

  1. 0:00 Interactive Labs in Django The presenters introduce their learning platform and demonstrate browser-based terminal and desktop lab environments.
  2. 3:21 The Guacamole Architecture The talk narrows its focus to how Apache Guacamole provides interactive terminal and desktop sessions in a browser.
  3. 4:08 Guacamole Server and Client The presenters explain GuacD, the Guacamole protocol, the Java client, and the browser-side rendering architecture.
  4. 8:54 Embedding Guacamole in Django They motivate bypassing the standard Java servlet application to connect Guacamole directly to Django data and deployment workflows.
  5. 11:19 PyGuacamole and Django Channels The talk introduces the Python Guacamole client and the WebSocket-based Django Channels layer needed for browser communication.
  6. 12:57 The WebSocket Consumer The presenters walk through the Django view, asynchronous consumer, database lookup, connection parameters, event forwarding, and read-only mode.
  7. 17:35 Running Daphne Behind Supervisor They cover routing and settings, then show how Daphne and Supervisor run the asynchronous Django application.
  8. 18:34 Nginx Service Integration The talk explains how the synchronous LMS and asynchronous Guacamole client are deployed together behind Nginx.
  9. 19:22 End-to-End Event Flow The presenters trace desktop and keyboard events from the upstream server through GuacD, PyGuacamole, Django, Nginx, and the browser.
  10. 21:32 References and Further Reading The talk closes with links, licenses, and references for PyGuacamole, Open edX, Apache Guacamole, and the presentation materials.

Transcript

3,526 words · auto-generated Show

Automatically transcribed, so expect mistakes in names and technical terms.

0:09

Speaker 1: Hi, I'm Mari.

0:11

Speaker 2: And I'm Florian. And you're here to talk to you about how to get interactive, putting a shell or a desktop right into your Django app. So what are we talking about here? How about we just show you? What you see on your screen right now is a platform that we run, City Cloud Academy. It's a learning management system that's based on OpenEX, which itself is a big set of Django applications that could really be a DjangoCon talk or tutorial all on its own. And in fact, probably the only reason why this is the only OpenEX talk in the conference that we know of is that OpenEX had its own annual conference just last week So we run this learning platform to teach people complex technology, like Ceph, Kubernetes, OpenStack, Terraform, that sort of thing. And we hope you agree with us that most people tend to learn best by doing.

0:56

Speaker 2: So you don't want to just read about those things or watch someone else do them, you of course want to do them yourself. And because all of those technologies are inherently distributed You want to learn them on distributed systems, on real platforms like a lab that your company might otherwise make available in hardware. But of course, a hardware lab is really expensive and it's usually a well it's a finite resource, it's also usually a scarce resource, it's frequently overbooked, and sometimes it's outright inaccessible, such as when everyone is working from home in the middle of a pandemic. So in comes cloud technology. And as it happens, the two of us work for a cloud company, so that comes in handy for us, but that's really of secondary importance to what we're about to show you, as you'll see in a moment

1:41

Speaker 2: So what's happening here is that we open up a page on the learning management system, the LMS. Whenever we talk about an LMS in this talk, it's always a learning management system. And it contains a little magic window, this interactive terminal. And that window is your entry point to your own little lab. So in this case, here what you see is the learner is dropping into a terminal They look around a bit and then ultimately they decide that they're about to develop and compile something on this lab environment, so they start By installing the Build Essential meta package on this Ubuntu box. And without the learner knowing it, when they first hit this page, the LMS made an API call to the cloud platform on their behalf

2:29

Speaker 2: It's spun up in a stack, a lab environment that could be that can be arbitrarily complex. In this case, it's just one Ubuntu machine, but it could be five, it could be ten, it could be three that each run fifty containers, whatever And then it presents you with this terminal right there in your browser. And this terminal is of course fully interactive and you can use it just like your favorite terminal emulator on your laptop or workstation. And as you can see in the next lab that we're progressing to here, that terminal needn't be a boring old text terminal, it can be a full-blown desktop. as well. So in this case what you see is an XFCE4 desktop on Zubuntu. It could be anything, it could be GNOME, it could be KDE, it could be LXDE, whatever. And what we'll do here, just to show you that yes, this is indeed a fully interactive system, is we open LibreOffice Writer

3:21

Speaker 2: and we create some text in it As you can see here in this little screencast. But today we're not going to talk about all of the fun little details of how the interaction with this cloud platform works or how the lap stacks spin up or how they automatically go to sleep when you don't need them and how they magically wake up. When you come back to them because we've already done a bunch of talks on that. They're on the internet. We have YouTube links for them at the end of the talk. And you can try this out yourself on our platform as well. We have links in the chat for that very purpose right now. Today what we're instead going to focus on, what we're zooming in on, is precisely how this entry point works. How exactly you can make a fully interactive Terminal or desktop session pop up in someone's browser

4:08

Speaker 2: using Django of course. Now the technology that this all revolves around is Apache guacamole. And we're going to do a bit of a refresher on guacamole terms and technology here. If you're not familiar with guacamole at all, this will be a nice little introduction to it. If you already know guacamole, like I said, it's a bit of a refresher. But from here on out, we're assuming two things. One, you're a learner on our platform, you've opened a page in a course that contains a lab. And that lab has successfully spun up a random box somewhere in the cloud, like you just saw. So there is something for us to work with. There is an environment that we can work with. And two, we're able to connect to an IP address, IPv4, IPv6, that doesn't matter, that's been exposed on that box.

4:56

Speaker 2: And we can connect to two TCP ports. One for Secure Shell, usually that's port 22, and one for RDP, usually that's port 3389. Now we could also be using VNC, but the same principle would apply. So we'll just stick With SSH and RDP for now to keep things simple and also because RDP is a protocol that works for both Windows and for Linux targets. So one natively on Windows RDP is available natively and on the other on Linux it's available via XRDP or GNOME Remote Desktop Alright now the first thing that we'll look at is the guacamole server or guacti. Now this is a server binary that's written in C, so it's very fast and efficient. connects to upstream SSH or RDP or BNC or whatever services using protocol plugins.

5:45

Speaker 2: Now we should note here that To the services running on your box, the SSH or RDP daemon running on your box, the Gwakdi server acts very much as an SSH or RDP client. We mention that because the terminology easily gets confusing, so please stay with us here. It's going to get a little worse before it gets better. The GuacD server's job is then to take all of these various upstream protocols and translate them into a unified event stream using what's called the Guacamole protocol. And the idea is that whatever comes down the pipe, whether it's SSH or VNC or RDP or whatever, everything is always translated into this one event stream, and that's always the guacamole protocol, or that you always uses the guacamole

6:32

Speaker 2: protocol. But your browser, of course, doesn't speak the guacamole protocol, right? It speaks HTTP, HTTP, WebSockets, and perhaps a few other protocols, but certainly not the guacamole protocol. So we need another translation engine to make this happen to display this stuff in your browser. And here is where unfortunately the naming gets really confusing because in guacamole 's documentation This thing is called the guacamole client, even though it's very much a server to your browser, right? But the naming is correct in so far as it is indeed the client part of the communication between two endpoints that speak the guacamole protocol, the other endpoint being the GuacD server. So it is confusing but arguably it's correct.

7:20

Speaker 2: So the guacamole client, that's the thing that speaks the guacamole protocol on one end to the guacD server and WebSockets on the other to your browser. And then to complete the picture you've got some JavaScript on the browser running in the browser window that's responsible for rendering what it gets from the WebSocket string. So this is the general architecture that we're talking about, random service somewhere in the cloud, guacamole server, guacamole client, and then your Your own web browser with its JavaScript engine that can render the whole thing. So please keep this picture in mind. We'll come back to it a few more times in the talk. Now, the guacamole client, which those of you who already know guacamole will be most familiar with, is a Java servlet application.

8:07

Speaker 2: It's a remote desktop manager and what most of the time what people do is they will deploy Guacdi and they will deploy the guacamole serverlet application usually on the same server. They can do that either natively or via Docker containers And what you get this way is a nice remote desktop manager. And the thing that's running here is an admittedly really dated version of guacamole that's being showcased in this little video that you can find on the guacamole website where you can see how you can connect from that Java Serverlet remote desktop manager application to some Windows hosts and Linux hosts and anything else that speaks one of the protocols that GuaqD can understand that it has protocol plugins for So again, this is sort of the general architecture. You've got the guacamole server, you've got the guacamole client, that's usually this Java servlet

8:54

Speaker 2: application running in Apache Tomcat and then your browser that consumes the whole thing. And if you don't need the whole standard guacamole remote desktop manager and you want to instead incorporate guacamole functionality into your own application, the developers give you a nice how-to for how to build your own. Again, this is assuming that you want to write the whole application in Java as a Java serverlet application that you can then deploy as a war file. But what if you actually don't want to take that one sort of detour through Java? For example, what if you already have Some data in your Django models that you can nicely access via the Django ORM that you somehow want to make accessible to guacamole

9:42

Speaker 2: and then steal the whole guacamole flow from Django. Now, let me give you a simple example. You might be generating one-time SSH keys for connecting your labs. So SSH keys that you create when you spin up a new lab and you delete when you throw the lab away So every key is always for one lab only and you're never reusing your keys. And now you want to store that data in Django somewhere. So say you've got two file fields pointing to the private and public key files. And of course, when you tear the lab down, you're going to throw everything away, but while the lab is alive, you want to be able to grab that data from your database and create a guacamole connection Now what you could do, sticking to the original architecture, the original recommended architecture, is you could do some really bad data mangling, copy all that data from your Django model

10:33

Speaker 2: into a database that the Java application could read from But that gets ugly really quickly, so you don't really want to do that. So instead, what if you wanted to do this and be able to bypass the Java servlet bits altogether? And there can be a number of reasons for this. Maybe you don't want to add a Java runtime environment and serverlet container to your development chain, right? Or maybe you're a pure Python shop and you simply don't have Java development capacity available on your team, or maybe you just really, really like using Django. So what if you could write a full-blown guacamole client in Python using Django that has access to everything that's in your data model? and you can just plug into your Django deployment pipeline. Well it turns out you can do exactly that.

11:19

Speaker 1: So Enter a pure Python Guacamola client, Pi Guacamola. Now what the heck is that? Well As you heard just a moment ago, we need a client that can talk to the Guacamole server, GuacD, on one end, and to the browser on the other end. So PyQuacamola is a Python library that gives us this client for communicating with QuacT. And we'll be looking into how to use it in just a bit. But before we do, what else do we need? We also need the browser to talk to this client. We want to draw a terminal or a desktop window to the browser and we want to be able to interact with it, right? So we need to connect to this client in a way that allows bi-directional communications

12:09

Speaker 1: and for that we'll be using WebSockets Now, as all of you probably know, to handle any other protocols aside from HTTP in a Django project, we'll need to use channels. And Channels is built on ASCII or a synchronous server gateway interface that allows multiple protocols. And the basic unit of Channel's code is a consumer, and that's what we need. So we'll be showing you the consumer of our application. Alright, so let's look at the code Let's start with the view. Our project, the Hastexa XP, is a plugin to Open EdX's edX platform. So the view will be rendered as a part of what we call a unique

12:57

Speaker 1: page. So our view will be this, the student view in hastexo. py. And just to show you really quick, this is where we render the main template and load the necessary JavaScript files. And here you can see the JavaScript file where we initialize the JavaScript Wacomola client. Now, this works exactly as it would with a Java servlet, so we don't need to look into this anymore now You can find the necessary information in Guacamola documentation or you're always most welcome to come see the code in our project, which is open source. Now, let's move on to the most important part, the consumer.

13:44

Speaker 1: py file. Since we are using WebSockets here and this communication runs in an asynchronous manner, we are implementing the async WebSocket Consumer from channels and we are calling it the Guacamole WebSocket Consumer. So two things we need to define here a client and a task. On WebSocket Connect, we are going to initialize the Guacamole client and this is where Py Guacamole comes in. We import the client here And we initialize the client here. For our target stack To what we want to connect

14:29

Speaker 1: to, we get the information from the database. So using database sync to async from channels. b, we can get the stack objects by calling stack objects get. As you can see here in our get stack method. Now back to the Coacamola client We need to provide a hostname and port for Guacti and then we can call handjek. So let's go over the parameters with this. We need to provide a protocol for the connection with the target. In our case this would be either SSH or RDP. We need to pass the hostname, port ,

15:14

Speaker 1: username, password, and private key for the target We can customize the window we draw to the browser bypassing the width and height in here in pixels. We have some additional customization options here like color scheme, font name, font size. There are more options for customization and you can see them in the guacamole documentation. Right, so now that we are connecting to the client, uh we're going to create a task. open the communication and

15:59

Speaker 1: accept the connection. When we open the connection here, we start receiving data from the Guacamola client And if we get something, we send it to the WebSocket. Everything we receive from the WebSocket in here, we send to the Coacamola client For example, what one will type into a terminal window in the browser, we will pass to the CoCommer client here as a key event. We have a use case where we want to display a terminal window in a read-only mode. So this is what you see here. When switched on, we just block or well ignore to be more exact all mouse and key events.

16:46

Speaker 1: And the last thing we do here is cancel the task and close the connection When the WebSocket gets disconnected. And that is all we need for the consumer. Less than a hundred lines of code. What we also need to do is define the application in routing. py and point the WebSocket to our Coacamole WebSocket consumer. In settings tagpy, amongst other things, we need to point our ASCII application to the application we defined in routing. py. Also note that we need to add channels to the list of installed apps. Okay, so now we've seen the code, but how do we run it?

17:35

Speaker 1: Well, there's an official ASCII HTTP WebSocket server called DAVNI, which is maintained by the Chinas project. We really have no reason not to use it and look for other options, which there are. So for us we're using Daphne, but in order to scale the number of processes, we are running it with Supervisor D. There are great examples in the channel's documentation on how to do this, and I'd like to show you that real quick. So this is an example setup on how to run Daphne with Supervisor D. As you can see, here's an example configuration file. This is what we also use for reference And what you need to do here mainly is to define your application. So for us this would be

18:21

Speaker 1: Hastexo Quacomola client routing application. And what follows is an example on how the setup engine nix to point traffic to your Daphne application.

18:34

Speaker 2: Now finally, how does this all work together? You may have noticed that we talked about running one application, OpenEdXS LMS, that's all classic HTT and Django and GUnicorn and WISGI. And we run that together with another, the Guacamole client, which runs with WebSockets, Async Django, channels, Daphne, and ASCII.

18:55

Speaker 1: And what we do here is something that's ubiquitous in OpenEDX all over the place, which is to run everything behind Nginx. The OpenEX has a bunch of different services besides the LMS, such as the OpenEX Studio, which is a course authoring tool, a certificate verification service, and many others And to unify things like the SSL certificate management and even to have one IP address for all services, we just throw everything behind engineers So to sum it all up, let's follow the track of how an RDB or SSH session ends up in an interactive browser window one more time. RDP traffic originates with the upstream

19:42

Speaker 1: server anywhere in the world. QuACD receives that traffic, translates it into a generic event stream, and encodes it in the Guacamola protocol. This happens in a C binary. A Guacamola client running on the same server as GuacD takes that event stream and translates it into a WebSocket stream. This is an async Django app. running in Daphne with ASCII using Py Guacamola. Ancient Nix proxies the WebSocket stream into a URL path hierarchy shared with other Open EdX services themselves synchronous Django apps running in GUINicorn with WSGI. Your browser receives the mixed HTTP WebSocket content from Nginx. One of the things your browser receives is the statically served Guacamole

20:30

Speaker 1: Web Client JavaScript library. Your browser takes that library and uses it to interpret the WebSocket stream and displays it in your browser window. Now you hit a key or click the window in your browser. A JavaScript event listener notices the keystrike or pointer click. It sends WebSocket requests up to Nginx. Nginx proxies that event to the ASCII listener exposed by Daphne. The listener takes the WebSocket event and translates it into a Quacamola protocol event. PiQuamola passes the event on to QuacT. QuagD translates it into an RDP event. Quag D's RTP client library, linked to free RDP tool, sends the RDP event onto the upstream server.

21:19

Speaker 1: The server processes the event sends an update back down the wire. And that's how you put a desktop or a terminal session in any browser with Django.

21:32

Speaker 2: We're finished with some links and references to the building blocks of the architecture that's discussed in this talk. Obviously with huge thanks to all of their developers and contributors. uh pi guacamole is an MIT licensed guacamole client library. We use it heavily in the Hastexo X XBlock, which is a plugin to OpenEX itself, a massively distributed learning platform that anyone can operate. Both the Uh XBlock and OpenEX itself are licensed under the Aferro GPL, and of course there's also Apache Guacamole itself. Which, surprise, surprise is naturally Apache licensed and of that we only use the server component. And finally, you can find this deck on GitHub under a Creative Commons license as well.

22:21

Speaker 1: And that's our talk.

22:22

Speaker 2: Thanks for watching.

22:23

Speaker 1: And now we're here to take any other questions

22:26

Speaker 2: in the chat.

Questions this talk answers

How can I integrate Apache Guacamole into Django without using its Java servlet client?

Use the pure-Python PyGuacamole client instead of the Java servlet application. It can access connection details stored in Django models, such as per-lab SSH keys, and can be deployed with the existing Django application.

Discussed at 11:19

How do I connect a Django Channels WebSocket consumer to Guacamole?

Create an asynchronous Channels WebSocket consumer that initializes a PyGuacamole client on connection, retrieves the target stack from the database, and forwards data in both directions: Guacamole output to the browser and browser key or mouse events back to Guacamole. The consumer then cancels its task and closes the connection when the WebSocket disconnects.

Discussed at 13:43

How do I run a Django Guacamole WebSocket application in production?

Run the ASGI application with Daphne, use Supervisor to manage and scale Daphne processes, and put it behind Nginx. Nginx can proxy the WebSocket paths alongside the normal synchronous Django services running under Gunicorn and WSGI.

Discussed at 17:35

How do I put an interactive terminal or desktop session in a Django app?

Use Apache Guacamole as the protocol bridge: GuacD connects to the remote SSH or RDP service, PyGuacamole translates between Guacamole and Django, and a Django Channels WebSocket sends the session to the browser, where Guacamole’s JavaScript client renders it. The talk’s end-to-end flow places the Django WebSocket app behind Nginx alongside the regular Django application.

Discussed at 19:42

Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.

More videos by Florian Haas and Maari Tamm

More videos from DjangoCon Europe