diff --git a/roles/pixelfed/defaults/main.yml b/roles/pixelfed/defaults/main.yml new file mode 100644 index 0000000..b4732b4 --- /dev/null +++ b/roles/pixelfed/defaults/main.yml @@ -0,0 +1,143 @@ +--- + +pixelfed_user: pixelfed +pixelfed_version: 0.11.2 +pixelfed_base_path: /opt/pixelfed + +pixelfed_deployment_method: docker_selfbuilt + +# user to run pixelfed as +pixelfed_run_user: "{{ pixelfed_user_stat.uid | default(pixelfed_user) }}" +pixelfed_run_group: "{{ pixelfed_user_stat.group | default(pixelfed_user) }}" + +# container settings +pixelfed_container_name: pixelfed +pixelfed_container_image_name: pixelfed +pixelfed_container_image_tag: ~ +pixelfed_container_image: "{{ pixelfed_container_image_name }}:{{ pixelfed_container_image_tag | default('v' + pixelfed_version, True) }}" +pixelfed_container_image_local_build: true +pixelfed_container_ports: [] +pixelfed_container_networks: [] +pixelfed_container_extra_volumes: [] +pixelfed_container_extra_labels: {} +pixelfed_container_extra_env: {} +pixelfed_container_restart_policy: unless-stopped +pixelfed_worker_container_name: "{{ pixelfed_container_name }}-worker" + +# host filesystem paths +pixelfed_config_path: "{{ pixelfed_base_path }}/config" +pixelfed_storage_path: "{{ pixelfed_base_path }}/storage" +pixelfed_source_path: "{{ pixelfed_base_path }}/source" + +pixelfed_app_paths: + - path: "{{ pixelfed_base_path }}" + mode: "0750" + - path: "{{ pixelfed_config_path }}" + mode: "0750" + - path: "{{ pixelfed_storage_path }}" + mode: "0750" + - path: "{{ pixelfed_source_path }}" + mode: "0750" + +pixelfed_config_app_key: ~ +pixelfed_config_app_name: "Pixelfed" +pixelfed_config_app_env: production +pixelfed_config_app_debug: false +pixelfed_config_app_url: "https://{{ pixelfed_config_app_url }}" +pixelfed_config_app_domain: ~ # my.pixelfed.domain +pixelfed_config_admin_domain: "{{ pixelfed_config_app_domain }}" +pixelfed_config_session_domain: "{{ pixelfed_config_app_domain }}" + +pixelfed_config_open_registration: true +pixelfed_config_enforce_email_verification: false +pixelfed_config_pf_max_users: 1000 +pixelfed_config_oauth_enabled: true + +pixelfed_config_app_timezone: UTC +pixelfed_config_app_locale: en + +pixelfed_config_limit_account_size: true +pixelfed_config_max_account_size: 1000000 +pixelfed_config_max_photo_size: 15000 +pixelfed_config_max_avatar_size: 2000 +pixelfed_config_max_caption_length: 500 +pixelfed_config_max_bio_length: 125 +pixelfed_config_max_name_length: 30 +pixelfed_config_max_album_length: 4 +pixelfed_config_image_quality: 80 +pixelfed_config_pf_optimize_images: true +pixelfed_config_pf_optimize_videos: true +pixelfed_config_admin_env_editor: false +pixelfed_config_account_deletion: true +pixelfed_config_account_delete_after: false +pixelfed_config_max_links_per_post: 0 + +pixelfed_config_instance_description: ~ +pixelfed_config_instance_public_hashtags: false +pixelfed_config_instance_contact_email: ~ +pixelfed_config_instance_public_local_timetime: false +pixelfed_config_banned_usernames: ~ +pixelfed_config_stories_enabled: false +pixelfed_config_restricted_instance: false + +pixelfed_config_mail_driver: log +pixelfed_config_mail_host: ~ +pixelfed_config_mail_port: 25 +pixelfed_config_mail_from_address: "pixelfed@{{ pixelfed_config_app_domain }}" +pixelfed_config_mail_from_name: "{{ pixelfed_config_app_name }}" +pixelfed_config_mail_username: null +pixelfed_config_mail_password: null +pixelfed_config_mail_encryption: null + +pixelfed_config_db_connection: pgsql +pixelfed_config_db_host: postgres +pixelfed_config_db_port: 5432 +pixelfed_config_db_username: pixelfed +pixelfed_config_db_password: ~ +pixelfed_config_db_database: pixelfed + +pixelfed_config_redis_client: phpredis +pixelfed_config_redis_scheme: tcp +pixelfed_config_redis_host: redis +pixelfed_config_redis_password: ~ +pixelfed_config_redis_port: 6379 +pixelfed_config_redis_database: 0 + +pixelfed_config_exp_lc: false +pixelfed_config_exp_rec: false +pixelfed_config_exp_loops: false + +pixelfed_config_activity_pub: false +pixelfed_config_ap_remote_follow: false +pixelfed_config_ap_shared_inbox: false +pixelfed_config_ap_inbox: false +pixelfed_config_ap_outbox: false +pixelfed_config_atom_feeds: true +pixelfed_config_nodeinfo: true +pixelfed_config_webfinger: true + +pixelfed_config_filesystem_driver: local +pixelfed_config_filesystem_cloud: s3 +pixelfed_config_pf_enable_cloud: false +pixelfed_config_aws_access_key_id: ~ +pixelfed_config_aws_secret_access_key: ~ +pixelfed_config_aws_default_region: ~ +pixelfed_config_aws_bucket: ~ +pixelfed_config_aws_url: ~ +pixelfed_config_aws_endpont: ~ +pixelfed_config_aws_use_path_style_endpoint: false + +pixelfed_config_horizon_darkmode: false +pixelfed_config_pf_costar_enabled: false +pixelfed_config_media_exif_database: false +pixelfed_config_log_channel: stderr +pixelfed_config_image_driver: imagick + +pixelfed_config_broadcast_driver: log +pixelfed_config_cache_driver: redis +pixelfed_config_restrict_html_types: true +pixelfed_config_queue_driver: redis +pixelfed_config_session_driver: redis +pixelfed_config_trust_proxies: "*" +pixelfed_config_passport_private_key: ~ +pixelfed_config_passport_public_key: ~ diff --git a/roles/pixelfed/handlers/main.yml b/roles/pixelfed/handlers/main.yml new file mode 100644 index 0000000..9ede86a --- /dev/null +++ b/roles/pixelfed/handlers/main.yml @@ -0,0 +1,17 @@ +--- + +- name: Restart pixelfed (docker) + docker_container: + name: "{{ pixelfed_container_name }}" + state: started + restart: yes + when: 'docker' in pixelfed_deployment_method + listen: restart-pixelfed + +- name: Restart pixelfed worker (docker) + docker_container: + name: "{{ pixelfed_worker_container_name }}" + state: started + restart: yes + when: 'docker' in pixelfed_deployment_method + listen: restart-pixelfed diff --git a/roles/pixelfed/tasks/docker-deploy.yml b/roles/pixelfed/tasks/docker-deploy.yml new file mode 100644 index 0000000..5325a42 --- /dev/null +++ b/roles/pixelfed/tasks/docker-deploy.yml @@ -0,0 +1,28 @@ +--- + +- name: Ensure docker container '{{ pixelfed_container_name }}' is running + docker_container: + name: "{{ pixelfed_container_name }}" + image: "{{ pixelfed_container_image }}" + env: "{{ pixelfed_container_env }}" + env_file: "{{ pixelfed_config_path }}/env" + labels: "{{ pixelfed_container_labels }}" + volumes: "{{ pixelfed_container_volumes }}" + ports: "{{ pixelfed_container_ports | default(omit, True) }}" + networks: "{{ pixelfed_container_networks | default(omit, True) }}" + purge_networks: "{{ pixelfed_container_purge_networks|default(False) }}" + restart_policy: "{{ pixelfed_container_restart_policy }}" + state: started + +- name: Ensure docker container '{{ pixelfed_worker_container_name }}' is running + docker_container: + name: "{{ pixelfed_worker_container_name }}" + image: "{{ pixelfed_container_image }}" + env: "{{ pixelfed_container_env }}" + env_file: "{{ pixelfed_config_path }}/env" + volumes: "{{ pixelfed_container_volumes }}" + networks: "{{ pixelfed_container_networks | default(omit, True) }}" + purge_networks: "{{ pixelfed_container_purge_networks|default(False) }}" + restart_policy: "{{ pixelfed_container_restart_policy }}" + command: "gosu www-data php artisan horizon" + state: started diff --git a/roles/pixelfed/tasks/docker-image.yml b/roles/pixelfed/tasks/docker-image.yml new file mode 100644 index 0000000..c34dec5 --- /dev/null +++ b/roles/pixelfed/tasks/docker-image.yml @@ -0,0 +1,28 @@ +--- + +- name: Ensure docker container image is pulled + docker_image: + name: "{{ pixelfed_container_image }}" + state: present + source: pull + force_source: "{{ true if docker_container_image_tag else false }}" + when: not pixelfed_container_image_local_build + +- name: Ensure upstream git repository is cloned to source folder + git: + repo: "{{ pixelfed_source_upstream_git_repo }}" + dest: "{{ pixelfed_source_path }}" + update: yes + clone: yes + when: pixelfed_container_image_local_build + +- name: Build docker container image '{{ pixelfed_container_image }}' locally + docker_image: + name: "{{ pixelfed_container_image_name }}" + tag: "{{ pixelfed_container_image_tag | default('v' + pixelfed_version) }}" + state: present + source: build + build: + dockerfile: "contrib/docker/Dockerfile.apache" + path: "{{ pixelfed_source_path }}" + when: pixelfed_container_image_local_build diff --git a/roles/pixelfed/tasks/main.yml b/roles/pixelfed/tasks/main.yml new file mode 100644 index 0000000..6251b5f --- /dev/null +++ b/roles/pixelfed/tasks/main.yml @@ -0,0 +1,48 @@ +--- + +- name: Ensure user '{{ pixelfed_user }}' for pixelfed is created + user: + name: "{{ pixelfed_user }}" + state: present + system: true + register: pixelfed_user_stat + +- name: Ensure file system paths exist for persisting data + file: + path: "{{ dir.path }}" + state: directory + owner: "{{ dir.user | default(pixelfed_run_user) }}" + group: "{{ dir.group | default(pixelfed_run_group) }}" + mode: "{{ dir.mode }}" + loop: "{{ pixelfed_app_paths }}" + loop_control: + loop_var: dir + label: "{{ dir.path }}" + +- name: Ensure pixelfed configuration is templated + copy: + content: |+ + {% for key in pixelfed_config | dict2items %} + {% if pixelfed_config[key] %} + {{ key }}={{ pixelfed_config[key] }} + {% endif %} + {% endfor %} + dest: "{{ pixelfed_config_path }}/env" + owner: "{{ pixelfed_run_user }}" + group: "{{ pixelfed_run_group }}" + mode: "0640" + notify: restart-pixelfed + +- name: Ensure docker container image is available + include_tasks: + file: docker-image.yml + when: 'docker' in pixelfed_deployment_method + +- name: Ensure pixelfed instance is started + block: + - name: Ensure pixelfed instance is started (docker) + include_tasks: + file: docker-deploy.yml + when: 'docker' in pixelfed_deployment_method + + diff --git a/roles/pixelfed/templates/env.docker.j2 b/roles/pixelfed/templates/env.docker.j2 new file mode 100644 index 0000000..6df70f2 --- /dev/null +++ b/roles/pixelfed/templates/env.docker.j2 @@ -0,0 +1,148 @@ +## Crypto +APP_KEY= + +## General Settings +APP_NAME="Pixelfed Prod" +APP_ENV=production +APP_DEBUG=false +APP_URL=https://real.domain +APP_DOMAIN="real.domain" +ADMIN_DOMAIN="real.domain" +SESSION_DOMAIN="real.domain" + +OPEN_REGISTRATION=true +ENFORCE_EMAIL_VERIFICATION=false +PF_MAX_USERS=1000 +OAUTH_ENABLED=true + +APP_TIMEZONE=UTC +APP_LOCALE=en + +## Pixelfed Tweaks +LIMIT_ACCOUNT_SIZE=true +MAX_ACCOUNT_SIZE=1000000 +MAX_PHOTO_SIZE=15000 +MAX_AVATAR_SIZE=2000 +MAX_CAPTION_LENGTH=500 +MAX_BIO_LENGTH=125 +MAX_NAME_LENGTH=30 +MAX_ALBUM_LENGTH=4 +IMAGE_QUALITY=80 +PF_OPTIMIZE_IMAGES=true +PF_OPTIMIZE_VIDEOS=true +ADMIN_ENV_EDITOR=false +ACCOUNT_DELETION=true +ACCOUNT_DELETE_AFTER=false +MAX_LINKS_PER_POST=0 + +## Instance +#INSTANCE_DESCRIPTION= +INSTANCE_PUBLIC_HASHTAGS=false +#INSTANCE_CONTACT_EMAIL= +INSTANCE_PUBLIC_LOCAL_TIMELINE=false +#BANNED_USERNAMES= +STORIES_ENABLED=false +RESTRICTED_INSTANCE=false + +## Mail +MAIL_DRIVER=log +MAIL_HOST=smtp.mailtrap.io +MAIL_PORT=2525 +MAIL_FROM_ADDRESS="pixelfed@example.com" +MAIL_FROM_NAME="Pixelfed" +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null + +## Databases (MySQL) +DB_CONNECTION=mysql +DB_DATABASE=pixelfed_prod +DB_HOST=db +DB_PASSWORD=pixelfed_db_pass +DB_PORT=3306 +DB_USERNAME=pixelfed +# pass the same values to the db itself +MYSQL_DATABASE=pixelfed_prod +MYSQL_PASSWORD=pixelfed_db_pass +MYSQL_RANDOM_ROOT_PASSWORD=true +MYSQL_USER=pixelfed + +## Databases (Postgres) +#DB_CONNECTION=pgsql +#DB_HOST=postgres +#DB_PORT=5432 +#DB_DATABASE=pixelfed +#DB_USERNAME=postgres +#DB_PASSWORD=postgres + +## Cache (Redis) +REDIS_CLIENT=phpredis +REDIS_SCHEME=tcp +REDIS_HOST=redis +REDIS_PASSWORD=redis_password +REDIS_PORT=6379 +REDIS_DATABASE=0 + +## EXPERIMENTS +EXP_LC=false +EXP_REC=false +EXP_LOOPS=false + +## ActivityPub Federation +ACTIVITY_PUB=false +AP_REMOTE_FOLLOW=false +AP_SHAREDINBOX=false +AP_INBOX=false +AP_OUTBOX=false +ATOM_FEEDS=true +NODEINFO=true +WEBFINGER=true + +## S3 +FILESYSTEM_DRIVER=local +FILESYSTEM_CLOUD=s3 +PF_ENABLE_CLOUD=false +#AWS_ACCESS_KEY_ID= +#AWS_SECRET_ACCESS_KEY= +#AWS_DEFAULT_REGION= +#AWS_BUCKET= +#AWS_URL= +#AWS_ENDPOINT= +#AWS_USE_PATH_STYLE_ENDPOINT=false + +## Horizon +HORIZON_DARKMODE=false + +## COSTAR - Confirm Object Sentiment Transform and Reduce +PF_COSTAR_ENABLED=false + +# Media +MEDIA_EXIF_DATABASE=false + +## Logging +LOG_CHANNEL=stderr + +## Image +IMAGE_DRIVER=imagick + +## Broadcasting +BROADCAST_DRIVER=log # log driver for local development + +## Cache +CACHE_DRIVER=redis + +## Purify +RESTRICT_HTML_TYPES=true + +## Queue +QUEUE_DRIVER=redis + +## Session +SESSION_DRIVER=redis + +## Trusted Proxy +TRUST_PROXIES="*" + +## Passport +#PASSPORT_PRIVATE_KEY= +#PASSPORT_PUBLIC_KEY= diff --git a/roles/pixelfed/templates/main.yml b/roles/pixelfed/templates/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/pixelfed/vars/main.yml b/roles/pixelfed/vars/main.yml new file mode 100644 index 0000000..a545e9d --- /dev/null +++ b/roles/pixelfed/vars/main.yml @@ -0,0 +1,133 @@ +--- + +pixelfed_container_base_volumes: + - "{{ pixelfed_storage_path }}:/var/www/storage:z" + - "{{ pixelfed_config_path/env:/var/www/.env:ro" + +pixelfed_container_base_env: {} + +pixelfed_container_base_labels: + VERSION: "{{ pixelfed_version }}" + +pixelfed_container_volumes: "{{ pixelfed_container_base_volumes + pixelfed_container_extra_volumes }}" +pixelfed_container_labels: "{{ pixelfed_container_base_labels + pixelfed_container_extra_labels }}" +pixelfed_container_env: "{{ pixelfed_container_base_env + pixelfed_container_extra_env }}" + +pixelfed_source_upstream_git_repo: "https://github.com/pixelfed/pixelfed.git" + +pixelfed_supported_deployment_methods: + - docker_selfbuilt + - docker_pulled + + +# pixelfed app config +pixelfed_config: + APP_KEY: "{{ pixelfed_config_app_key }}" + APP_NAME: "{{ pixelfed_config_app_name }}" + APP_ENV: "{{ pixelfed_config_app_env }}" + APP_DEBUG: "{{ pixelfed_config_app_debug }}" + APP_URL: "{{ pixelfed_config_app_url }}" + APP_DOMAIN: "{{ pixelfed_config_app_domain }}" + ADMIN_DOMAIN: "{{ pixelfed_config_app_admin_domain }}" + SESSION_DOMAIN: "{{ pixelfed_config_session_domain }}" + + OPEN_REGISTRATION: "{{ pixelfed_config_open_registration }}" + ENFORCE_EMAIL_VERIFICATION: "{{ pixelfed_config_enforce_email_verification }}" + PF_MAX_USERS: "{{ pixelfed_config_pf_max_users }}" + OAUTH_ENABLED: "{{ pixelfed_config_oauth_enabled }}" + + APP_TIMEZONE: "{{ pixelfed_config_app_timezone }}" + APP_LOCALE: "{{ pixelfed_config_all_locale }}" + + LIMIT_ACCOUNT_SIZE: "{{ pixelfed_config_limit_account_size }}" + MAX_ACCOUNT_SIZE: "{{ pixelfed_config_max_account_size }}" + MAX_PHOTO_SIZE: "{{ pixelfed_config_ }}" + MAX_AVATAR_SIZE: "{{ pixelfed_config_ }}" + MAX_CAPTION_LENGTH: "{{ pixelfed_config_ }}" + MAX_BIO_LENGTH: "{{ pixelfed_config_ }}" + MAX_NAME_LENGTH: "{{ pixelfed_config_ }}" + MAX_ALBUM_LENGTH: "{{ pixelfed_config_ }}" + IMAGE_QUALITY: "{{ pixelfed_config_ }}" + PF_OPTIMIZE_IMAGES: "{{ pixelfed_config_ }}" + PF_OPTIMIZE_VIDEOS: "{{ pixelfed_config_ }}" + ADMIN_ENV_EDITOR: "{{ pixelfed_config_ }}" + ACCOUNT_DELETION: "{{ pixelfed_config_ }}" + ACCOUNT_DELETE_AFTER: "{{ pixelfed_config_ }}" + MAX_LINKS_PER_POST: "{{ pixelfed_config_ }}" + + INSTANCE_DESCRIPTION: "{{ pixelfed_config_instance_description }}" + INSTANCE_PUBLIC_HASHTAGS: "{{ pixelfed_config_instance_public_hashtags }}" + INSTANCE_CONTACT_EMAIL: "{{ pixelfed_config_instance_contact_email }}" + INSTANCE_PUBLIC_LOCAL_TIMELINE: "{{ pixelfed_config_instance_public_local_timeline }}" + BANNED_USERNAMES: "{{ pixelfed_config_banned_usernames }}" + STORIES_ENABLED: "{{ pixelfed_config_stories_enabled }}" + RESTRICTED_INSTANCE: "{{ pixelfed_config_restricted_instance }}" + + ## Mail + MAIL_DRIVER: "{{ pixelfed_config_mail_driver }}" + MAIL_HOST: "{{ pixelfed_config_mail_host }}" + MAIL_PORT: "{{ pixelfed_config_mail_port }}" + MAIL_FROM_ADDRESS: "{{ pixelfed_config_mail_from_address }}" + MAIL_FROM_NAME: "{{ pixelfed_config_mail_from_name }}" + MAIL_USERNAME: "{{ pixelfed_config_mail_username }}" + MAIL_PASSWORD: "{{ pixelfed_config_mail_password }}" + MAIL_ENCRYPTION: "{{ pixelfed_config_mail_encryption }}" + + ## Databases (MySQL) + DB_CONNECTION: "{{ pixelfed_config_db_connection }}" + DB_DATABASE: "{{ pixelfed_config_db_database }}" + DB_HOST: "{{ pixelfed_config_db_host }}" + DB_PASSWORD: "{{ pixelfed_config_db_password }}" + DB_PORT: "{{ pixelfed_config_db_port }}" + DB_USERNAME: "{{ pixelfed_config_db_username }}" + + ## Cache (Redis) + REDIS_CLIENT: "{{ pixelfed_config_redis_client }}" + REDIS_SCHEME: "{{ pixelfed_config_redis_scheme }}" + REDIS_HOST: "{{ pixelfed_config_redis_host }}" + REDIS_PASSWORD: "{{ pixelfed_config_redis_password }}" + REDIS_PORT: "{{ pixelfed_config_redis_port }}" + REDIS_DATABASE: "{{ pixelfed_config_redis_database }}" + + ## EXPERIMENTS + EXP_LC: "{{ pixelfed_config_exp_lc }}" + EXP_REC: "{{ pixelfed_config_exp_rec }}" + EXP_LOOPS: "{{ pixelfed_config_exp_loops }}" + + ## ActivityPub Federation + ACTIVITY_PUB: "{{ pixelfed_config_activity_pub }}" + AP_REMOTE_FOLLOW: "{{ pixelfed_config_ap_remote_follow }}" + AP_SHAREDINBOX: "{{ pixelfed_config_ap_sharedinbox }}" + AP_INBOX: "{{ pixelfed_config_ap_inbox }}" + AP_OUTBOX: "{{ pixelfed_config_ap_outbox }}" + ATOM_FEEDS: "{{ pixelfed_config_atom_feeds }}" + NODEINFO: "{{ pixelfed_config_nodeinfo }}" + WEBFINGER: "{{ pixelfed_config_webfinger }}" + + ## S3 + FILESYSTEM_DRIVER: "{{ pixelfed_config_filesystem_driver }}" + FILESYSTEM_CLOUD: "{{ pixelfed_config_filesystem_cloud }}" + PF_ENABLE_CLOUD: "{{ pixelfed_config_pf_enable_cloud }}" + AWS_ACCESS_KEY_ID: "{{ pixelfed_config_aws_access_key_id }}" + AWS_SECRET_ACCESS_KEY: "{{ pixelfed_config_aws_secret_access_key }}" + AWS_DEFAULT_REGION: "{{ pixelfed_config_aws_default_region }}" + AWS_BUCKET: "{{ pixelfed_config_aws_bucket }}" + AWS_URL: "{{ pixelfed_config_aws_url }}" + AWS_ENDPOINT: "{{ pixelfed_config_aws_endpoint }}" + AWS_USE_PATH_STYLE_ENDPOINT: "{{ pixelfed_config_aws_use_path_style_endpoint }}" + + HORIZON_DARKMODE: "{{ pixelfed_config_horizon_darkmode }}" + PF_COSTAR_ENABLED: "{{ pixelfed_config_pf_costar_enabled }}" + MEDIA_EXIF_DATABASE: "{{ pixelfed_config_media_exif_database }}" + LOG_CHANNEL: "{{ pixelfed_config_log_channel }}" + IMAGE_DRIVER: "{{ pixelfed_config_image_driver }}" + + BROADCAST_DRIVER: "{{ pixelfed_config_ }}" + CACHE_DRIVER: "{{ pixelfed_config_cache_driver }}" + RESTRICT_HTML_TYPES: "{{ 'true' pixelfed_config_restrict_html_types else 'false' }}" + QUEUE_DRIVER: "{{ pixelfed_config_queue_driver }}" + SESSION_DRIVER: "{{ pixelfed_config_session_driver }}" + TRUST_PROXIES: "{{ pixelfed_config_trust_proxies }}" + PASSPORT_PRIVATE_KEY: "{{ pixelfed_config_passport_private_key }}" + PASSPORT_PUBLIC_KEY: "{{ pixelfed_config_passport_public_key }}" +