Skip to content

Instantly share code, notes, and snippets.

@gilangvperdana
Last active January 11, 2023 15:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gilangvperdana/81eaaea6b2731c0adbe51ef1dc2bfc46 to your computer and use it in GitHub Desktop.
Save gilangvperdana/81eaaea6b2731c0adbe51ef1dc2bfc46 to your computer and use it in GitHub Desktop.
Psono PW Self Hosted Installation on Ubuntu 20.04 LTS

Goals

Can deploy Psono.pw self hosted on Ubuntu 20.04 LTS Server.

Env

  • Ubuntu 20.04 LTS
  • Docker
  • Nginx Systemd

docker-compose.yml

version: '3'
services:
  psono_db:
    image: postgres:10.4
    container_name: psono_db
    environment:
      - POSTGRES_USER=psono
      - POSTGRES_PASSWORD=psono
      - POSTGRES_DB=psono
      - DB_EXTENSION=pgcrypto
      - DB_EXTENSION=ltree
    volumes:
      - "psonodb:/var/lib/postgresql/data"
    networks:
      - backend
    ports:
      - "5432:5432"
    restart: always

  psono_backend:
    image: psono/psono-server:latest
    container_name: psono_backend
    volumes:
      - "${PWD}/settings.yaml:/root/.psono_server/settings.yaml"
    links:
      - psono_db
    networks:
      - backend
    ports:
      - "10100:80"
    restart: always
    depends_on:
      - psono_db

#    psono_reverse:
#      image: nginx:latest
#      container_name: psono_reverse
#      volumes:
#        - "${PWD}/vhost.conf:/etc/nginx/conf.d/vhost.conf"
#        - "${PWD}/ssl:/etc/ssl"
#      networks:
#        - backend
#        - outside
#      ports:
#        - "443:443"
#      restart: always
#      depends_on:
#        - psono_db
#        - psono_backend

  psono_client:
    image: psono/psono-client:latest
    container_name: psono_client
    networks:
      - backend
    ports:
      - "10101:80"
    restart: always
    depends_on:
      - psono_db
      - psono_backend

  psono_admin:
    image: psono/psono-admin-client:latest
    container_name: psono_admin
    networks:
      - backend
    ports:
      - "10102:80"
    restart: always
    depends_on:
      - psono_db
      - psono_backend
volumes:
  psonodb:
  #  external: true

networks:
  outside:
    external: true
  backend:

settings.yaml

# generate the following six parameters with the following command
# python3 ~/psono-server/psono/manage.py generateserverkeys
SECRET_KEY: '+?`\\x&.rFq4sd~R,ZB/vPN~jn~19hif?~L#TuRgMg.L=(wSmtq'
ACTIVATION_LINK_SECRET: '6`MmEO=QG,qBZ;,(i\\_b*L"U[EXUWoFEZGUW&={bYM6.rJeaSZ'
DB_SECRET: '\\"z.%%WkV5DQF`j~xvYfVM7M;?{lV_SzD=iURd{C?yL4N_Zolk'
EMAIL_SECRET_SALT: '$2b$12$JwSQyeRva7lf0lg6PYBeaO'
PRIVATE_KEY: '40661064be34a7926ba098950d3c5a98bd1e6613d907a1cd6d6b6235ef472089'
PUBLIC_KEY: 'f56a7369392a12fd88eef4387b81857a3680af3bc11488b5e17ac30b50664014'
# The URL of the web client (path to e.g activate.html without the trailing slash)
# WEB_CLIENT_URL: 'https://www.psono.pw'

# Switch DEBUG to false if you go into production
DEBUG: False

# Adjust this according to Django Documentation https://docs.djangoproject.com/en/1.10/ref/settings/
ALLOWED_HOSTS: ['*']

# Should be your domain without "www.". Will be the last part of the username
ALLOWED_DOMAINS: ['dev-psono.com']

# If you want to disable registration, you can comment in the following line
# ALLOW_REGISTRATION: False

# If you want to restrict registration to some email addresses you can specify here a list of domains to filter
# REGISTRATION_EMAIL_FILTER: ['company1.com', 'company2.com']

# Should be the URL of the host under which the host is reachable
# If you open the url you should have a text similar to {"detail":"Authentication credentials were not provided."}
HOST_URL: 'https://dev-psono.com/server'

# The email used to send emails, e.g. for activation
EMAIL_FROM: 'REDACTED'
EMAIL_HOST: 'REDACTED'
EMAIL_HOST_USER: 'REDACTED'
EMAIL_HOST_PASSWORD : 'REDACTED'
EMAIL_PORT: 587
EMAIL_SUBJECT_PREFIX: 'Psono'
EMAIL_USE_TLS: False
EMAIL_USE_SSL: False
EMAIL_SSL_CERTFILE:
EMAIL_SSL_KEYFILE:
EMAIL_TIMEOUT:

