mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
dev: self hosted settings file (#2202)
* dev: self hosted settings file * dev: add analytics and dockerized variable in settings * dev: update .env.example and docker compose file also * dev: self hosted setup minio
This commit is contained in:
parent
11258686ad
commit
926d2ae0a0
@ -1,6 +1,7 @@
|
|||||||
# Backend
|
# Backend
|
||||||
# Debug value for api server use it as 0 for production use
|
# Debug value for api server use it as 0 for production use
|
||||||
DEBUG=0
|
DEBUG=0
|
||||||
|
DJANGO_SETTINGS_MODULE="plane.settings.selfhosted"
|
||||||
|
|
||||||
# Error logs
|
# Error logs
|
||||||
SENTRY_DSN=""
|
SENTRY_DSN=""
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
"""Production settings and globals."""
|
"""Production settings and globals."""
|
||||||
from urllib.parse import urlparse
|
|
||||||
import ssl
|
import ssl
|
||||||
import certifi
|
import certifi
|
||||||
|
|
||||||
import dj_database_url
|
import dj_database_url
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
from sentry_sdk.integrations.django import DjangoIntegration
|
from sentry_sdk.integrations.django import DjangoIntegration
|
||||||
@ -91,112 +89,89 @@ if bool(os.environ.get("SENTRY_DSN", False)):
|
|||||||
profiles_sample_rate=1.0,
|
profiles_sample_rate=1.0,
|
||||||
)
|
)
|
||||||
|
|
||||||
if DOCKERIZED and USE_MINIO:
|
# The AWS region to connect to.
|
||||||
INSTALLED_APPS += ("storages",)
|
AWS_REGION = os.environ.get("AWS_REGION", "")
|
||||||
STORAGES["default"] = {"BACKEND": "storages.backends.s3boto3.S3Boto3Storage"}
|
|
||||||
# The AWS access key to use.
|
|
||||||
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "access-key")
|
|
||||||
# The AWS secret access key to use.
|
|
||||||
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "secret-key")
|
|
||||||
# The name of the bucket to store files in.
|
|
||||||
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_S3_BUCKET_NAME", "uploads")
|
|
||||||
# The full URL to the S3 endpoint. Leave blank to use the default region URL.
|
|
||||||
AWS_S3_ENDPOINT_URL = os.environ.get(
|
|
||||||
"AWS_S3_ENDPOINT_URL", "http://plane-minio:9000"
|
|
||||||
)
|
|
||||||
# Default permissions
|
|
||||||
AWS_DEFAULT_ACL = "public-read"
|
|
||||||
AWS_QUERYSTRING_AUTH = False
|
|
||||||
AWS_S3_FILE_OVERWRITE = False
|
|
||||||
|
|
||||||
# Custom Domain settings
|
# The AWS access key to use.
|
||||||
parsed_url = urlparse(os.environ.get("WEB_URL", "http://localhost"))
|
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "")
|
||||||
AWS_S3_CUSTOM_DOMAIN = f"{parsed_url.netloc}/{AWS_STORAGE_BUCKET_NAME}"
|
|
||||||
AWS_S3_URL_PROTOCOL = f"{parsed_url.scheme}:"
|
|
||||||
else:
|
|
||||||
# The AWS region to connect to.
|
|
||||||
AWS_REGION = os.environ.get("AWS_REGION", "")
|
|
||||||
|
|
||||||
# The AWS access key to use.
|
# The AWS secret access key to use.
|
||||||
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "")
|
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "")
|
||||||
|
|
||||||
# The AWS secret access key to use.
|
# The optional AWS session token to use.
|
||||||
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "")
|
# AWS_SESSION_TOKEN = ""
|
||||||
|
|
||||||
# The optional AWS session token to use.
|
# The name of the bucket to store files in.
|
||||||
# AWS_SESSION_TOKEN = ""
|
AWS_S3_BUCKET_NAME = os.environ.get("AWS_S3_BUCKET_NAME")
|
||||||
|
|
||||||
# The name of the bucket to store files in.
|
# How to construct S3 URLs ("auto", "path", "virtual").
|
||||||
AWS_S3_BUCKET_NAME = os.environ.get("AWS_S3_BUCKET_NAME")
|
AWS_S3_ADDRESSING_STYLE = "auto"
|
||||||
|
|
||||||
# How to construct S3 URLs ("auto", "path", "virtual").
|
# The full URL to the S3 endpoint. Leave blank to use the default region URL.
|
||||||
AWS_S3_ADDRESSING_STYLE = "auto"
|
AWS_S3_ENDPOINT_URL = os.environ.get("AWS_S3_ENDPOINT_URL", "")
|
||||||
|
|
||||||
# The full URL to the S3 endpoint. Leave blank to use the default region URL.
|
# A prefix to be applied to every stored file. This will be joined to every filename using the "/" separator.
|
||||||
AWS_S3_ENDPOINT_URL = os.environ.get("AWS_S3_ENDPOINT_URL", "")
|
AWS_S3_KEY_PREFIX = ""
|
||||||
|
|
||||||
# A prefix to be applied to every stored file. This will be joined to every filename using the "/" separator.
|
# Whether to enable authentication for stored files. If True, then generated URLs will include an authentication
|
||||||
AWS_S3_KEY_PREFIX = ""
|
# token valid for `AWS_S3_MAX_AGE_SECONDS`. If False, then generated URLs will not include an authentication token,
|
||||||
|
# and their permissions will be set to "public-read".
|
||||||
|
AWS_S3_BUCKET_AUTH = False
|
||||||
|
|
||||||
# Whether to enable authentication for stored files. If True, then generated URLs will include an authentication
|
# How long generated URLs are valid for. This affects the expiry of authentication tokens if `AWS_S3_BUCKET_AUTH`
|
||||||
# token valid for `AWS_S3_MAX_AGE_SECONDS`. If False, then generated URLs will not include an authentication token,
|
# is True. It also affects the "Cache-Control" header of the files.
|
||||||
# and their permissions will be set to "public-read".
|
# Important: Changing this setting will not affect existing files.
|
||||||
AWS_S3_BUCKET_AUTH = False
|
AWS_S3_MAX_AGE_SECONDS = 60 * 60 # 1 hours.
|
||||||
|
|
||||||
# How long generated URLs are valid for. This affects the expiry of authentication tokens if `AWS_S3_BUCKET_AUTH`
|
# A URL prefix to be used for generated URLs. This is useful if your bucket is served through a CDN. This setting
|
||||||
# is True. It also affects the "Cache-Control" header of the files.
|
# cannot be used with `AWS_S3_BUCKET_AUTH`.
|
||||||
# Important: Changing this setting will not affect existing files.
|
AWS_S3_PUBLIC_URL = ""
|
||||||
AWS_S3_MAX_AGE_SECONDS = 60 * 60 # 1 hours.
|
|
||||||
|
|
||||||
# A URL prefix to be used for generated URLs. This is useful if your bucket is served through a CDN. This setting
|
# If True, then files will be stored with reduced redundancy. Check the S3 documentation and make sure you
|
||||||
# cannot be used with `AWS_S3_BUCKET_AUTH`.
|
# understand the consequences before enabling.
|
||||||
AWS_S3_PUBLIC_URL = ""
|
# Important: Changing this setting will not affect existing files.
|
||||||
|
AWS_S3_REDUCED_REDUNDANCY = False
|
||||||
|
|
||||||
# If True, then files will be stored with reduced redundancy. Check the S3 documentation and make sure you
|
# The Content-Disposition header used when the file is downloaded. This can be a string, or a function taking a
|
||||||
# understand the consequences before enabling.
|
# single `name` argument.
|
||||||
# Important: Changing this setting will not affect existing files.
|
# Important: Changing this setting will not affect existing files.
|
||||||
AWS_S3_REDUCED_REDUNDANCY = False
|
AWS_S3_CONTENT_DISPOSITION = ""
|
||||||
|
|
||||||
# The Content-Disposition header used when the file is downloaded. This can be a string, or a function taking a
|
# The Content-Language header used when the file is downloaded. This can be a string, or a function taking a
|
||||||
# single `name` argument.
|
# single `name` argument.
|
||||||
# Important: Changing this setting will not affect existing files.
|
# Important: Changing this setting will not affect existing files.
|
||||||
AWS_S3_CONTENT_DISPOSITION = ""
|
AWS_S3_CONTENT_LANGUAGE = ""
|
||||||
|
|
||||||
# The Content-Language header used when the file is downloaded. This can be a string, or a function taking a
|
# A mapping of custom metadata for each file. Each value can be a string, or a function taking a
|
||||||
# single `name` argument.
|
# single `name` argument.
|
||||||
# Important: Changing this setting will not affect existing files.
|
# Important: Changing this setting will not affect existing files.
|
||||||
AWS_S3_CONTENT_LANGUAGE = ""
|
AWS_S3_METADATA = {}
|
||||||
|
|
||||||
# A mapping of custom metadata for each file. Each value can be a string, or a function taking a
|
# If True, then files will be stored using AES256 server-side encryption.
|
||||||
# single `name` argument.
|
# If this is a string value (e.g., "aws:kms"), that encryption type will be used.
|
||||||
# Important: Changing this setting will not affect existing files.
|
# Otherwise, server-side encryption is not be enabled.
|
||||||
AWS_S3_METADATA = {}
|
# Important: Changing this setting will not affect existing files.
|
||||||
|
AWS_S3_ENCRYPT_KEY = False
|
||||||
|
|
||||||
# If True, then files will be stored using AES256 server-side encryption.
|
# The AWS S3 KMS encryption key ID (the `SSEKMSKeyId` parameter) is set from this string if present.
|
||||||
# If this is a string value (e.g., "aws:kms"), that encryption type will be used.
|
# This is only relevant if AWS S3 KMS server-side encryption is enabled (above).
|
||||||
# Otherwise, server-side encryption is not be enabled.
|
# AWS_S3_KMS_ENCRYPTION_KEY_ID = ""
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_ENCRYPT_KEY = False
|
|
||||||
|
|
||||||
# The AWS S3 KMS encryption key ID (the `SSEKMSKeyId` parameter) is set from this string if present.
|
# If True, then text files will be stored using gzip content encoding. Files will only be gzipped if their
|
||||||
# This is only relevant if AWS S3 KMS server-side encryption is enabled (above).
|
# compressed size is smaller than their uncompressed size.
|
||||||
# AWS_S3_KMS_ENCRYPTION_KEY_ID = ""
|
# Important: Changing this setting will not affect existing files.
|
||||||
|
AWS_S3_GZIP = True
|
||||||
|
|
||||||
# If True, then text files will be stored using gzip content encoding. Files will only be gzipped if their
|
# The signature version to use for S3 requests.
|
||||||
# compressed size is smaller than their uncompressed size.
|
AWS_S3_SIGNATURE_VERSION = None
|
||||||
# Important: Changing this setting will not affect existing files.
|
|
||||||
AWS_S3_GZIP = True
|
|
||||||
|
|
||||||
# The signature version to use for S3 requests.
|
# If True, then files with the same name will overwrite each other. By default it's set to False to have
|
||||||
AWS_S3_SIGNATURE_VERSION = None
|
# extra characters appended.
|
||||||
|
AWS_S3_FILE_OVERWRITE = False
|
||||||
|
|
||||||
# If True, then files with the same name will overwrite each other. By default it's set to False to have
|
STORAGES["default"] = {
|
||||||
# extra characters appended.
|
|
||||||
AWS_S3_FILE_OVERWRITE = False
|
|
||||||
|
|
||||||
STORAGES["default"] = {
|
|
||||||
"BACKEND": "django_s3_storage.storage.S3Storage",
|
"BACKEND": "django_s3_storage.storage.S3Storage",
|
||||||
}
|
}
|
||||||
|
|
||||||
# AWS Settings End
|
# AWS Settings End
|
||||||
|
|
||||||
@ -218,18 +193,7 @@ CSRF_COOKIE_SECURE = True
|
|||||||
|
|
||||||
REDIS_URL = os.environ.get("REDIS_URL")
|
REDIS_URL = os.environ.get("REDIS_URL")
|
||||||
|
|
||||||
if DOCKERIZED:
|
CACHES = {
|
||||||
CACHES = {
|
|
||||||
"default": {
|
|
||||||
"BACKEND": "django_redis.cache.RedisCache",
|
|
||||||
"LOCATION": REDIS_URL,
|
|
||||||
"OPTIONS": {
|
|
||||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
CACHES = {
|
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "django_redis.cache.RedisCache",
|
"BACKEND": "django_redis.cache.RedisCache",
|
||||||
"LOCATION": REDIS_URL,
|
"LOCATION": REDIS_URL,
|
||||||
@ -238,7 +202,7 @@ else:
|
|||||||
"CONNECTION_POOL_KWARGS": {"ssl_cert_reqs": False},
|
"CONNECTION_POOL_KWARGS": {"ssl_cert_reqs": False},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
WEB_URL = os.environ.get("WEB_URL", "https://app.plane.so")
|
WEB_URL = os.environ.get("WEB_URL", "https://app.plane.so")
|
||||||
@ -261,19 +225,16 @@ broker_url = (
|
|||||||
f"{redis_url}?ssl_cert_reqs={ssl.CERT_NONE.name}&ssl_ca_certs={certifi.where()}"
|
f"{redis_url}?ssl_cert_reqs={ssl.CERT_NONE.name}&ssl_ca_certs={certifi.where()}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if DOCKERIZED:
|
CELERY_RESULT_BACKEND = broker_url
|
||||||
CELERY_BROKER_URL = REDIS_URL
|
CELERY_BROKER_URL = broker_url
|
||||||
CELERY_RESULT_BACKEND = REDIS_URL
|
|
||||||
else:
|
|
||||||
CELERY_RESULT_BACKEND = broker_url
|
|
||||||
CELERY_BROKER_URL = broker_url
|
|
||||||
|
|
||||||
GITHUB_ACCESS_TOKEN = os.environ.get("GITHUB_ACCESS_TOKEN", False)
|
GITHUB_ACCESS_TOKEN = os.environ.get("GITHUB_ACCESS_TOKEN", False)
|
||||||
|
|
||||||
|
# Enable or Disable signups
|
||||||
ENABLE_SIGNUP = os.environ.get("ENABLE_SIGNUP", "1") == "1"
|
ENABLE_SIGNUP = os.environ.get("ENABLE_SIGNUP", "1") == "1"
|
||||||
|
|
||||||
# Scout Settings
|
# Scout Settings
|
||||||
SCOUT_MONITOR = os.environ.get("SCOUT_MONITOR", False)
|
SCOUT_MONITOR = os.environ.get("SCOUT_MONITOR", False)
|
||||||
SCOUT_KEY = os.environ.get("SCOUT_KEY", "")
|
SCOUT_KEY = os.environ.get("SCOUT_KEY", "")
|
||||||
SCOUT_NAME = "Plane"
|
SCOUT_NAME = "Plane"
|
||||||
|
|
||||||
|
128
apiserver/plane/settings/selfhosted.py
Normal file
128
apiserver/plane/settings/selfhosted.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
"""Self hosted settings and globals."""
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
import dj_database_url
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
|
||||||
|
from .common import * # noqa
|
||||||
|
|
||||||
|
# Database
|
||||||
|
DEBUG = int(os.environ.get("DEBUG", 0)) == 1
|
||||||
|
|
||||||
|
# Docker configurations
|
||||||
|
DOCKERIZED = 1
|
||||||
|
USE_MINIO = 1
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
"default": {
|
||||||
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
|
"NAME": "plane",
|
||||||
|
"USER": os.environ.get("PGUSER", ""),
|
||||||
|
"PASSWORD": os.environ.get("PGPASSWORD", ""),
|
||||||
|
"HOST": os.environ.get("PGHOST", ""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse database configuration from $DATABASE_URL
|
||||||
|
DATABASES["default"] = dj_database_url.config()
|
||||||
|
SITE_ID = 1
|
||||||
|
|
||||||
|
# File size limit
|
||||||
|
FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880))
|
||||||
|
|
||||||
|
CORS_ALLOW_METHODS = [
|
||||||
|
"DELETE",
|
||||||
|
"GET",
|
||||||
|
"OPTIONS",
|
||||||
|
"PATCH",
|
||||||
|
"POST",
|
||||||
|
"PUT",
|
||||||
|
]
|
||||||
|
|
||||||
|
CORS_ALLOW_HEADERS = [
|
||||||
|
"accept",
|
||||||
|
"accept-encoding",
|
||||||
|
"authorization",
|
||||||
|
"content-type",
|
||||||
|
"dnt",
|
||||||
|
"origin",
|
||||||
|
"user-agent",
|
||||||
|
"x-csrftoken",
|
||||||
|
"x-requested-with",
|
||||||
|
]
|
||||||
|
|
||||||
|
CORS_ALLOW_CREDENTIALS = True
|
||||||
|
CORS_ALLOW_ALL_ORIGINS = True
|
||||||
|
|
||||||
|
STORAGES = {
|
||||||
|
"staticfiles": {
|
||||||
|
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTALLED_APPS += ("storages",)
|
||||||
|
STORAGES["default"] = {"BACKEND": "storages.backends.s3boto3.S3Boto3Storage"}
|
||||||
|
# The AWS access key to use.
|
||||||
|
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "access-key")
|
||||||
|
# The AWS secret access key to use.
|
||||||
|
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "secret-key")
|
||||||
|
# The name of the bucket to store files in.
|
||||||
|
AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_S3_BUCKET_NAME", "uploads")
|
||||||
|
# The full URL to the S3 endpoint. Leave blank to use the default region URL.
|
||||||
|
AWS_S3_ENDPOINT_URL = os.environ.get(
|
||||||
|
"AWS_S3_ENDPOINT_URL", "http://plane-minio:9000"
|
||||||
|
)
|
||||||
|
# Default permissions
|
||||||
|
AWS_DEFAULT_ACL = "public-read"
|
||||||
|
AWS_QUERYSTRING_AUTH = False
|
||||||
|
AWS_S3_FILE_OVERWRITE = False
|
||||||
|
|
||||||
|
# Custom Domain settings
|
||||||
|
parsed_url = urlparse(os.environ.get("WEB_URL", "http://localhost"))
|
||||||
|
AWS_S3_CUSTOM_DOMAIN = f"{parsed_url.netloc}/{AWS_STORAGE_BUCKET_NAME}"
|
||||||
|
AWS_S3_URL_PROTOCOL = f"{parsed_url.scheme}:"
|
||||||
|
|
||||||
|
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
|
||||||
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
|
# Allow all host headers
|
||||||
|
ALLOWED_HOSTS = [
|
||||||
|
"*",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Security settings
|
||||||
|
SESSION_COOKIE_SECURE = True
|
||||||
|
CSRF_COOKIE_SECURE = True
|
||||||
|
|
||||||
|
# Redis URL
|
||||||
|
REDIS_URL = os.environ.get("REDIS_URL")
|
||||||
|
|
||||||
|
# Caches
|
||||||
|
CACHES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "django_redis.cache.RedisCache",
|
||||||
|
"LOCATION": REDIS_URL,
|
||||||
|
"OPTIONS": {
|
||||||
|
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# URL used for email redirects
|
||||||
|
WEB_URL = os.environ.get("WEB_URL", "http://localhost")
|
||||||
|
|
||||||
|
# Celery settings
|
||||||
|
CELERY_BROKER_URL = REDIS_URL
|
||||||
|
CELERY_RESULT_BACKEND = REDIS_URL
|
||||||
|
|
||||||
|
# Enable or Disable signups
|
||||||
|
ENABLE_SIGNUP = os.environ.get("ENABLE_SIGNUP", "1") == "1"
|
||||||
|
|
||||||
|
# Analytics
|
||||||
|
ANALYTICS_BASE_API = False
|
||||||
|
|
||||||
|
# OPEN AI Settings
|
||||||
|
OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1")
|
||||||
|
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", False)
|
||||||
|
GPT_ENGINE = os.environ.get("GPT_ENGINE", "gpt-3.5-turbo")
|
@ -4,7 +4,7 @@ x-api-and-worker-env:
|
|||||||
&api-and-worker-env
|
&api-and-worker-env
|
||||||
DEBUG: ${DEBUG}
|
DEBUG: ${DEBUG}
|
||||||
SENTRY_DSN: ${SENTRY_DSN}
|
SENTRY_DSN: ${SENTRY_DSN}
|
||||||
DJANGO_SETTINGS_MODULE: plane.settings.production
|
DJANGO_SETTINGS_MODULE: plane.settings.selfhosted
|
||||||
DATABASE_URL: postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:5432/${PGDATABASE}
|
DATABASE_URL: postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:5432/${PGDATABASE}
|
||||||
REDIS_URL: redis://plane-redis:6379/
|
REDIS_URL: redis://plane-redis:6379/
|
||||||
EMAIL_HOST: ${EMAIL_HOST}
|
EMAIL_HOST: ${EMAIL_HOST}
|
||||||
|
Loading…
Reference in New Issue
Block a user