The Psono usually requires a reverse proxy, to glue the webclient and the server together. This section will explain how to install one of those reverse proxies.

Preamble

This whole guide is based on Ubuntu 18.04 LTS. Ubuntu 12.04+ LTS and Debian based systems should be similar if not even identical.

We assume that you want to use:

  • https://www.example.com to host your webclient
  • https://www.example.com/server will host your server
  • https://www.example.com/portal will host your admin portal
  • you have a valid certificate in /etc/ssl/ with fullchain.pem and privkey.pem
  • An A-Record for example.com exists, pointing to your server’s ip address
  • The psono server runs on port 10100
  • The webclient runs on port 10101 or has been unpacked into /var/www/html
  • The admin webclient runs on port 10102 or has been unpacked into /var/www/html/portal

Reverse Proxy with Nginx

  1. Install Nginx

    sudo apt-get install nginx
    
  2. Create nginx config

    Create example.com.conf in /etc/nginx/sites-available with the following content:

    server {
        listen 80;
        server_name example.com;
        return 301 https://$host$request_uri;
    }
        
    server {
        listen 80;
        server_name www.example.com;
        return 301 https://$host$request_uri;
    }
        
    server {
        listen 443 ssl http2;
        server_name example.com;
        return 301 https://www.$host$request_uri;
        
        ssl_protocols TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;
        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_session_timeout 1d;
        resolver 8.8.8.8 8.8.4.4 valid=300s;
        resolver_timeout 5s;
        ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
        
        add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
        
        add_header Referrer-Policy same-origin;
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        
        # If you have the admin webclient installed too behind this reverse proxy domaain, then you have to change the following from:
        # "connect-src 'self' https://api.pwnedpasswords.com;" to "connect-src 'self' https://example.com https://static.psono.com https://api.pwnedpasswords.com;"
        add_header Content-Security-Policy "default-src 'none'; connect-src 'self' https://api.pwnedpasswords.com; font-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'self'";
        
        ssl_certificate /etc/ssl/fullchain.pem;
        ssl_certificate_key /etc/ssl/privkey.pem;
    }
    server {
        listen 443 ssl http2;
        server_name www.example.com;
        
        ssl_protocols TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;
        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_session_timeout 1d;
        resolver 8.8.8.8 8.8.4.4 valid=300s;
        resolver_timeout 5s;
        ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
            
        # Comment this in if you know what you are doing
        # add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
        
        add_header Referrer-Policy same-origin;
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        
        # If you have the admin webclient installed too behind this reverse proxy domaain, then you have to change the following from:
        # "connect-src 'self' https://api.pwnedpasswords.com;" to "connect-src 'self' https://example.com https://static.psono.com https://api.pwnedpasswords.com;"
        add_header Content-Security-Policy "default-src 'none'; connect-src 'self' https://api.pwnedpasswords.com; font-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'self'";
        
        ssl_certificate /etc/ssl/fullchain.pem;
        ssl_certificate_key /etc/ssl/privkey.pem;
        
        
        gzip on;
        gzip_disable "msie6";
        
        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_buffers 16 8k;
        gzip_http_version 1.1;
        gzip_min_length 256;
        gzip_types text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
        
        root /var/www/html;
        
        location /server {
            rewrite ^/server/(.*) /$1 break;
            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;
    			
            add_header Last-Modified $date_gmt;
            add_header Pragma "no-cache";
            add_header Cache-Control "private, max-age=0, no-cache, no-store";
            if_modified_since off;
            expires off;
            etag off;
    			
            proxy_pass          http://localhost:10100;
        }
            
        location ~* ^/portal.*\.(?:ico|css|js|gif|jpe?g|png)$ {
            expires 30d;
            add_header Pragma public;
            add_header Cache-Control "public";
                
            # Comment in the following lines if you have the admin webclient running in a docker container
            # 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_pass          http://localhost:10102;
            # proxy_redirect      http://localhost:10102 https://example.com;
        }
            
        location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
            expires 30d;
            add_header Pragma public;
            add_header Cache-Control "public";
                
            # Comment in the following lines if you have the webclient running in a docker container
            # 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_pass          http://localhost:10101;
            # proxy_redirect      http://localhost:10101 https://example.com;
        }
        
        # Comment in the following lines if you have the admin webclient running in a docker container
        # location /portal {
        # 	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_read_timeout  90;
        # 	
        # 	proxy_pass          http://localhost:10102;
        # 	proxy_redirect      http://localhost:10102 https://example.com;
        # }
        
        # Comment in the following lines if you have the webclient running in a docker container
        # location / {
        # 	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_pass          http://localhost:10101;
        # 	proxy_read_timeout  90;
        # 	
        # 	proxy_redirect      http://localhost:10101 https://example.com;
        # }
    }
    
  3. Test nginx config

    sudo nginx -t
    
  4. Restart nginx

    sudo service nginx restart
    

    You should now be able to open https://www.example.com in your browser and see the Psono webclient. If you open https://example.com/server in your browser, you should see the following:

    {"detail":"Authentication credentials were not provided."}
    

    If you have installed the admin webclient too, then https://www.example.com/portal/ should show you the admin portal login screen.

Edit me