# In case one wants to use mailgun, comment in below lines and provide the mailgun access key and server name
# EMAIL_BACKEND: 'django_mailgun.MailgunBackend'
# MAILGUN_ACCESS_KEY: ''
# MAILGUN_SERVER_NAME: ''

# In case you want to offer Yubikey support, create a pair of credentials here https://upgrade.yubico.com/getapikey/
# and update the following two lines before commenting them in
# YUBIKEY_CLIENT_ID: '123456'
# YUBIKEY_SECRET_KEY: '8I65IA6ASDFIUHGIH5021FKJA='

# If you have own Yubico servers, you can specify here the urls as a list
# YUBICO_API_URLS: ['https://api.yubico.com/wsapi/2.0/verify']

# Cache enabled without belows Redis may lead to unexpected behaviour

# Cache with Redis
# By default you should use something different than database 0 or 1, e.g. 13 (default max is 16, can be configured in
# redis.conf) possible URLS are:
#    redis://[:password]@localhost:6379/0
#    rediss://[:password]@localhost:6379/0
#    unix://[:password]@/path/to/socket.sock?db=0
# CACHE_ENABLE: False
# CACHE_REDIS: False
# CACHE_REDIS_LOCATION: 'redis://127.0.0.1:6379/13'

# Disables Throttling (necessary for unittests to pass) by overriding the cache with a dummy cache
# https://docs.djangoproject.com/en/1.11/topics/cache/#dummy-caching-for-development
# THROTTLING: False

# Enables the management API, required for the psono-admin-client / admin portal
MANAGEMENT_ENABLED: True

# Allows that users can search for partial usernames
# ALLOW_USER_SEARCH_BY_USERNAME_PARTIAL: True

# Allows that users can search for email addresses too
# ALLOW_USER_SEARCH_BY_EMAIL: True

# Only necessary if the psono-client runs on a sub path (no trailing slash) e.g. "https://wwww.psono.pw"
# WEB_CLIENT_URL: ''

# Prevents the use of the last X passwords. 0 disables it.
# DISABLE_LAST_PASSWORDS: 0

# Your Postgres Database credentials
DATABASES:
    default:
        'ENGINE': 'django.db.backends.postgresql_psycopg2'
        'NAME': 'psono'
        'USER': 'psono'
        'PASSWORD': 'psono'
        'HOST': 'psono_db'
        'PORT': '5432'
# for master / slave replication setup comment in the following (all reads will be redirected to the slave
#    slave:
#        'ENGINE': 'django.db.backends.postgresql_psycopg2'
#        'NAME': 'YourPostgresDatabase'
#        'USER': 'YourPostgresUser'
#        'PASSWORD': 'YourPostgresPassword'
#        'HOST': 'YourPostgresHost'
#        'PORT': 'YourPostgresPort'

# Update the path to your templates folder
# If you do not want to change it (yet) you can leave it like it is.
TEMPLATES: [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['/root/psono/templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

psono-server.ini

[program:psono-server]
command = /usr/bin/gunicorn --bind 127.0.0.1:10100 psono.wsgi
directory=/home/psono/psono-server/psono
user = psono
autostart=true
autorestart=true
redirect_stderr=true

vhost.conf

  • change 10.0.2.115:10101 to your IP Address
server {
    listen 80;
    server_name dev-psono.com;
    return 301 https://$host$request_uri;
}
    
server {
    listen 80;
    server_name www.dev-psono.com;
    return 301 https://$host$request_uri;
}
    
#server {
#    listen 443 ssl http2;
#    server_name dev-psono.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://dev-psono.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/letsencrypt/live/psono/server.crt;
#    ssl_certificate_key /etc/letsencrypt/live/psono/server.key;
#}
server {
    listen 443 ssl http2;
    server_name www.dev-psono.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://dev-psono.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/letsencrypt/live/psono/server.crt;
    ssl_certificate_key /etc/letsencrypt/live/psono/server.key;
    
    
    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://10.0.2.115: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://10.0.2.115:10102;
         proxy_redirect      http://10.0.2.115:10102 https://dev-psono.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://10.0.2.115:10101;
         proxy_redirect      http://10.0.2.115:10101 https://dev-psono.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://10.0.2.115:10102;
     	proxy_redirect      http://10.0.2.115:10102 https://dev-psono.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://10.0.2.115:10101;
     	proxy_read_timeout  90;
     	
     	proxy_redirect      http://10.0.2.115:10101 https://dev-psono.com;
     }
}

Create Super Admin

docker exec -it psono_backend ash
python3  ~/psono/manage.py createuser admin@dev-psono.com PASSWORD admin@dev-psono.com
python3 ~/psono/manage.py promoteuser admin@dev-psono.com superuser

Reference

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment