Securing Django Admin with Port Forwarding

Anna Elde / November 2 2017

Securing Django Admin with Port Forwarding

If you'd like to use Django admin in production, I recommend that you secure it with more than a password.

Restricting access to your server using port forwarding is a good way of securing it, because it puts access to your admin site behind an SSH key. Let's go over the steps to making this happen.

Configuring Nginx

Below is a basic Nginx configuration. The main focus here is the location block, which controls access to your admin URL. You would also need blocks for static files, media files, and a block to pass all other requests to your application server. For brevity, I've only included the configuration for Django admin.

server {
    listen              443 ssl;
    ssl_certificate     certificate_file;
    ssl_certificate_key key_file;

    location ^~ /admin {
        allow       localhost;
        deny        all;
        include     proxy_params;
        proxy_pass  http://unix:/path/my.sock;

In this configuration, you're denying all access to /admin, except for requests coming from the loopback address, i.e., from inside the server itself. Then, you're passing these requests to the application server.

But how do you make a request for /admin come from within the server? That's where port forwarding (more specifically, local forwarding) comes in.

Adding an SSH Host

In your user folder, open up the .ssh folder. There may or may not be a file named config there. Open up the file or create it.

config is used to define hosts with options so you don't have to type out your SSH information every time you want to connect to a server. Using my website as an example, a host in your configuration would look like this:

# configuration
Host portfolio
    User anna
    Port 22
    IdentityFile ~/keys/my_key_file

Let's go through this line-by-line:

  1. Host is a name for the host, which will be used to refer to it on the command line
  2. HostName should be an IP address or domain name
  3. User should be your user on the server
  4. Port should be the port used for SSH, typically 22
  5. IdentityFile is your private SSH key

Using this configuration, when I type ssh portfolio into the command line, I'm connected to my server.

Adding a Local Forward

Adding a local forward to your SSH configuration is simple. Just paste this line into the host you want to do port forwarding for:

LocalForward 10000

The port on your computer can be whatever you like, but the port on the server should be the one that Nginx is listening to (either 80 or 443).

Once you do that, whenever you connect to your server using SSH, the server will send requests made to https://localhost:10000 on your machine to the IP address and port specified. In this case, this is the loopback address using port 443.

Note: If I forwarded my port to port 80, I would use http://localhost:10000 instead of https. If you try accessing the wrong one, it'll seem like the local forward isn't working.

Configuring Django

One last step here. Django will not let you connect from localhost, unless you have added "" to ALLOWED_HOSTS in your settings. As far as I know, that's the only Django-specific configuration you need to make this set-up work.

Accessing Your Admin

So, after configuring Nginx, SSH, and Django, and then connecting to your server, visiting https://localhost:10000/admin will result in your Django admin page showing up.

If you are not connected to the server via SSH, you cannot access the admin page.

Final Thoughts

To me, this seems like a pretty good way of securing Django admin. I can't see any downsides, besides the inconvenience of connecting to the server prior to accessing the admin. Do you agree/disagree? Leave a comment, I would love to hear other opinions on this!


Nginx Django SSH