diff --git a/penpot.yml b/penpot.yml
new file mode 100644
index 0000000..8983ac5
--- /dev/null
+++ b/penpot.yml
@@ -0,0 +1,27 @@
+---
+
+# Infrastructure
+# Ansible instructions to deploy the infrastructure
+# Copyright (C) 2021 Saibotk
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+- hosts: penpot
+ roles:
+ - docker
+ - docker_compose
+ - docker_cleanup
+ - traefik
+ - penpot
+ environment:
+ PYTHONPATH: /opt/ansible-dependencies/lib/python2.7/site-packages
diff --git a/roles/penpot/README.md b/roles/penpot/README.md
new file mode 100644
index 0000000..733c87c
--- /dev/null
+++ b/roles/penpot/README.md
@@ -0,0 +1,35 @@
+Penpot
+=========
+
+This will set up a [Penpot](https://penpot.app) server using docker and traefik.
+
+Requirements
+------------
+
+You will need to have docker, docker-compose and traefik installed or declared as dependencies with their respective roles.
+
+**This role assumes that you have setup traefik with an endpoint called `websecure`.**
+
+Role Variables
+--------------
+
+**Please look at the [defaults/main.yml](defaults/main.yml) for all available variables and their description.**
+
+**Note: Lines that are commented out via `#` are usually still valid/used variables, but they are not defined by default, so they might enable a feature, when uncommenting/defining them!**
+
+### Global variables, that are used:
+
+- `proxy_network`: Defined by the local traefik installation, this is the shared proxy network used by traefik to reach the containers. (optional)
+- `proxy_hiddenservice`: Defined by the local traefik installation, this is used to generate the alt-svc header for the alternative Tor domain. (optional)
+
+Dependencies
+------------
+
+- Docker
+- Docker-Compose
+- Traefik
+
+License
+-------
+
+GPL-3.0-only
diff --git a/roles/penpot/defaults/main.yml b/roles/penpot/defaults/main.yml
new file mode 100644
index 0000000..a23f989
--- /dev/null
+++ b/roles/penpot/defaults/main.yml
@@ -0,0 +1,67 @@
+---
+# Default variables for the penpot role
+
+# Infrastructure
+# Ansible instructions to deploy the infrastructure
+# Copyright (C) 2021 Saibotk
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# The install locations
+penpot_install_location: /srv/penpot
+penpot_database_location: "{{ penpot_install_location }}/database"
+penpot_redis_location: "{{ penpot_install_location }}/redis"
+penpot_asset_location: "{{ penpot_install_location }}/assets"
+
+# The docker image/version
+# renovate: depName=docker.io/penpottapp/frontend
+penpot_version: "1.2.0-alpha"
+penpot_frontend_image_version: "{{ penpot_version }}"
+penpot_backend_image_version: "{{ penpot_version }}"
+penpot_exporter_image_version: "{{ penpot_version }}"
+
+# The redis/database image versions/tags
+# renovate: depName=docker.io/library/redis
+penpot_redis_image_version: "6"
+# renovate: depName=docker.io/library/postgres
+penpot_database_image_version: "13"
+
+# The domain for traefik to serve this on
+penpot_domain: design.example.com
+
+# The certresolver for traefik to use on this domain
+penpot_traefik_certresolver: letsencrypt_http
+
+# The database credentials
+penpot_database_password: "{{ lookup('passwordstore', penpot_domain + '/db create=true length=42') }}"
+
+# Should the registration be enabled?
+penpot_registration_enabled: false
+
+# Gitlab OAuth settings
+penpot_gitlab:
+ base_uri: "https://gitlab.com"
+ client_id: ""
+ client_secret: ""
+
+# SMTP settings for the application
+penpot_smtp:
+ enabled: false
+ host: ""
+ port: ""
+ username: ""
+ password: ""
+ tls: true
+ ssl: false
+ from: "no-reply@example.com"
+ reply_to: "no-reply@example.com"
diff --git a/roles/penpot/meta/main.yml b/roles/penpot/meta/main.yml
new file mode 100644
index 0000000..4b5e0ed
--- /dev/null
+++ b/roles/penpot/meta/main.yml
@@ -0,0 +1,17 @@
+galaxy_info:
+ author: saibotk
+ description: Setup a penpot docker container with traefik.
+ license: GPL-3.0-only
+ min_ansible_version: 2.9
+
+ platforms:
+ - name: CentOS
+ versions:
+ - 7
+
+ galaxy_tags: []
+
+dependencies:
+ - docker
+ - docker_compose
+ - traefik
diff --git a/roles/penpot/tasks/main.yml b/roles/penpot/tasks/main.yml
new file mode 100644
index 0000000..a192e16
--- /dev/null
+++ b/roles/penpot/tasks/main.yml
@@ -0,0 +1,74 @@
+---
+# Tasks file for the penpot role
+
+# Infrastructure
+# Ansible instructions to deploy the infrastructure
+# Copyright (C) 2021 Saibotk
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+- name: Update default SELinux contexts
+ sefcontext:
+ target: '{{ item }}(/.*)?'
+ setype: "container_file_t"
+ state: present
+ with_items:
+ - "{{ penpot_database_location }}"
+ - "{{ penpot_asset_location }}"
+ - "{{ penpot_redis_location }}"
+ become: true
+
+- name: Create install directory
+ file:
+ path: "{{ item }}"
+ state: directory
+ mode: '0700'
+ owner: 'root'
+ group: 'root'
+ with_items:
+ - "{{ penpot_install_location }}"
+ become: true
+
+- name: Create data directories
+ file: # noqa 208 # Container manages permissions on its own
+ path: "{{ item }}"
+ state: directory
+ setype: "container_file_t"
+ with_items:
+ - "{{ penpot_database_location }}"
+ - "{{ penpot_asset_location }}"
+ - "{{ penpot_redis_location }}"
+ become: true
+
+- name: Deploy docker-compose.yml
+ template:
+ src: "docker-compose.yml"
+ dest: "{{ penpot_install_location }}/docker-compose.yml"
+ mode: '0600'
+ owner: 'root'
+ group: 'root'
+ validate: docker-compose -f %s config -q
+ tags:
+ - penpot
+ become: true
+
+- name: Compose penpot
+ docker_compose:
+ state: present
+ project_src: "{{ penpot_install_location }}"
+ pull: yes
+ remove_orphans: yes
+ tags:
+ - docker
+ - penpot
+ become: true
diff --git a/roles/penpot/templates/docker-compose.yml b/roles/penpot/templates/docker-compose.yml
new file mode 100644
index 0000000..0dd7728
--- /dev/null
+++ b/roles/penpot/templates/docker-compose.yml
@@ -0,0 +1,180 @@
+{{ ansible_managed | comment }}
+
+# Infrastructure
+# Ansible instructions to deploy the infrastructure
+# Copyright (C) 2021 Saibotk
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, version 3 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+version: '2'
+services:
+ penpot-frontend:
+ image: "docker.io/penpotapp/frontend:{{ penpot_frontend_image_version }}"
+ mem_limit: 32mb
+ memswap_limit: 64mb
+ tmpfs:
+ - "/var/cache/nginx:size=10M"
+ - "/run:size=512K"
+ - "/tmp:size=128K"
+ security_opt:
+ - no-new-privileges
+ environment:
+{% if penpot_gitlab is defined %}
+ - PENPOT_GITLAB_CLIENT_ID={{ penpot_gitlab.client_id }}
+{% endif %}
+ - PENPOT_ALLOW_DEMO_USERS=false
+ - PENPOT_DEMO_WARNING=false
+ - PENPOT_LOGIN_WITH_LDAP=false
+ - PENPOT_REGISTRATION_ENABLED={{ penpot_registration_enabled | lower }}
+ labels:
+ - "traefik.enable=true"
+ - "traefik.http.routers.penpot.rule=Host(`{{ penpot_domain }}`) && PathPrefix(`/`)"
+ - "traefik.http.routers.penpot.entrypoints=websecure"
+ - "traefik.http.routers.penpot.tls=true"
+ - "traefik.http.routers.penpot.tls.certresolver={{ penpot_traefik_certresolver }}"
+ - "traefik.http.routers.penpot.middlewares=penpot,compress"
+ - "traefik.http.middlewares.penpot.headers.sslredirect=true"
+ - "traefik.http.middlewares.penpot.headers.stsSeconds=63072000"
+ - "traefik.http.middlewares.penpot.headers.referrerPolicy=no-referrer"
+{% if proxy_network is defined %}
+ - "traefik.docker.network={{ proxy_network }}"
+{% endif %}
+{% if proxy_hiddenservice is defined and proxy_hiddenservice.content is defined %}
+ - "traefik.http.middlewares.penpot.headers.customresponseheaders.alt-svc=h2={{ proxy_hiddenservice['content'] | b64decode | trim }}:443; ma=2592000"
+{% endif %}
+ volumes:
+ - {{ penpot_asset_location }}:/opt/data
+ depends_on:
+ - penpot-backend
+ - penpot-exporter
+ networks:
+ penpot:
+{% if proxy_network is defined %}
+ {{ proxy_network }}:
+{% endif %}
+ restart: always
+
+ penpot-backend:
+ image: "docker.io/penpotapp/backend:{{ penpot_backend_image_version }}"
+ volumes:
+ - {{ penpot_asset_location }}:/opt/data
+ depends_on:
+ - penpot-postgres
+ - penpot-redis
+ environment:
+ # Should be set to the public domain when penpot is going to be
+ # served.
+ - PENPOT_PUBLIC_URI=https://{{ penpot_domain }}
+
+ # User registration
+ - PENPOT_REGISTRATION_ENABLED={{ penpot_registration_enabled | lower }}
+
+ # comma-separated domains, defaults to `""` which means that all domains are allowed)
+ - PENPOT_REGISTRATION_DOMAIN_WHITELIST=""
+
+{% if penpot_gitlab is defined %}
+ # Gitlab OAuth
+ - PENPOT_GITLAB_BASE_URI={{ penpot_gitlab.base_uri }}
+ - PENPOT_GITLAB_CLIENT_ID={{ penpot_gitlab.client_id }}
+ - PENPOT_GITLAB_CLIENT_SECRET={{ penpot_gitlab.client_secret }}
+{% endif %}
+ # Standard database connection parametes (only postgresql is supported):
+ - PENPOT_DATABASE_URI=postgresql://penpot-postgres/penpot
+ - PENPOT_DATABASE_USERNAME=penpot
+ - PENPOT_DATABASE_PASSWORD={{ penpot_database_password }}
+
+ # Redis is used for the websockets notifications.
+ - PENPOT_REDIS_URI=redis://penpot-redis/0
+
+ # By default files upload by user are stored in local
+ # filesystem. But it can be configured to store in AWS S3 or
+ # completelly in de the database. Storing in the database makes
+ # the backups more easy but will make access to media less
+ # performant.
+ - PENPOT_STORAGE_BACKEND=fs
+ - PENPOT_STORAGE_FS_DIRECTORY=/opt/data/assets
+
+ # Telemetry. When enabled, a periodical process will send
+ # annonymous data about this instance. Telemetry data will
+ # enable us to learn on how the application is used based on
+ # real scenarios. If you want to help us, please leave it
+ # enabled. In any case you can see the source code of both
+ # client and server in the penpot repository.
+ - PENPOT_TELEMETRY_ENABLED=false
+
+{% if penpot_smtp is defined %}
+ # Email sending configuration. By default emails are printed in
+ # console, but for production usage is recommeded to setup a
+ # real SMTP provider. Emails are used for confirm user
+ # registration.
+ - PENPOT_SMTP_ENABLED={{ penpot_smtp.enabled | lower }}
+ - PENPOT_SMTP_DEFAULT_FROM={{ penpot_smtp.from }}
+ - PENPOT_SMTP_DEFAULT_REPLY_TO={{ penpot_smtp.reply_to }}
+ - PENPOT_SMTP_HOST={{ penpot_smtp.host }}
+ - PENPOT_SMTP_PORT={{ penpot_smtp.port }}
+ - PENPOT_SMTP_USERNAME={{ penpot_smtp.username }}
+ - PENPOT_SMTP_PASSWORD={{ penpot_smtp.password }}
+ - PENPOT_SMTP_TLS={{ penpot_smtp.tls | lower }}
+ - PENPOT_SMTP_SSL={{ penpot_smtp.ssl | lower }}
+{% endif %}
+ networks:
+ - penpot
+ restart: always
+
+ penpot-exporter:
+ image: "docker.io/penpotapp/exporter:{{ penpot_exporter_image_version }}"
+ environment:
+ # Don't touch it; this uses internal docker network to
+ # communicate with the frontend.
+ - PENPOT_PUBLIC_URI=http://penpot-frontend
+ networks:
+ - penpot
+ restart: always
+
+ penpot-postgres:
+ image: "docker.io/library/postgres:{{ penpot_database_image_version }}"
+ restart: always
+ mem_limit: 512mb
+ memswap_limit: 768mb
+ read_only: true
+ tmpfs:
+ - /run/postgresql:size=512K
+ - /tmp:size=128K
+ stop_grace_period: 2m
+ stop_signal: SIGINT
+ environment:
+ - POSTGRES_INITDB_ARGS=--data-checksums
+ - POSTGRES_DB=penpot
+ - POSTGRES_USER=penpot
+ - POSTGRES_PASSWORD={{ penpot_database_password }}
+ volumes:
+ - {{ penpot_database_location }}:/var/lib/postgresql/data
+ networks:
+ - penpot
+
+ penpot-redis:
+ image: "docker.io/library/redis:{{ penpot_redis_image_version }}"
+ mem_limit: 512mb
+ memswap_limit: 768mb
+ restart: always
+ volumes:
+ - {{ penpot_redis_location }}:/data
+ networks:
+ - penpot
+
+networks:
+ penpot:
+{% if proxy_network is defined %}
+ {{ proxy_network }}:
+ external: true
+{% endif %}