Repository: YunoHost/doc Branch: main Commit: 8e6fc8404d42 Files: 1752 Total size: 10.8 MB Directory structure: gitextract_z2uj399p/ ├── .github/ │ ├── PULL_REQUEST_TEMPLATE.md │ ├── actions/ │ │ └── docusaurus/ │ │ └── action.yml │ └── workflows/ │ ├── auto_regen_pot.yml │ └── build.yml ├── .gitignore ├── .markdownlint-cli2.yaml ├── README.md ├── docs/ │ ├── admin/ │ │ ├── 01.about_self_hosting.mdx │ │ ├── 02.what_is_yunohost/ │ │ │ ├── 10.structure.mdx │ │ │ ├── 20.demo.mdx │ │ │ └── index.mdx │ │ ├── 05.get_started/ │ │ │ ├── 02.why_should_you_not_host_yourself.mdx │ │ │ ├── 05.methods.mdx │ │ │ ├── 10.providers/ │ │ │ │ ├── 05.registrar/ │ │ │ │ │ ├── _category_.yaml │ │ │ │ │ ├── gandi.mdx │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── namecheap.mdx │ │ │ │ │ └── ovh/ │ │ │ │ │ ├── _category_.yaml │ │ │ │ │ ├── autodns.mdx │ │ │ │ │ └── manualdns.mdx │ │ │ │ ├── 10.isp.mdx │ │ │ │ ├── 15.vpn/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ └── vpn_advantage.mdx │ │ │ │ ├── 20.servers.mdx │ │ │ │ └── _category_.yaml │ │ │ ├── 20.install_on/ │ │ │ │ ├── _configuration.mdx │ │ │ │ ├── _install_script.mdx │ │ │ │ ├── arm_board.mdx │ │ │ │ ├── index.mdx │ │ │ │ ├── on_top_of_debian.mdx │ │ │ │ ├── raspberry_pi.mdx │ │ │ │ ├── regular_computer.mdx │ │ │ │ ├── remote_server.mdx │ │ │ │ ├── virtualbox.mdx │ │ │ │ └── wsl.mdx │ │ │ ├── 40.post_install/ │ │ │ │ ├── 10.find_ip.mdx │ │ │ │ ├── 15.port_forwarding.mdx │ │ │ │ ├── 20.dns_config.mdx │ │ │ │ └── _category_.yaml │ │ │ ├── 90.guidelines.mdx │ │ │ └── _category_.yaml │ │ ├── 12.webadmin.mdx │ │ ├── 15.command_line.mdx │ │ ├── 20.users/ │ │ │ ├── groups_and_permissions.mdx │ │ │ └── index.mdx │ │ ├── 25.domains/ │ │ │ ├── certificate.mdx │ │ │ └── index.mdx │ │ ├── 30.apps/ │ │ │ ├── custom_apps.mdx │ │ │ └── index.mdx │ │ ├── 35.email/ │ │ │ ├── 05.clients.mdx │ │ │ ├── 10.migration.mdx │ │ │ └── index.mdx │ │ ├── 40.backups/ │ │ │ ├── 05.evaluate.mdx │ │ │ ├── 10.backup_methods.mdx │ │ │ ├── 15.clone_filesystem.mdx │ │ │ ├── 20.avoid_hardware_failure.mdx │ │ │ ├── 25.include_exclude_files.mdx │ │ │ ├── 30.custom_backup_methods.mdx │ │ │ ├── 35.migrate_or_merge_servers.mdx │ │ │ └── index.mdx │ │ ├── 42.security.mdx │ │ ├── 43.upgrade/ │ │ │ ├── 11.0-bullseye.mdx │ │ │ ├── 12.0-bookworm/ │ │ │ │ ├── 05.issues_faq.mdx │ │ │ │ └── index.mdx │ │ │ └── index.mdx │ │ ├── 45.tutorials/ │ │ │ ├── 05.domains/ │ │ │ │ ├── _category_.yaml │ │ │ │ ├── dns_dynamicip.mdx │ │ │ │ ├── dns_local_network.mdx │ │ │ │ ├── dns_nohost_me.mdx │ │ │ │ └── dns_subdomains.mdx │ │ │ ├── 10.theming.mdx │ │ │ ├── 15.filezilla.mdx │ │ │ ├── 25.external_storage.mdx │ │ │ ├── 35.email_configure_relay.mdx │ │ │ ├── 55.moving_app_folder.mdx │ │ │ ├── 65.sftp_on_apps.mdx │ │ │ ├── 90.freebox_storage.mdx │ │ │ └── _category_.yaml │ │ ├── 50.troubleshooting/ │ │ │ ├── 03.cleanup.mdx │ │ │ ├── 05.fail2ban.mdx │ │ │ ├── 10.change_root_password.mdx │ │ │ ├── 15.noaccess.mdx │ │ │ ├── 20.ipv6.mdx │ │ │ ├── 25.blacklist_forms.mdx │ │ │ └── index.mdx │ │ ├── 80.advanced/ │ │ │ ├── 40.torhiddenservice.mdx │ │ │ ├── 45.certificate_custom.mdx │ │ │ ├── 70.chatons.mdx │ │ │ └── _category_.yaml │ │ ├── _category_.yaml │ │ └── index.mdx │ ├── community/ │ │ ├── 05.faq.mdx │ │ ├── 10.help.mdx │ │ ├── 15.forum.mdx │ │ ├── 20.chat_rooms.mdx │ │ ├── 25.yunohost_project_organization.mdx │ │ ├── 30.project_budget.mdx │ │ ├── 35.security_team.mdx │ │ ├── 40.press_kit.mdx │ │ ├── 40.sponsors_partners.mdx │ │ ├── 90.terms_of_services.mdx │ │ └── index.mdx │ └── dev/ │ ├── 05.git.mdx │ ├── 10.doc.mdx │ ├── 20.translation.mdx │ ├── 50.packaging/ │ │ ├── 05.structure.mdx │ │ ├── 10.manifest.mdx │ │ ├── 15.resources.mdx │ │ ├── 20.scripts/ │ │ │ ├── 20.helpers_v2.0.mdx │ │ │ ├── 20.helpers_v2.1.mdx │ │ │ ├── _category_.yaml │ │ │ └── index.mdx │ │ ├── 30.doc.mdx │ │ ├── 40.test.mdx │ │ ├── 50.publish.mdx │ │ ├── 60.advanced/ │ │ │ ├── 20.config_panels.mdx │ │ │ ├── 30.sso_ldap_integration.mdx │ │ │ ├── 50.hooks.mdx │ │ │ ├── 60.advanced_packagers.mdx │ │ │ ├── 70.packaging_v2.mdx │ │ │ └── _category_.yaml │ │ ├── 80.misc/ │ │ │ ├── _category_.yaml │ │ │ ├── packaging_apps_git.mdx │ │ │ ├── packaging_apps_virtualbox.mdx │ │ │ └── shell_variables_scope.mdx │ │ ├── 90.policy.mdx │ │ └── index.mdx │ ├── 80.core/ │ │ ├── 05.architecture.mdx │ │ ├── 10.devenv.mdx │ │ ├── 20.ynh_core.mdx │ │ ├── 25.ynh_admin.mdx │ │ ├── forms.mdx │ │ ├── index.mdx │ │ └── maindomain.mdx │ └── index.mdx ├── docusaurus.config.ts ├── footer.ts ├── i18n/ │ ├── de/ │ │ ├── code.json │ │ ├── docusaurus-plugin-content-blog/ │ │ │ └── options.json │ │ ├── docusaurus-plugin-content-docs/ │ │ │ ├── current/ │ │ │ │ └── community/ │ │ │ │ └── 05.faq.mdx │ │ │ └── current.json │ │ └── docusaurus-theme-classic/ │ │ ├── footer.json │ │ └── navbar.json │ ├── docs/ │ │ └── admin/ │ │ ├── 01.about_self_hosting/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 02.what_is_yunohost__10.structure/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 02.what_is_yunohost__20.demo/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 02.what_is_yunohost__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__02.why_should_you_not_host_yourself/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__05.methods/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__10.providers__05.registrar__gandi/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__10.providers__05.registrar__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__10.providers__05.registrar__namecheap/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__10.providers__05.registrar__ovh__autodns/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__10.providers__05.registrar__ovh__manualdns/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__10.providers__10.isp/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__10.providers__15.vpn__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__10.providers__15.vpn__vpn_advantage/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__10.providers__20.servers/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__20.install_on___configuration/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__20.install_on___install_script/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__20.install_on__arm_board/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__20.install_on__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__20.install_on__on_top_of_debian/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__20.install_on__raspberry_pi/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__20.install_on__regular_computer/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__20.install_on__remote_server/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__20.install_on__virtualbox/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__20.install_on__wsl/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__40.post_install__10.find_ip/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__40.post_install__15.port_forwarding/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__40.post_install__20.dns_config/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 05.get_started__90.guidelines/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 12.webadmin/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 15.command_line/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 20.users__groups_and_permissions/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 20.users__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 25.domains__certificate/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 25.domains__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 30.apps__custom_apps/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 30.apps__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 35.email__05.clients/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 35.email__10.migration/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 35.email__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 40.backups__05.evaluate/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 40.backups__10.backup_methods/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 40.backups__15.clone_filesystem/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 40.backups__20.avoid_hardware_failure/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 40.backups__25.include_exclude_files/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 40.backups__30.custom_backup_methods/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 40.backups__35.migrate_or_merge_servers/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 40.backups__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 42.security/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 42security/ │ │ │ ├── fr.stats.json │ │ │ ├── pl.stats.json │ │ │ └── tr.stats.json │ │ ├── 43.upgrade__11.0-bullseye/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 43.upgrade__12.0-bookworm__05.issues_faq/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 43.upgrade__12.0-bookworm__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 43.upgrade__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 43upgrade__110-bullseye/ │ │ │ ├── es.stats.json │ │ │ ├── fr.stats.json │ │ │ ├── kab.stats.json │ │ │ ├── pl.stats.json │ │ │ └── tr.stats.json │ │ ├── 43upgrade__120-bookworm__05issues_faq/ │ │ │ ├── fr.stats.json │ │ │ ├── pl.stats.json │ │ │ └── tr.stats.json │ │ ├── 43upgrade__120-bookworm__index/ │ │ │ ├── es.stats.json │ │ │ ├── fr.stats.json │ │ │ ├── kab.stats.json │ │ │ ├── pl.stats.json │ │ │ └── tr.stats.json │ │ ├── 43upgrade__index/ │ │ │ ├── es.stats.json │ │ │ ├── kab.stats.json │ │ │ ├── pl.stats.json │ │ │ └── tr.stats.json │ │ ├── 45.tutorials__05.domains__dns_dynamicip/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 45.tutorials__05.domains__dns_local_network/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 45.tutorials__05.domains__dns_nohost_me/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 45.tutorials__05.domains__dns_subdomains/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 45.tutorials__10.theming/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 45.tutorials__15.filezilla/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 45.tutorials__25.external_storage/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 45.tutorials__35.email_configure_relay/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 45.tutorials__55.moving_app_folder/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 45.tutorials__65.sftp_on_apps/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 45.tutorials__90.freebox_storage/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 50.troubleshooting__03.cleanup/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 50.troubleshooting__05.fail2ban/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 50.troubleshooting__10.change_root_password/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 50.troubleshooting__15.noaccess/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 50.troubleshooting__20.ipv6/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 50.troubleshooting__25.blacklist_forms/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 50.troubleshooting__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 55.upgrade__11.0-bullseye/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 55.upgrade__12.0-bookworm__05.issues_faq/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 55.upgrade__12.0-bookworm__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 55.upgrade__index/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 80.advanced__40.torhiddenservice/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 80.advanced__45.certificate_custom/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 80.advanced__70.chatons/ │ │ │ ├── ar.po │ │ │ ├── ca.po │ │ │ ├── de.po │ │ │ ├── en.pot │ │ │ ├── es.po │ │ │ ├── eu.po │ │ │ ├── fr.po │ │ │ ├── gl.po │ │ │ ├── id.po │ │ │ ├── it.po │ │ │ ├── kab.po │ │ │ ├── nn.po │ │ │ ├── pl.po │ │ │ ├── pt_BR.po │ │ │ ├── ru.po │ │ │ ├── tr.po │ │ │ ├── uk.po │ │ │ ├── uz.po │ │ │ └── zh_Hans.po │ │ ├── 80advanced__40torhiddenservice/ │ │ │ ├── fr.stats.json │ │ │ ├── kab.stats.json │ │ │ ├── pl.stats.json │ │ │ └── tr.stats.json │ │ ├── 80advanced__45certificate_custom/ │ │ │ ├── es.stats.json │ │ │ ├── fr.stats.json │ │ │ ├── pl.stats.json │ │ │ └── tr.stats.json │ │ ├── 80advanced__70chatons/ │ │ │ ├── gl.stats.json │ │ │ ├── pl.stats.json │ │ │ └── tr.stats.json │ │ └── index/ │ │ ├── ar.po │ │ ├── ca.po │ │ ├── de.po │ │ ├── en.pot │ │ ├── es.po │ │ ├── eu.po │ │ ├── fr.po │ │ ├── gl.po │ │ ├── id.po │ │ ├── it.po │ │ ├── kab.po │ │ ├── nn.po │ │ ├── pl.po │ │ ├── pt_BR.po │ │ ├── ru.po │ │ ├── tr.po │ │ ├── uk.po │ │ ├── uz.po │ │ └── zh_Hans.po │ ├── en/ │ │ ├── code.json │ │ ├── docusaurus-plugin-content-blog/ │ │ │ └── options.json │ │ ├── docusaurus-plugin-content-docs/ │ │ │ └── current.json │ │ └── docusaurus-theme-classic/ │ │ ├── footer.json │ │ └── navbar.json │ ├── es/ │ │ ├── code.json │ │ ├── docusaurus-plugin-content-blog/ │ │ │ └── options.json │ │ ├── docusaurus-plugin-content-docs/ │ │ │ ├── current/ │ │ │ │ └── community/ │ │ │ │ └── 20.chat_rooms.mdx │ │ │ └── current.json │ │ └── docusaurus-theme-classic/ │ │ ├── footer.json │ │ └── navbar.json │ ├── fr/ │ │ ├── code.json │ │ ├── docusaurus-plugin-content-blog/ │ │ │ └── options.json │ │ ├── docusaurus-plugin-content-docs/ │ │ │ ├── current/ │ │ │ │ └── community/ │ │ │ │ ├── 05.faq.mdx │ │ │ │ ├── 10.help.mdx │ │ │ │ ├── 20.chat_rooms.mdx │ │ │ │ ├── 30.project_budget.mdx │ │ │ │ ├── 35.security_team.mdx │ │ │ │ ├── 40.sponsors_partners.mdx │ │ │ │ └── 90.terms_of_services.mdx │ │ │ └── current.json │ │ └── docusaurus-theme-classic/ │ │ ├── footer.json │ │ └── navbar.json │ ├── it/ │ │ ├── code.json │ │ ├── docusaurus-plugin-content-blog/ │ │ │ └── options.json │ │ ├── docusaurus-plugin-content-docs/ │ │ │ ├── current/ │ │ │ │ └── community/ │ │ │ │ ├── 05.faq.mdx │ │ │ │ └── 20.chat_rooms.mdx │ │ │ └── current.json │ │ └── docusaurus-theme-classic/ │ │ ├── footer.json │ │ └── navbar.json │ └── ru/ │ ├── code.json │ ├── docusaurus-plugin-content-blog/ │ │ └── options.json │ ├── docusaurus-plugin-content-docs/ │ │ └── current.json │ └── docusaurus-theme-classic/ │ ├── footer.json │ └── navbar.json ├── package.json ├── redirects.ts ├── scripts/ │ ├── check_missing_or_bad_image_path.sh │ ├── dead_links.py │ ├── forms_doc_generate.py │ ├── forms_doc_template.md.j2 │ ├── generate_docs.sh │ ├── helpers_doc_generate.py │ ├── helpers_doc_template.md.j2 │ ├── patch_enabled_locales.sh │ ├── po4a.py │ ├── resources_doc_generate.py │ ├── resources_doc_template.md.j2 │ └── update_ui_translations.sh ├── sidebars.ts ├── src/ │ ├── YunoHostImagesListScript.js │ ├── components/ │ │ ├── Button.tsx │ │ ├── Column.tsx │ │ ├── Columns.tsx │ │ ├── Figures.tsx │ │ ├── HardRedirects.tsx │ │ ├── Highlight.tsx │ │ ├── SidebarDocCardList.tsx │ │ ├── SmallInline.tsx │ │ ├── YunoHostDocsCard.module.css │ │ ├── YunoHostDocsCard.tsx │ │ └── YunoHostImagesList.tsx │ ├── css/ │ │ └── custom.css │ ├── pages/ │ │ ├── index.module.css │ │ └── index.tsx │ └── theme/ │ ├── DocCard/ │ │ ├── index.tsx │ │ └── styles.module.css │ └── MDXComponents.tsx └── static/ ├── img/ │ ├── ecosystem.odg │ ├── ecosystem_fr.odg │ ├── internet_topologies_fr_src.odg │ ├── internet_topologies_src.odg │ ├── internet_topologies_with_ynh_fr_src.odg │ ├── internet_topologies_with_ynh_src.odg │ ├── portForwarding_src_en.odg │ └── portForwarding_src_fr.odg └── js/ └── language-detect.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## Problem - *Description of why you made this PR, what is its purpose* ## Solution - *And how do you relevantly fix that problem* ## PR checklist - [ ] PR finished and ready to be reviewed ================================================ FILE: .github/actions/docusaurus/action.yml ================================================ name: Check and build Docusaurus doc inputs: base_url: description: Base URL to pass to Docusaurus required: true default: / runs: using: "composite" steps: - name: Set up Python uses: actions/setup-python@v5 - name: Set up Node uses: actions/setup-node@v4 with: node-version: lts/* - name: Installation shell: bash run: npm ci - name: Install perl dependencies (for po4a) shell: bash run: sudo apt install gettext libyaml-tiny-perl libsyntax-keyword-try-perl libpod-parser-perl libsgmls-perl opensp perl liblocale-gettext-perl libterm-readkey-perl libtext-wrapi18n-perl libunicode-linebreak-perl -y - name: Check image paths consistency shell: bash run: bash scripts/check_missing_or_bad_image_path.sh - name: Tweak enabled locales according to Weblate statistics (keep langs with >= 5% translated) shell: bash run: bash scripts/patch_enabled_locales.sh - name: Regen UI translations shell: bash run: bash scripts/update_ui_translations.sh - name: Build translated .mdx using the .po from po4a/weblate shell: bash run: python3 ./scripts/po4a.py build_translated_mdx - name: Build docs env: BASE_URL: "${{ inputs.base_url }}" shell: bash run: | echo "Using baseUrl=$BASE_URL" npm run build ================================================ FILE: .github/workflows/auto_regen_pot.yml ================================================ name: Auto-regen the .pot used as source for translations (po4a/Weblate) on: push: branches: [ "main" ] jobs: auto_regen_pot: runs-on: ubuntu-latest permissions: # Give the default GITHUB_TOKEN write permission to commit and push the changed files back to the repository. contents: write steps: - uses: actions/checkout@v4 - name: Install perl dependencies (for po4a) shell: bash run: sudo apt install gettext libyaml-tiny-perl libsyntax-keyword-try-perl libpod-parser-perl libsgmls-perl opensp perl liblocale-gettext-perl libterm-readkey-perl libtext-wrapi18n-perl libunicode-linebreak-perl -y - name: Check image paths consistency shell: bash run: bash scripts/check_missing_or_bad_image_path.sh - name: Build translated .mdx using the .po from po4a/weblate shell: bash run: python3 ./scripts/po4a.py regen_pot - uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: "🌐 ${{ github.workflow }}" ================================================ FILE: .github/workflows/build.yml ================================================ name: Build Docusaurus doc on: push: branches: - main - next concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: build: name: Build Docs timeout-minutes: 30 runs-on: ubuntu-latest env: # This variable allow to build for either doc.yunohost.org or nextdoc.yunohost.org BUILD_FOR: ${{ github.ref == 'refs/heads/main' && 'main' || 'next' }} steps: - name: Checkout uses: actions/checkout@v4 - name: Check and build doc uses: ./.github/actions/docusaurus - name: Archive the docs uses: actions/upload-artifact@v4 with: name: docs path: build/ deploy: name: Deploy the new doc needs: build runs-on: ubuntu-latest if: ${{github.event_name == 'push' && ( github.ref == 'refs/heads/main' || github.ref == 'refs/heads/next' ) }} env: APP: ${{ github.ref == 'refs/heads/main' && 'my_webapp' || 'my_webapp__4' }} steps: - name: Download the built docs artifact uses: actions/download-artifact@v4 with: name: docs path: docs - name: Install tools run: | sudo apt install sshpass rsync - name: Deploy run: sshpass -p ${{ secrets.DOC_SFTP_PWD }} rsync -avz --delete -e "ssh -o StrictHostKeyChecking=no" docs/ ${APP}@apicius.yunohost.org:~/www/ ================================================ FILE: .gitignore ================================================ # Dependencies /node_modules # Production /build # Generated files .docusaurus .cache-loader # Misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* # Virtualenv for tools /.venv /venv .po4a i18n/*/docusaurus-plugin-content-docs/current/admin/ ================================================ FILE: .markdownlint-cli2.yaml ================================================ ignores: # This page contains markdown issues on purpose - pages/06.contribute/05.write_documentation/02.markdown_guide/doc_markdown_guide* # Those pages are auto-generated, issues found there should be fixed upstream - pages/06.contribute/10.packaging_apps/10.manifest/10.appresources/packaging_app_manifest_resources.md - pages/06.contribute/10.packaging_apps/20.scripts/10.helpers/packaging_app_scripts_helpers.md - pages/06.contribute/10.packaging_apps/20.scripts/12.helpers21/packaging_app_scripts_helpers_v21.md - pages/06.contribute/10.packaging_apps/80.resources/15.appresources/packaging_apps_resources.md - pages/06.contribute/15.dev/03.forms/forms.md config: default: true # FIXME: should be removed when actually fixed no-alt-text: false # Title pages have first-level headings duplicated with the markdown header single-title: false # Github and grav don't have the same heading link fragment algorithm, headings with `'` are broken link-fragments: false code-block-style: style: fenced code-fence-style: style: backtick emphasis-style: style: asterisk strong-style: style: asterisk ul-style: style: dash ul-indent: indent: 2 heading-style: style: atx no-duplicate-heading: siblings_only: true hr-style: style: --- ol-indent: indent: 2 ol-prefix: style: ordered no-trailing-punctuation: punctuation: ".,;:" no-inline-html: false MD040: allowed_languages: - bash - html - css - javascript - php - json - yaml - toml - markdown - text - nginx language_only: true proper-names: code_blocks: false html_elements: false names: - YunoHost - GitHub line-length: false no-reversed-links: false no-missing-space-atx: false first-line-heading: false ================================================ FILE: README.md ================================================ # YunoHost Documentation This repository contains the code for [the YunoHost documentation](https://doc.yunohost.org). It is built using [Docusaurus 3](https://docusaurus.io), a modern static website generator. Issues are to be reported on [the YunoHost bugtracker](https://github.com/YunoHost/issues/issues). App-specific documentation doesn't happen here but in the package/app repositories themselves. More info in [the dedicated page](https://doc.yunohost.org/packaging/doc/). Checkout **** for more info on how to work on documentation, and **** for more info on how to work on translation. # Building / previewing the doc locally Checkout instructions on or [this file in this repo](docs/dev/10.doc.mdx) ================================================ FILE: docs/admin/01.about_self_hosting.mdx ================================================ --- title: About self-hosting hide_table_of_contents: true --- Self-hosting means owning and administrating your own server, typically at home, to host your **personal data and services** yourself instead of relying exclusively on third parties. For instance, you can self-host your blog, such that it 'lives' on a machine that you have control of, instead of having it on somebody else's computer (a.k.a. FAANG or The Cloud) in exchange for money, advertisements, or private data. Self-hosting implies owning a server. **A server is a computer that is typically accessible on the network 24/7**, and usually does not have a screen or keyboard (it is instead controlled remotely). Contrary to a popular belief, a server is not necessarily a huge and extra-powerful machine: nowadays, a small, ~$30 ARM board is adequate for self-hosting. ![Internet topologies diagram](/img/internet_topologies.png) Self-hosting is not about making "your Internet" more secure and does not provide anonymity by itself. Instead, it is about being autonomous and in control of your services and data — which also means being responsible for them. ================================================ FILE: docs/admin/02.what_is_yunohost/10.structure.mdx ================================================ --- title: Structure of a YunoHost server hide_table_of_contents: true --- This page provide an overview of the ecosystem of a YunoHost server. While this overview contains several approximations, the purpose here is to introduce the global picture before digging into the different aspects. ![Yunohost ecosystem graph](/img/ecosystem.png) Everything starts with the special user **admin**. This is the administrator of the machine who can install, configure and manage things on the server through the web administration interface, or via SSH and the command line interface. *(If you are already familiar with GNU/Linux, it is quite similar to root. YunoHost has this additional 'admin' user for several technical reasons.)* The administrator can create users and install applications, among other admin actions. Users automatically have their own email address when they get created. Users will also be able to connect to the user portal (SSO) to access applications. Some applications can typically be installed either as publicly-accessible, or as private, i.e. only some users will have access to it depending on which groups they are member of. Applications and their features of the server rely on different services to work properly. Services (sometimes also called daemons) are programs that are constantly running on the server to ensure various tasks are done, such as answering to web requests from web browsers, or relaying emails. ================================================ FILE: docs/admin/02.what_is_yunohost/20.demo.mdx ================================================ --- title: Try YunoHost description: A demo server routes: default: '/try' hide_table_of_contents: true --- import {YunoHostDocsCard, YunoHostDocsCardHeading} from '@site/src/components/YunoHostDocsCard'; # Try YunoHost on a demo server :::caution This demo server is reset *every 30 minutes* and could be down from time to time, but at least you can test and that's really cool :) :::
User interface https://demo.yunohost.org username: `demo` password: `demo` Administration interface https://demo.yunohost.org/yunohost/admin/ username: `demo` password: `demo`
:::info **Demo server gracefully provided by [Gitoyen](https://www.gitoyen.net?target=_blank) ** ::: ================================================ FILE: docs/admin/02.what_is_yunohost/index.mdx ================================================ --- title: What is YunoHost? hide_table_of_contents: true --- YunoHost is an **operating system** aiming to **simplify server administration** and therefore democratize [self-hosting](/admin/about_self_hosting) while making sure it stays reliable, secure, ethical and lightweight. It is a copylefted libre software project maintained by volunteers. Technically, it can be seen as a server distribution based on [Debian GNU/Linux](https://debian.org). YunoHost can be installed on [many kinds of hardware](/admin/get_started/install_on), either at home or on a remote server (VPS). ![General representation of a YunoHost server installation](/img/internet_topologies_with_ynh.png?resize=600) ## Features - Based on Debian, for a trustworthy & familiar base; - Administer your server through a **friendly web interface** as well as a handy CLI; - Deploy **apps in just a few clicks** from [our more than 500 apps catalog](https://apps.yunohost.org)!; - Manage **users** (based on LDAP); - Manage **domain names**; - Create and restore **backups**; - Connect to all apps simultaneously through the **user portal** (NGINX, SSOwat); - Includes a **full e-mail stack** (Postfix, Dovecot, OpenDKIM, PostSRSd); - Manages **SSL certificates** (based on Let's Encrypt); - ... and **security systems** (`fail2ban`, firewall using `nftables`). ## Origin YunoHost was created in February 2012 after something like this: > "Shit, I'm too lazy to reconfigure my mail server... Beudbeud, how were you able to get your little server running with LDAP?" > *Kload, February 2012* All that was needed was an admin interface for Beudbeud's server to make something usable, so Kload decided to develop one. Finally, after automating several configs and packaging in some web apps, YunoHost v1 was finished. Noting the growing enthusiasm around YunoHost and around self-hosting in general, the original developers, along with new contributors, decided to start work on version 2, a more extensible, more powerful, more easy-to-use, and, at that, one that makes a nice cup of fair-trade coffee for the elves of Lapland. The name **YunoHost** comes from the jargon "[Y U NO](https://knowyourmeme.com/memes/y-u-no-guy) Host". The [Internet meme](https://en.wikipedia.org/wiki/Internet_meme) should illustrate it:
![The meme in question, showing a guy with a face bent in frustration and questioning "Y U NO Host"](/img/dude_yunohost.jpg)
## What YunoHost is not? **YunoHost is *not* an enterprise or a for-profit entity.** It is developed and maintained by volunteers. We do not sell services, we do not host or control your data or services in any way, and we have no intention or interest in monetizing anything. We also do not offer any formal guarantees. Our goal is simply to develop and maintain YunoHost in the hope that it contributes to a more decentralized internet and empowers people to reclaim autonomy over their digital services and technology. That said, we do our best to provide community support, and commercial support may be available through third parties if needed. **YunoHost as a project is *not* apolitical.** By its very nature, YunoHost promotes a decentralized internet and technologies that empower people. We reject the flawed notion that technology is inherently neutral, or that software projects should remain neutral. Many contributors to the project remain vigilant about the social and political implications of technological developments, and emphasize the importance of solidarity and alignment with broader movements such as feminism, LGBTQIA+ rights and visibility, environmental justice, and social justice. We stand firmly against fascism, sexism, racism, xenophobia, [bigotry](https://simple.wikipedia.org/wiki/Bigotry), ableism, imperialism, extractivism, [eugenics](https://en.wikipedia.org/wiki/Eugenics), and right-wing libertarianism. If you are not aligned with these values, you are encouraged to *not* use YunoHost and look for a different system. **YunoHost is *not* designed to "scale" in the traditional sense.** It is intended for a relatively modest number of user accounts and simultaneous users. While there is no strict limit—since performance depends heavily on your specific setup — we estimate that some technical adjustments may be necessary when reaching 250~500 user accounts, or about 50 simultaneous users on resource-intensive apps. That said, YunoHost can comfortably handle hosting a website or several lightweight services, even with thousands of daily visitors. **YunoHost is primarily designed for people who want things to "just work".** Of course, it’s not perfect — we're constantly working to improve the user experience, robustness, and simplicity. Though YunoHost is "tinkerable", the first target public is *not* power users with complex or highly customized use cases in mind. We encourage you to keep your setup as simple as possible. That said, you are more than welcome to experiment and share your feedback with us! **YunoHost is *not* designed to be a *heavy* multi-tenant solution** for providing services to completely separate organizations across different domains. While you *can* manage multiple domains and subdomains — such as hosting apps for friends, colleagues, and an association — you should keep in mind that there is no strict isolation between apps. Under the hood, all applications share the same system and environment. (Note for power users) **YunoHost does not use "hard" containerization technologies** such as Docker, for its apps. This is partly for historical reasons and partly to keep the system lightweight — both in terms of resource usage and technical complexity. That said, we do take security seriously: applications run under dedicated user accounts with limited privileges and capabilities, and we're continuously working to enhance the system’s security. ## Artworks Black and white YunoHost by ToZz. Licence: CC-BY-SA 4.0. Logos and other artwork are available in [the Artworks repository](https://github.com/YunoHost/yunohost-artwork). ================================================ FILE: docs/admin/05.get_started/02.why_should_you_not_host_yourself.mdx ================================================ --- title: Why should you (not?) host yourself? hide_table_of_contents: true description: " " hide_title: true --- ## Why should you host yourself? - **You believe in a free, open and decentralized internet.** In a centralized internet, private companies and government can spy, analyze and influence people by dictating how they connect with each other, and by filtering content. YunoHost is developed by a community who believe in an open and decentralized internet, and we hope that you do, too! - **You want to have control of your data and services.** Your pictures, chat messages, browsing history, and that text you are writing for school, have nothing to do on somebody else's server (a.k.a. The Cloud). They are part of your private life, but also part of your family's life, your friend's life, and so on. These data should be managed by *you*, not a random company in the US who wants your data to analyze them and sell the results. - **You want to learn about how computers and the Internet work.** Operating your own server is a pretty good context to understand the basic mechanisms at the heart of operating systems and the Internet. You might have to deal with command line interface, network architecture, DNS configuration, SSH, and so on. - **You want to explore new possibilities and customize things.** Ever dreamed of running a Minecraft server for you friends, or a persistent IRC or XMPP client? With your very own server, you can manually install and run virtually any program you want, and customize every bit. ## Why should you *not* host yourself? - **Self-hosting requires some work and patience.** Hosting yourself is a bit like growing your own garden or vegetables: it requires work and patience. While YunoHost aims to do all the hard work for you, self-hosting still requires that you take time to learn and configure a few things to setup your server properly. You will also need to perform maintenance tasks (such as upgrades) from time to time, or to ask for support if some things break. - **With great servers comes great responsibilities.** Operating a server means that you are responsible for the data you are hosting. Nobody will be able to recover them for you if they get lost. YunoHost provides backup features, which you should use regularly to backup the configurations and data you care about. You should also keep an eye on security news and recommendations so that your server or critical data don't get compromised. - **Quality and performance probably won't be as good as premium services.** YunoHost (and most of the applications packaged for it) are free and open-source software, developed by communities of people in their free time and on the basis of best effort. There is no absolute guarantee that software will work in every possible circumstance. The performance of your self-hosted server is also related to its CPU and RAM, and to the available internet connectivity. ================================================ FILE: docs/admin/05.get_started/05.methods.mdx ================================================ --- title: Choose your self-hosting mode hide_table_of_contents: true --- You can host yourself at home (on a small computer), or on a remote server. Each solution has its pros and cons: ## At home, for instance on an ARM board or an old computer You can host yourself at home with an ARM board or a re-purposed regular computer, connected to your home router/box. - **Pros**: you will have physical control of the machine and only need to buy the hardware; - **Cons**: you will have to [manually configure your internet box](/admin/get_started/post_install/port_forwarding) and [might be limited by your ISP](/admin/get_started/providers/isp/). ## At home, behind a VPN A VPN is an encrypted tunnel between two machines. In practice, it makes it "as if" you were directly, locally, connected to your server machine, but actually from somewhere else on the Internet. This allows you to still host yourself at home, while bypassing possible limitations of your ISP. See also [the Internet Cube project](https://internetcu.be/) and [the FFDN](https://www.ffdn.org/). - **Pros**: you will have physical control of the machine, and the VPN hides your traffic from your ISP and allows you to bypass its limitations; - **Cons**: you will have to pay a monthly subscription for the VPN. ## On a remote server (VPS or dedicated server) You can rent a virtual private server or a dedicated machine from [associative](https://db.ffdn.org/) or [commercial](/admin/get_started/providers/servers) "Cloud" providers. - **Pros**: your server and its internet connectivity will be fast; - **Cons**: you will have to pay a monthly subscription and won't have physical control of your server. ## Summary export const styleNone = { textAlign: 'center', }; export const styleGood = { textAlign: 'center', backgroundColor: 'green', color: 'white', }; export const styleMeh = { textAlign: 'center', backgroundColor: 'darkgoldenrod', color: 'white', }; export const styleDanger = { textAlign: 'center', backgroundColor: 'brown', color: 'white', };
At home
(e.g. ARM board, old computer)
At home
behind a VPN
On a remote server
(VPS or dedicated)
Hardware cost About 50€
(e.g. a Raspberry Pi)
None
Monthly cost Negligible
(electricity)
Around 5€
(VPN)
Starting at ~3€
(VPS)
Physical control of the machine Yes Yes No
Manual port routing required Yes No No
Possible ISP limitations Yes
(see here)
Bypassed by VPN Typically no
Internet connectivity Depends on home connectivity Typically pretty good
================================================ FILE: docs/admin/05.get_started/10.providers/05.registrar/_category_.yaml ================================================ ================================================ FILE: docs/admin/05.get_started/10.providers/05.registrar/gandi.mdx ================================================ --- sidebar_label: Gandi title: Obtaining an API key from Gandi --- This page is meant to guide you in obtaining an API key from Gandi in order to configure YunoHost's automatic DNS configuration mecanism :::caution **DO NOT share your API tokens with anybody!** A malicious attacker obtaining your tokens could take over your domain, and possibly your server! ::: 1. Go to [https://account.gandi.net/](https://account.gandi.net/) 2. You should land on this page. Then click on 'Security' ![](/img/providers/registrar_api_gandi_1.png) 3. In the next page, click on '(re)Generate the API key'. ![](/img/providers/registrar_api_gandi_2.png) ================================================ FILE: docs/admin/05.get_started/10.providers/05.registrar/index.mdx ================================================ --- title: Registrars --- Since version 4.3, YunoHost includes a mechanism to interface your server with your DNS registrar API, with the purpose of simplifying and automatizing DNS records registration and maintenance. The procedure requires an initial configuration where you need to generate an API key on your registrar's interface. Not all registrars are supported. So far, the community tested and validated the interface with [Gandi](https://gandi.net) and [OVH](https://ovh.com), which are recommended. The interface with other registrars may work, but is still considered experimental until we gather feedback from the community. The list below can help you to choose a registrar if you plan to buy a domain name to use it with YunoHost. | Registrar | Compatibility | Easy to obtain an API key | Howto | |-------------------------------------|-----------------------------|---------------------------|-------| | [Gandi](https://www.gandi.net) | ✘ (broken) | ✘ | [Obtain an API key](/admin/get_started/providers/registrar/gandi)
[See bug here](https://github.com/YunoHost/issues/issues/2419) | | [OVH](https://ovh.com/domaines) | ✔ (tested) | ✘ | [Obtain an API key](/admin/get_started/providers/registrar/ovh/autodns)
[Configure manually](/admin/get_started/providers/registrar/ovh/manualdns) | | [Namecheap](https://namecheap.com) | ✘ (in lexicon but untested) | ✘✘✘ API not available without 50$ on the account | [Obtain an API key](/admin/get_started/providers/registrar/namecheap) | ================================================ FILE: docs/admin/05.get_started/10.providers/05.registrar/namecheap.mdx ================================================ --- sidebar_label: Namecheap title: Obtaining an API key from Namecheap --- See the [API Documentation](https://www.namecheap.com/support/api/intro/) for reference. 1. Login to your Namecheap account. 2. Go to the Profile > Tools menu. 3. Scroll down to the Business & Dev Tools section. Click on MANAGE next to Namecheap API Access. 4. Toggle ON/OFF, read our Terms of Service, enter your account password. 5. After enabling API access, you will be allotted an APIKey. Your Namecheap account username will act as API username. Your access to the API is authenticated using these elements. ================================================ FILE: docs/admin/05.get_started/10.providers/05.registrar/ovh/_category_.yaml ================================================ label: "OVH" ================================================ FILE: docs/admin/05.get_started/10.providers/05.registrar/ovh/autodns.mdx ================================================ --- sidebar_label: OVH DNS config via API title: Obtaining an API key from OVH --- This page is meant to guide you in obtaining an API key from OVH in order to configure YunoHost's automatic DNS configuration mecanism :::caution **DO NOT share your API tokens with anybody!** A malicious attacker obtaining your tokens could take over your domain, and possibly your server! ::: 1. Go to [the OVH token request page](https://eu.api.ovh.com/createToken/) 2. Fill the form with the required information as shown below: - Account ID or email address: This is your usual OVH login - Password: This is your usual OVH password - Script Name: for example `YunoHost Auto DNS` - Script description: for example `YunoHost Auto DNS` - Validity: `Unlimited` - Rights: use the `+` button to add the following lines - `GET` : `/domain/zone/*` - `POST` : `/domain/zone/*` - `PUT` : `/domain/zone/*` - `DELETE` : `/domain/zone/*` ![](/img/providers/registrar_api_ovh_1.png) 3. You will obtain three tokens (an application key, a secret application key, and a consumer key) which should be used in YunoHost's configuration ================================================ FILE: docs/admin/05.get_started/10.providers/05.registrar/ovh/manualdns.mdx ================================================ --- sidebar_label: OVH manual DNS config title: DNS Configuration with OVH --- Let's see how to properly set the DNS redirections with [OVH](http://www.ovh.com). Once you bought your domain name, got to the Web Control Panel, and click on you domain name on the left side: ![OVH website screenshot](/img/providers/ovh_control_panel.png?resize=800) Click on the **DNS Zone** tab, then on **Add an entry**: ![OVH website screenshot](/img/providers/ovh_dns_zone.png?resize=800) Now you need to add the DNS redirections as specified by the [standard DNS zone configuration](/admin/get_started/post_install/dns_config) Click on "Change in text format", keep the first four lines: ```text $TTL 3600 @ IN SOA dns104.ovh.net. tech.ovh.net. (2020083101 86400 3600 3600000 60) IN NS dns104.ovh.net. IN NS ns104.ovh.net. ``` then erase everything below, and replace it with the configuration generated by YunoHost as explained in [this page](/admin/get_started/post_install/dns_config). ### Dynamic IP [General tutorial on dynamic IP](/admin/tutorials/domains/dns_dynamicip). You should follow this part if you have a dynamic IP. Find out if your ISP provides you with a dynamic IP address [here](/admin/get_started/providers/isp/). Let's create a DynHost id. Follow [this tutorial](http://blog.developpez.com/brutus/p6316/ubuntu/configurer_dynhost_ovh_avec_ddclient) to install ddclient. ddclient will take care of telling OVH that the IP has changed. Then OVH will update the IP. You need to add in the configuration file: - your login and password DynHost - your domain name You should also check out [OVH's guide on DynHost](https://www.ovh.co.uk/g2024.hosting_dynhost). ================================================ FILE: docs/admin/05.get_started/10.providers/10.isp.mdx ================================================ --- title: Internet service providers hide_table_of_contents: true description: " " --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; | Fournisseur d’accès | Box/modem/routeur | [Port 25 ouvrable](/admin/email)| [Hairpinning](http://fr.wikipedia.org/wiki/Hairpinning) | [Reverse DNS](https://en.wikipedia.org/wiki/Reverse_DNS_lookup) | Fixed IP | | :--------: | :------: | :---: | :-----: | :-----: | :-----: | | **Orange** | Livebox2 | non | **non** | **non** | **non** | | **Moov** | | | | | | | **MTN** | | | | | | | Service provider | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | --------------------------- | ------------------------ | --- | --- | ------- | | **LG U+ (HelloVision)** | Yes (Without ISP Router) | No | - | Partial | | **KT (SkyLife, Qook&Show)** | Yes | No | - | Partial | | **SKT (SK Broadband)** | Yes | No | - | Partial | | Service provider | Box/modem/router | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | -------------------------- | -------- | --- | -------------------------- | --- | ------- | | **CHT (Chunghwa Telecom)** | Multiple | Yes | Yes (Need hidden settings) | No | Partial | | Service provider | Box/modem/router | [Poort 25 openen mogelijk](/admin/email)| [Hairpinning](http://fr.wikipedia.org/wiki/Hairpinning) | [Reverse DNS](https://en.wikipedia.org/wiki/Reverse_DNS_lookup) | vaste IP | | :----------: | :---: | :---: | :-----: | :-----: | :-----: | | **Proximus** | BBox2 | ja | **nee** | **nee** | **nee** | | | BBox3 | ja | **nee** | **nee** | **nee** | | **Scarlet** | BBox2 | ja | **nee** | **nee** | **nee** | :::caution **Proximus** zou niet openstaan voor self-hosting. Het openen van de poorten zou moeilijker zijn om SPAM te voorkomen. Het loont de moeite om een vpn te gebruiken. ::: | Fournisseur d’accès | Box/modem/routeur | [Port 25 ouvrable](/admin/email)| [Hairpinning](http://fr.wikipedia.org/wiki/Hairpinning) | [Reverse DNS](https://en.wikipedia.org/wiki/Reverse_DNS_lookup) | IP fixe | | :----------: | :----------: | :---: | :-----: | :-----: | :-----: | | **Proximus** | BBox2 | oui | **non** | **non** | **non** | | | BBox3 | oui | **non** | **non** | **non** | | **Scarlet** | BBox2 | oui | **non** | **non** | **non** | :::caution **Proximus** ne serait pas ouvert à l’auto-hébergement. L’ouverture des ports serait plus difficile afin d’éviter tout SPAM. Il serait préférable de passer par [Neutrinet](http://neutrinet.be), un des [membres de la Fédération French Data Network](http://www.ffdn.org/fr/membres). ::: | Service provider | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | ---------------- | ---------------- | ------------------------------------------------------- | --------------------------- | -------- | | DNA | No | Yes | No | No. Only for business. | | Elisa | No | Yes | Not available for consumers | No. Only for Business. | | Telia | No | Yes | Not available for consumers | No. Only for Business. | :::caution Regulations in Finland prohibit the use of Port 25 for consumers. ::: :::tip Tous les fournisseurs d’accès à Internet [membres de la Fédération French Data Network](http://www.ffdn.org/fr/membres) ont une politique favorable à l’auto-hébergement. ::: | Fournisseur d’accès | Box/modem/routeur | [Port 25 ouvrable](/admin/email) | [Hairpinning](http://fr.wikipedia.org/wiki/Hairpinning) | [Reverse DNS](https://en.wikipedia.org/wiki/Reverse_DNS_lookup) personnalisable | [IP fixe](/admin/tutorials/domains/dns_dynamicip) | [Non listé sur le DUL](https://en.wikipedia.org/wiki/Dialup_Users_List) | | -------------------- | ------------------------ | -------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------- | | OVH | Personnel
ou Box OVH | ✔ | ✔ | ✔ | ✔ | … | | Free | Freebox | ✔ | ✔ | ✔ (sauf IPv6, pas de support, et buggué sur certaines plages d'adresses ipv4) | ✔ | ✘ | | SFR | Neufbox | ✔ | ✔/✘ | … | ✔/✘ | … | | Orange | Livebox | ✘ | ✔ (depuis la Livebox 4) | ✘ (XXX.pro.dns-orange.fr disponible sur les abonnements orange pro) | ✘ (en option depuis la Livebox 3 et sur les abonnements orange pro) | … | | Bouygues
Télécom | Bbox | ✔ | ✔ | ✘ | … | … | | Darty | Dartybox | ✔ | ✔ | ✘ | … | … | Pour une liste plus complète et précise, référez-vous à la très bonne documentation de [wiki.auto-hebergement.fr](http://wiki.auto-hebergement.fr/fournisseurs/fai#d%C3%A9tail_des_fai). :::tip [FDN](http://www.fdn.fr) fournit des [VPN](http://www.fdn.fr/-VPN-.html) permettant de rapatrier une (ou plusieurs sur demande) IPv4 fixe et un /48 en IPv6 et ainsi « nettoyer » votre connexion si vous êtes chez l’un des FAI *limitants* du tableau ci-dessus. :::
| Service provider | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | ------------------------------------- | ------------------ | ------------------------------------------------------- | ------------------------ | ---------- | | DIGI Távközlési és Szolgáltató Kft. | No. Business only. | No | No. Business only | No. Business only | | Telekom Magyarország | No | No | No | No | :::tip DIGI allows non-business users to subscribe to their business plan, for roughly the same price as the regular plan. Fix IP is an additional subscription for business plan users. ::: | Service provider | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | ---------------- | ---------------- | ------------------------------------------------------- | ------------------------ | -------- | | Whizzy Internet | Yes | Yes | Yes | Yes | | Service provider | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | ---------------- | ------------------ | ------------------------------------------------------- | ------------------------ | ------------------ | | Telia | No. Business only. | Yes | No. Business only. | No. Business only. | | Bredbandsbolaget | No. Business only. | Yes | No. Business only. | No. Business only. | | Ownit | Yes | N/A? | ? | Yes | Ownit reserves port 3 and 4 of their router to TV. With a simple call to their hotline, explaining that you want to selfhost, they can reassign one of the ports to be in bridge mode. It means that your server will have its own public fixed IP address, in addition to the modem's. NB: Most of non-business IP provided by ISP are blocklisted. | Service provider | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | ---------------- | ---------------- | ------------------------------------------------------- | ------------------------ | -------- | | Sunrise | Yes | No | - | - | | Swisscom | Yes | No | No | No | | VTX | Yes | No | - | - | | Service provider | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | ---------------- | ---------------- | ------------------------------------------------------- | -------------------------- | -------- | | BT Internet | Yes | - | - | No | | Virgin Media | - | - | No | No | | ZEN Internet | Yes | - | Yes | Yes | | PlusNet | Yes | No | Yes, if you raise a ticket | Small one off Charge |
| Service provider | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | ---------------- | ---------------- | ------------------------------------------------------- | ------------------------ | ---------------- | | Telus | No. Extra charge | - | - | No. Extra charge | | TekSavvy | Yes | No | - | No. Extra charge | | Service provider | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | ----------------- | ------------------------------------- | ------------------------------------------------------- | ------------------------ | ---------------------------------- | | Cox | No. Only for business class customer. | No | No | Yes, as a business class customer | | Charter | No. Only for business class customer. | No | No | Yes, as a business class customer | | DSLExtreme | Yes | No | No | Yes, extra charge. | | AT&T | No. Only for business class customer. | unknown. | unknown. | unknown. | | Xfinity (Comcast) | No. Only for business class customer. | unknown. | unknown. | Yes, as a business class customer | | Service provider | Port 25 openable | [Hairpinning](http://en.wikipedia.org/wiki/Hairpinning) | Customizable reverse DNS | Fixed IP | | ---------------------- | ------------------- | ------------------------------------------------------- | ------------------------ | -------- | | Global Village Telecom | No. Only for Fix IP | No | No | Yes, extra charge. |
================================================ FILE: docs/admin/05.get_started/10.providers/15.vpn/index.mdx ================================================ --- title: VPN providers --- import {HighlightFFDN, HighlightNonProfit} from '@site/src/components/Highlight'; Since setting up a server at home is an uncommon practice, most Internet connections provided to individuals are unsuitable for this purpose especially if you desire to send mail. A net neutral VPN providing a dedicated fixed public IPv4 address and IPv6 addresses [can help to circumvent some limitations or difficulties](/admin/get_started/providers/vpn/vpn_advantage). :::info Note that except if you have a threat model that implies to really be "hidden", you do not need to hide your home IP address using a VPN. It is really not a huge deal to expose your IP address, do not trust the big commercial VPN companies who tries to sell you a product by inducing fear. If you *do* have such a threat model, especially against state threats, most of the providers listed below will **not** be of any help to you, since they will have to comply with police and judicial demands. However, a VPN can help you to bypass port-forwarding limitations, or to get a stable IP address (if you ISP only provide dynamic IP) and this page will help you for that! ::: Below, you can find a list of providers compatible for self-hosting and especially those providing .cube format for VPNClient apps and those providing [internetcube](https://internetcu.be). :::info By **compatible for self-hosting** we means VPN offers with at least: - a fixed dedicated public IPv4 - port forwarding or opened features - net neutrality: no traffic analysis, no user data resale, no alteration of traffic (without legal obligations)... ::: ## English-speaking sites | VPN provider | [VPNClient](https://github.com/labriqueinternet/vpnclient_ynh) compatibility | IPv6 | rDNS IPv4 | rDNS IPv6 | Price | Membership | Net Neutrality | | ------------ | ---------------------------------------------------------------------------- | ---- | --------- | --------- | ----- | ---------- | -------------- | | [Neutrinet](https://neutrinet.be/en/vpn) | ✔ (.cube + [internetcube](https://internetcu.be)) | ✔ | ✔ | ✔ | ~10€¹/month or 30€/year | included | | ¹ [Pay what you want](https://en.wikipedia.org/wiki/Pay_what_you_want) :::info If you try an other VPN provider that include **public dedicated ipv4 and port forwarding**, feel free to contribute to this documentation. We need people to test specific offers of those commercial providers: - ✘ [VPN area](https://vpnarea.com/front/home/dedicated-ip) does not allow forwarding port 80. Running a webserver is against their TOS. - [Trust zone](https://trust.zone/fr/order?p=25) - [PureVPN](https://www.purevpn.fr/ip-vpn-dedie) - [RapidVPN](https://www.rapidvpn.com/vpn) ::: ## French-speaking sites | VPN provider | [VPNClient](https://github.com/labriqueinternet/vpnclient_ynh) compatibility | IPv6 | rDNS IPv4 | rDNS IPv6 | Price | Membership | Net Neutrality | | ------------ | ---------------------------------------------------------------------------- | ---- | --------- | --------- | ----- | ---------- | -------------- | | [Aquilenet](https://www.aquilenet.fr/vpn/) | ✔ (.cube) | ✔ | ✔ | ✔ | 3 à 5 / mois | ~15€¹ /an | | | [Alsace Réseau Neutre](https://arn-fai.net/vpn) | ✔ (.cube + [internetcube](https://internetcu.be)) | ✔ | ✔ | ✔ | 4 € (ou [Ğ1](https://duniter.org/fr/monnaie-libre-g1/)) / mois | 15€ / an | | | [Baionet](https://www.baionet.fr/nos-services/vpn/) | ✘ (wireguard) | ? | ? | ? | 2,5 € ou 5 € / mois | 5€ ou 40€ / an | | | [FAImaison](https://www.faimaison.net/services/vpn.html) | ✔ (.cube) | ✘ | ✔ | ✘ | Prix libre | 8 ou 16€ / an | | | [French Data Network](https://www.fdn.fr/services/vpn/) | ✔ (.cube) | ✔ | ✔ | ✔ | 6,5€ à 23€ / mois | 15 ou 30€ / an | | | [Franciliens](https://www.franciliens.net/acces-internet/vpn/) | ✔ (.cube + [internetcube](https://internetcu.be)) | ✔ | ✔ | ✔ | 4€ à 23€ / mois | 15€ / an | | | [Grifon](https://grifon.fr/services/vpn/) | ✔ (manuelle) + L2TP/IPSec | ✔ | ✔ | ✔ | 5€ / mois | 15€ / an | | | [Igwan.net](https://igwan.net) | ✘ (L2TP/IPSec) | ? | ? | ? | 4 ou 8€ / mois | ? / an | | | [Illyse](https://www.illyse.net/acces-internet-par-vpn/) | ✔ (manuelle) | ✔ | ✔ | ✔ | 6 ou 8€ / mois | 20€ / an | | | [ILOTH](https://iloth.net/vpn/) | ✔ (.cube) | ✘ | ✔ | ✘ | 80€ / an | 5 à 100€ / an | | | [Milkywan](https://milkywan.fr/prices#popupTunnel) | ✔ (manuelle) | ✔ | ✔ | ✔ | 5 € / mois | incluse | | | [Mycélium](https://mycelium-fai.org/wiki/documentation/services/vpn) | ✔ (manuelle) | ✘ | ✘ | ✘ | Prix libre | incluse
Réservé aux nordistes(FR 59) | | | [Neutrinet](https://neutrinet.be/en/vpn) | ✔ (.cube + [internetcube](https://internetcu.be)) | ✔ | ✔ | ? | ~8 €¹ / mois | incluse | | | [Rézine](https://www.rezine.org/acces_internet/tunnels_chiffr%C3%A9s/) | ✔ (manuelle) | ✔ | ✔ | ✔ | 5 à 10€ / mois | Prix libre | | | [Swiss Neutral Network](https://www.swissneutral.net/?page_id=31) | ✔ (.cube) | ✔ | ✔ | ✔ | 30.- CHF/mois | 50.- CHF / an
Réservé aux suisses | | | [Tetaneutral](https://tetaneutral.net/adherer/) | ✘ (wireguard) | ? | ? | ? | 5€¹ / mois | 5 à 100€¹ / an | | | [Touraine Data Network](https://tdn-fai.net/) | ✔ (.cube + [internetcube](https://internetcu.be)) | ✔ | ? | ? | 5€ / mois | 10 à 20€ / an | | ¹ [Pay what you want](https://en.wikipedia.org/wiki/Pay_what_you_want) ## German-speaking sites | VPN provider | [VPNClient](https://github.com/labriqueinternet/vpnclient_ynh) compatibility | IPv6 | rDNS IPv4 | rDNS IPv6 | Price | Membership | Net Neutrality | | ------------ | ---------------------------------------------------------------------------- | ---- | --------- | --------- | ----- | ---------- | -------------- | | [In-Berlin](https://in-vpn.de/provider/vpn.html) | ✔ (manuelle) | ✔ | ✔ | ✔ | 9 or 14€ / month | 20€ / an | | | [Portunity](https://www.portunity.de/access/produkte/vpn-loesungen/vpn-tunnel.html) | ✔ (manuelle) | ✔ | ✔ | ✔ | from 6,80€ / month | | | | [FesteIP-Kit (Portunity)](https://www.festeip-kit.de/) | ✘ (managed ready-to-use router utilizing a Raspberry Pi) | ✔ | ✔ | ✔ | from 10,80€ / month | | | ================================================ FILE: docs/admin/05.get_started/10.providers/15.vpn/vpn_advantage.mdx ================================================ --- sidebar_label: Advantages title: Advantage of a VPN for self-hosting --- Since setting up a server at home is an uncommon practice, most Internet connections provided to individuals are unsuitable for this purpose. A net neutral VPN providing a static IPv4 address and IPv6 addresses can help to circumvent some limitations or difficulties. :::caution Not all existing [VPN providers](/admin/get_started/providers/vpn/) meet these conditions, make sure the one you choose meets them. ::: ## Advantages ### Plug & Play By setting up a VPN on your server, you'll be able to make it accessible to the rest of the Internet without having to change the configuration of the router you connect it to. This can be really handy if you are going on vacation, moving or have an Internet disconnection, as you will be able to easily connect it to someone you trust without having to configure the router of the person who is helping you. In the same way, you save yourself the trouble of opening your router's ports and bypassing hairpinning. ### No micro DNS outages If your Internet connection does not have a fixed public IP, you will be forced to set up a dynamic domain name (Dynamic DNS). This solution may be acceptable, but the DNS will only be updated at regular intervals (every two minutes if it is a `noho.st` or `nohost.me` domain name). So there is a chance that this will cause some display errors in the browser from time to time, or even that another site will be displayed (the risks are however reduced because the practice of self-hosting is not widespread). With a neutral VPN, this problem is circumvented because the VPN can be compared to a Virtual Internet connection, which has its own fixed IPv4 address, so no need to update the domain name. ### The case of email Email is one of the most complex protocols to self-host, usually it is what a user self-hosts last. Indeed, it is very easy to find yourself in a situation where emails sent by the server are refused by the recipient SMTP servers. To avoid this you need to: - configure the reverse DNS of the server's Internet connection (or VPN) - a fixed IPv4 - that this IPv4 is removable from all blacklists (notably the IP must not be on the DUL) - to be able to open port 25 (as well as the other SMTP ports) Unfortunately, none of the most common French ISPs respect all these points. To overcome this, the use of a VPN respecting these points can be an alternative. ### Trust Finally, if you do not want the content of your server's communications to be spied on by equipment present on your ISP's network, you can use a VPN to encrypt your communications and deport your trust to a VPN provider. Remember, since 2015, the government officially deploys black boxes at the large network operators whose objective is to tap all French digital communications to preserve the scientific, economic and industrial interests of France. ## Disadvantages ### Cost A neutral VPN has a cost since the operator who provides it must run a server and use bandwidth. The prices of the FFDN's associative VPNs are around 6 € per month. ### Packet path When you set up a VPN on your server, if you don't set up any particular configuration, the transfer of a file from a computer on the local network to the server using the VPN, will go through the end of the VPN i.e. through the server of the VPN provider. To solve this problem, there are two solutions: - transform the server into a router and connect the home equipments to it, these equipments will then benefit from the VPN confidentiality too. - use the YunoHost server as a DNS resolver when you are at home, in order to redirect the server's domain names to the local IP rather than the public IP. This operation can be done either on each equipment or on the router (if the latter allows it). ================================================ FILE: docs/admin/05.get_started/10.providers/20.servers.mdx ================================================ --- title: Server providers hide_table_of_contents: true description: " " --- import {HighlightFFDN, HighlightNonProfit, HighlightCHATONS} from '@site/src/components/Highlight'; ## Pre-installed YunoHost Offers * [Alsace Réseau Neutre](https://arn-fai.net) (VPS) * [ECOWAN](https://ecowan.fr) (VPS) * [Hosterfy](https://www.hosterfy.com/en/kvm-vps-hosting) (VPS) * [Scaleway Dedibox](https://www.scaleway.com/en/dedibox/operating-systems/) (dedicated server) * [Numericoop](https://numericoop.fr/solution-sur-mesure/) (VPS) ## YunoHost IT outsourcing * [ReflexLibre](https://reflexlibre.net) (France only) * [Numericoop](https://numericoop.fr/solution-sur-mesure/) (France only) * [Librezo](https://librezo.fr/) (France only) ================================================ FILE: docs/admin/05.get_started/10.providers/_category_.yaml ================================================ label: "Providers" link: type: "generated-index" title: "Providers" ================================================ FILE: docs/admin/05.get_started/20.install_on/_configuration.mdx ================================================ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## Proceed with the initial configuration :::info If you are in the process of restoring a server using a YunoHost backup, you should skip this step and instead [restore the backup instead of the postinstall step](/admin/backups). ::: :::info This documentation assumes you're on the same local network as your YunoHost installation. For a VPS, please use the public IP address instead of the local domain or address. ::: On a computer, open a browser and try to reach the webadmin: - if you're installing on a VPS, you probably used the `curl | bash` install method, and it should have pointed you with the address, typically `https://xx.xx.xx.xx` (with the **public IPv4** of your server) - if you're installing at home, and assuming that *you are on the same local network as the server* - you can try to open https://yunohost.local (this may or may not work depending if your computer and network supports the Bonjour protocol) - if you already know the local IP of the machine, go to `https://xx.xx.xx.xx` (with the **local** IP, typically starting with `192.168.`) - otherwise you will need to [find out its local IP ](/admin/get_started/post_install/find_ip) before continuing. :::warning During the first visit, you will very likely encounter a security warning related to the certificate used by the server. For now, your server uses a self-signed certificate. You will later be able to add a certificate automatically recognized by web browsers as described in the [certificate documentation](/admin/domains/certificate). For now, you should add a security exception to accept the current certificate. (Though, PLEASE, do not take the habit of blindly accepting this kind of security alert!) ::: You should then land on this page:
You can also perform the postinstallation with the command `yunohost tools postinstall` directly on the server, or [via SSH](/admin/command_line).
### Main domain
WSL specific configuration You will have to choose a fake domain, since it will not be accessible from outside. For example, `ynh.wsl`. The tricky part is advertising this domain to your host. Alter your `C:\Windows\System32\drivers\etc\hosts` file. You should have a line starting by `::1`, update it or add it if needed to get: ```text ::1 ynh.wsl localhost ``` If you want to create subdomains, do not forget to add them in the `hosts` file too: ```text ::1 ynh.wsl subdomain.ynh.wsl localhost ```
This will be the domain used by your server's users to access the **authentication portal**. You can later add other domains, and change which one is the main domain if needed. - If you're new to self-hosting and do not already have a domain name, we recommend using a **.nohost.me** / **.noho.st** / **.ynh.fr** (e.g. `homersimpson.nohost.me`). Provided that it's not already taken, the domain will be configured automatically and you won't need any further configuration step. Please note that the downside is that you won't have full-control over the DNS configuration. - If you already own a domain name, you probably want to use it here. You will later need to configure DNS records as explained [here](/admin/get_started/post_install/dns_config). :::tip Yes, you *have to* configure a domain name. If you don't have any domain name and don't want a **.nohost.me** / **.noho.st** / **.ynh.fr** either, you can set up a dummy domain such as `yolo.test` and tweak your **local** `/etc/hosts` file such that this dummy domain [points to the appropriate IP, as explained here](/admin/tutorials/domains/dns_local_network). ::: ### First user The first user is now created at this stage. You should pick a username and a reasonably complex password. (We cannot stress enough that the password should be **robust**!) This user will be added to the Admins group, and will therefore be able to access the user portal, the web admin interface, and connect [via **SSH**](/admin/command_line) or [**SFTP**](/admin/tutorials/filezilla). Admins will also receive emails sent to `root@yourdomain.tld` and `admin@yourdomain.tld`: these emails may be used to send technical information or alerts. You can later add additional users, which you can also add to the Admins group. This user replaces the old `admin` user, which some old documentation page may still refer to. In which case: just replace `admin` with your username. ## Run the initial diagnosis Once the postinstall is done, you should be able to actually log in the web admin interface using the credentials of the first user you just created. The diagnosis system is meant to provide an easy way to validate that all critical aspects of your server are properly configured - and guide you in how to fix issues. The diagnosis will run twice a day and send an alert by email if issues are detected. :::tip **Don't run away** ! The first time you run the diagnosis, it is quite expected to see a bunch of yellow/red alerts because you typically need to [configure DNS records](/admin/get_started/post_install/dns_config) (if not using a `.nohost.me`/`noho.st`/`ynh.fr` domain), as well as [port forwarding](/admin/get_started/post_install/port_forwarding) on your home's router. ::: :::tip If an alert is not relevant (for example because you don't intend on using a specific feature), it is perfectly fine to flag the issue as 'ignored' by going in the webadmin > Diagnosis, and clicking the ignore button for this specifc issue. ::: :::warning Especially, installations on WSL or virtual machines will likely not be reachable from outside without further network configuration on Virtualbox and your machine. ::: To run a diagnosis, go on Web Admin in the Diagnosis section. Click Run initial diagnosis and you should get a screen like this:
```bash yunohost diagnosis run yunohost diagnosis show --issues --human-readable ``` ## Get a Let's Encrypt certificate Once you configured DNS records and port forwarding (if needed), you should be able to install a Let's Encrypt certificate. This will get rid of the spooky security warning from earlier for new visitors. For more detailed instructions, or to lean more about SSL/TLS certificates, see [the corresponding page here](/admin/domains/certificate). Go in Domains > Click on your domain > Certificate
```bash yunohost domain cert install ``` ## 🎉 Congratz! You now have a pretty well configured server. If you're new to YunoHost, we recommend having a look at [the guided tour](/admin/webadmin). You should also be able to [install your favourite applications](https://apps.yunohost.org/). Don't forget to [plan backups](/admin/backups) ! ================================================ FILE: docs/admin/05.get_started/20.install_on/_install_script.mdx ================================================ ## Run the install script - Open a command line prompt on your server (either directly or [through SSH](/admin/command_line)) - Make sure you are root (or type `sudo -i` to become root) - Run the following command: ```bash curl https://install.yunohost.org | bash ``` :::danger Always make sure there's an `s` at the end of `https`. ::: :::warning You might need to first install `curl` and `ca-certificates` by running: ```bash apt install curl ca-certificates ``` ::: :::note **For advanced users concerned with the `curl | bash` approach:** consider reading ["Is curl|bash insecure?"](https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-pgp-verified-install) on Sandstom's blog, and possibly [this discussion on Hacker News](https://news.ycombinator.com/item?id=12766350&noprocess). ::: ================================================ FILE: docs/admin/05.get_started/20.install_on/arm_board.mdx ================================================ --- title: On an ARM board description: Looks like a Raspberry Pi, isn't quite one sidebar_position: 2 sidebar_custom_props: doc_card_image: /img/icons/icon-olinuxino.png pagination_next: admin/get_started/install_on/on_top_of_debian sidebar_class_name: hidden --- import InitialConfiguration from "./_configuration.mdx"; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import YunoHostImagesList from '@site/src/components/YunoHostImagesList'; import InstallScript from "./_install_script.mdx"; ## Pre-requisites - An ARM board with at least 512MB RAM - A power supply (either an adapter or a USB cable) for your board; - A microSD card: 16GB capacity (at least), [class "A1"](https://en.wikipedia.org/wiki/SD_card#Class) highly recommended (such as [this SanDisk A1 card](https://www.amazon.fr/SanDisk-microSDHC-Adaptateur-homologu%C3%A9e-Nouvelle/dp/B073JWXGNT/)); - A [reasonable ISP](/admin/get_started/providers/isp/), preferably with a good and unlimited upstream bandwidth - An ethernet cable (RJ-45) to connect your server to your router. - A computer to read this guide, flash the image and access your server. :::warning Each ARM board is different and there might be specific instructions for your board. Please follow the Armbian documentation first! ::: ## Download the Armbian image You should download the Armbian **Bookworm** (Debian 12) image from your vendor's or Armbian's website.
## Flash the Armbian image Now that you downloaded the image of Armbian, you should flash it on a microSD card Download Etcher for your operating system and install it. Plug your SD card, select your image and click "Flash" ![Etcher](/img/softwares/etcher.gif) Download [USBimager](https://bztsrc.gitlab.io/usbimager/) for your operating system and install it. Plug your SD card, select your image and click "Write" ![USBimager](/img/softwares/usbimager.png) If you are on GNU/Linux / macOS and know your way around command line, you may also flash your USB stick or SD card with `dd`. You can identify which device corresponds to your USB stick or SD card with `fdisk -l` or `lsblk`. A typical SD card name is something like `/dev/mmcblk0`. BE CAREFUL and make sure you got the right name. Then run: ```bash # Replace /dev/mmcblk0 if the name of your device is different... dd if=/path/to/armbian.img of=/dev/mmcblk0 status=progress ; sync ``` ## Power up the board - Insert the SD card in the board - Connect your board to your home router via Ethernet - For advanced users requiring WiFi instead, please follow [the official documentation](https://docs.armbian.com/User-Guide_Autoconfig/#sample-config-file). - If you want to follow the initial boot, connect a screen and keyboard on your board. - Power up the board ## Connect to the board Next you need to [find the local IP address of your server](/admin/get_started/post_install/find_ip) to connect as root user [via SSH](/admin/command_line) with the temporary password `1234` (see [the Armbian doc](https://docs.armbian.com/User-Guide_Getting-Started/#how-to-login)). ```bash ssh root@192.168.x.xxx ``` ================================================ FILE: docs/admin/05.get_started/20.install_on/index.mdx ================================================ --- title: Install on... slug: /admin/get_started/install_on sidebar_class_name: hidden_menu_caret bold hide_table_of_contents: true --- import DocCardList from '@theme/DocCardList'; import { useCurrentSidebarCategory } from '@docusaurus/theme-common'; Select the hardware on which you want install YunoHost: ================================================ FILE: docs/admin/05.get_started/20.install_on/on_top_of_debian.mdx ================================================ --- title: On top of Debian description: Typically on a VPS, or if you can't use preinstalled images sidebar_position: 6 sidebar_custom_props: doc_card_image: /img/icons/logo-debian.png pagination_next: admin/get_started/guidelines sidebar_class_name: hidden --- import InstallScript from "./_install_script.mdx"; import InitialConfiguration from "./_configuration.mdx"; YunoHost can be installed "on top" of Debian. This can be useful if you already have a Debian machine or can't use the recommended methods. Note that there is no actual difference in your resulting YunoHost installation between doing this and using the other methods involving pre-installed images: the pre-installed images are just convenient to skip a bunch of steps and having the system already shipped with everything needed. ## Get Debian You should download the version **Bookworm** (Debian 12) and select the architecture for your PC. When in doubt, select `amd64`, or `i386` for a pre-2010 PC.
Alternatively, you can browse the [Debian archive](https://cdimage.debian.org/mirror/cdimage/archive) for the latest 12.x version, select your architecture, the select `iso-cd` and download the `netinst` iso. ### Installation You might want to **wipe the hard drive** before starting the Debian installer. Flash the ISO your USB key, for example using [Etcher](https://www.balena.io/etcher/), [USBimager](https://bztsrc.gitlab.io/usbimager/) or `dd`. Debian installer will ask for a **hostname** and a **domain name**. You can use `yunohost` and `yunohost.local`. It is not that important since the YunoHost Installer will overwrite those anyway. Debian will ask for a **root password**, which should be reaonably complex as it is your primary defense to possible attacks. The installer will also ask for a **user account** and another password. :::warning **IMPORTANT:** this username should be DIFFERENT from the first YunoHost user which you will choose during YunoHost's posinstall… For example, you can name it `debian`. Be sure to also use a long complex password. ::: When the install asks where to install and how to **create disk partitions**, select the option to **use the whole disk**, unless you know what you're doing. - We recommend not to separate the `/home`, `/var` or `/tmp` partitions. Use the option to "keep all files in one partition". - If you don't know what you're doing, don't encrypt the disk (Decryption at power-on will be an issue) The installer will ask about **mirrors**. Select a country and server close to your location, or use the default options. The installer will ask which **desktop environment** you want. This is generally useless and might waste resources. - Unselect all desktop environment - Keep "standard system utilities" checked ### After installing Debian 1. Remove the installation media (unplug the USB stick) 2. Reboot 3. Login as `root` 4. Install curl by typing `apt install curl` ================================================ FILE: docs/admin/05.get_started/20.install_on/raspberry_pi.mdx ================================================ --- title: On a Raspberry Pi description: One of the most popular baked boards sidebar_position: 1 sidebar_custom_props: doc_card_image: /img/icons/icon-raspberrypi.png pagination_next: admin/get_started/guidelines sidebar_class_name: hidden --- import InitialConfiguration from "./_configuration.mdx"; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import YunoHostImagesList from '@site/src/components/YunoHostImagesList'; ## Pre-requisites - A Raspberry Pi 3, 4 or 5 - A power supply (either an adapter or a USB cable) for your board; - A microSD card: 16GB capacity (at least), [class "A1"](https://en.wikipedia.org/wiki/SD_card#Class) highly recommended (such as [this SanDisk A1 card](https://www.amazon.fr/SanDisk-microSDHC-Adaptateur-homologu%C3%A9e-Nouvelle/dp/B073JWXGNT/)); - An ethernet cable (RJ-45) to connect your server to your router. - A [reasonable ISP](/admin/get_started/providers/isp/), preferably with a good and unlimited upstream bandwidth - A computer to read this guide, flash the image and access your server. :::warning Support for Raspberry Pi 2 was dropped. If you really want to install YunoHost on a Pi 2, download and install "Raspberry Pi OS (32-bit)" from [the official website](https://www.raspberrypi.com/software/operating-systems/) and then [follow the instructions](./on_top_of_debian) to install YunoHost on Debian. ::: ## Download the YunoHost image :::note (FIXME: this bit is currently broken...) Optionally, you can [download the project's public key](https://forge.yunohost.org/keys/yunohost_bookworm.asc) to check the authenticity of the images. ::: ## Flash the YunoHost image Now that you downloaded the image of YunoHost, you should flash it on a microSD card Download Etcher for your operating system and install it. Plug your SD card, select your image and click "Flash" ![Etcher](/img/softwares/etcher.gif) Download [USBimager](https://bztsrc.gitlab.io/usbimager/) for your operating system and install it. Plug your SD card, select your image and click "Write" ![USBimager](/img/softwares/usbimager.png) If you are on GNU/Linux / macOS and know your way around command line, you may also flash your USB stick or SD card with `dd`. You can identify which device corresponds to your USB stick or SD card with `fdisk -l` or `lsblk`. A typical SD card name is something like `/dev/mmcblk0`. BE CAREFUL and make sure you got the right name. Then run: ```bash # Replace /dev/mmcblk0 if the name of your device is different... dd if=/path/to/yunohost.img of=/dev/mmcblk0 status=progress ; sync ``` ## Power up the board - Insert the SD card in the board - Connect your board to your home router via Ethernet - For advanced users requiring WiFi instead, please follow [the official documentation](https://www.raspberrypi.com/documentation/computers/configuration.html#connect-to-a-wireless-network). - If you want to follow the initial boot, connect a screen and keyboard on your board. - Power up the board ================================================ FILE: docs/admin/05.get_started/20.install_on/regular_computer.mdx ================================================ --- title: On a regular computer description: An old desktop computer or laptop, or any x86 machine sidebar_position: 4 sidebar_custom_props: doc_card_image: /img/icons/icon-computer.png pagination_next: admin/get_started/guidelines sidebar_class_name: hidden --- import InitialConfiguration from "./_configuration.mdx"; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import YunoHostImagesList from '@site/src/components/YunoHostImagesList'; ## Pre-requisites - A x86-compatible hardware dedicated to YunoHost with at least 512MB of RAM and 16GB of disk - this may be an old laptop, desktop computer, or a proper server machine - A 1GB+ USB key - A [reasonable ISP](/admin/get_started/providers/isp/), preferably with good and unlimited upstream bandwidth - An ethernet cable (RJ-45) to connect your server to your router. - A computer to read this guide, flash the image and access your server. ## Download the YunoHost image :::warning If your machine is 32 bits, be sure to download the 32-bit image. ::: :::info (FIXME: this bit is currently broken...) Optionally, you can [download the project's public key](https://forge.yunohost.org/keys/yunohost_bookworm.asc) to check the authenticity of the images. ::: ## Flash the YunoHost image Flash the image on the USB key or CD/DVD. Download Etcher for your operating system and install it. Plug your USB key, select your image and click "Flash" ![Etcher](/img/softwares/etcher.gif) Download [USBimager](https://bztsrc.gitlab.io/usbimager/) for your operating system and install it. Plug your USB key, select your image and click "Write" ![USBimager](/img/softwares/usbimager.png) If you are on GNU/Linux / macOS and know your way around command line, you may also flash your USB stick or SD card with `dd`. You can identify which device corresponds to your USB stick or SD card with `fdisk -l` or `lsblk`. A typical SD card name is something like `/dev/mmcblk0`. BE CAREFUL and make sure you got the right name. Then run: ```bash # Replace /dev/mmcblk0 if the name of your device is different... dd if=/path/to/armbian.img of=/dev/mmcblk0 status=progress ; sync ``` Ventoy will be useful if you can't sucessfully boot the YunoHost image using the other methods. [Ventoy](https://www.ventoy.net/) is a nice tool that makes it really easy to put multiple linux images on a USB stick. When the computer refuses to boot from an image on a USB stick, Ventoy will usually be able to boot it anyway! 1. Install [Ventoy](https://www.ventoy.net/) on the USB stick. Refer to the [install instructions](https://www.ventoy.net/en/doc_start.html). - This will create 2 partitions on the stick. 2. Using your favorite file explorer app, copy the YunoHost image file on the big `Ventoy` partition (not "VTOYEFI") - Don't use *Balena Etcher*, USBImager or `dd` for this! Later, when you'll boot the computer using this USB stick, Ventoy will appear and will list the images on the USB stick. Select the YunoHost image, then select GRUB2 launch option (or use whichever works for your computer 😉) ## Boot the machine on your USB stick - Connect your computer to your home router via Ethernet - Boot up your server with the USB stick or a CD-ROM inserted, and select it as **bootable device**. - Depending on your hardware, you will need to press one of the following keys: ``, ``, ``, ``, ``, `` or ``. - N.B. : if the server was previously installed with a recent version of Windows (8+), you first need to tell Windows, to "actually reboot". This can be done somewhere in "Advanced startup options". :::tip If you can't boot the YunoHost image, try using Ventoy (select "Ventoy" in the section "Flash the YunoHost image" above). ::: ## Launch the graphical install You should see a screen like this:
:::danger Once you have validated the keyboard layout, the installation will be launched and will completely erase the data on your hard disk! ::: 1. Select `Graphical install` 2. Select your language, your location, your keyboard layout, and eventually your timezone. 3. The installer will then download and install all required packages. The YunoHost project simplified the classic installation as much as possible in order to avoid as many people as possible being lost with questions that are too technical or related to specific cases. With the expert mode installation, you have more possibilities, especially concerning the exact partitioning of your storage media. You can also decide to use the classic mode and [add your disks afterwards](/admin/tutorials/external_storage). ### Summary of the steps in expert mode 1. Select `Expert graphical install`. 2. Select your language, location, keyboard layout and possibly your timezone. 3. Partition your disks. This is where you can set up a RAID or encrypt all or part of the server. 4. Specify a possible HTTP proxy to use for the installation of the packages 5. Specify on which volumes grub should be installed ### Regarding partitioning In general, we recommend against partitioning `/var`, `/opt`, `/usr`, `/bin`, `/etc`, `/lib`, `/tmp` and `/root` on separate partitions. This will prevent you from having to worry about full partitions that could crash your machine, cause app installations to fail, or even corrupt your databases. For performance reasons, it is recommended to mount your fastest storage (SSD) on the root `/`. If you have one or more hard drives to store data, you can choose to mount it on one of these folders depending on your usage. | Path | Contents | | -------------------------------- | -------- | | `/home` | User folders accessible via SFTP | | `/home/yunohost.backup/archives` | YunoHost backups to be placed ideally elsewhere than on the disks that manage the data | | `/home/yunohost.app` | Heavy data from YunoHost applications (nextcloud, matrix...) | | `/home/yunohost.multimedia` | Heavy data shared between several applications | | `/var/mail` | User mail | If you want flexibility and don't want to (re)size partitions, you can also choose to mount on `/mnt/hdd` and follow this [tutorial to mount all these folders with `mount --bind`](/admin/tutorials/external_storage). ### About encryption Be aware that if you encrypt all or part of your disks, you will have to type the passphrase every time you restart your server, which can be a problem if you are not on site. There are however solutions (quite difficult to implement) that allow you to type the passphrase via SSH or via a web page (search for "dropbear encrypted disk"). ### About RAID Keep in mind that: - the disks in your RAIDs must be of different brands, wear and tear or batches (especially if they are SSDs) - a RAID 1 (even without a spare) is more reliable than a RAID 5 from a probability point of view - hardware raids are dependent on the raid card, if the card fails you will need a replacement to read and rebuild the array :::info If the YunoHost installer fails and you can't solve the issue, know that it's also possible to install Debian and then install YunoHost on top. See [the specific instructions](/admin/get_started/install_on/on_top_of_debian). ::: ================================================ FILE: docs/admin/05.get_started/20.install_on/remote_server.mdx ================================================ --- title: On a remote server description: "Cloud machines: VPS or dedicated servers" sidebar_position: 3 sidebar_custom_props: doc_card_image: /img/icons/icon-vps.png pagination_next: admin/get_started/install_on/on_top_of_debian sidebar_class_name: hidden --- import InstallScript from "./_install_script.mdx"; import InitialConfiguration from "./_configuration.mdx"; ## Pre-requisites - A dedicated or virtual private server with Debian 12 (Bookworm) (with **kernel >= 6.1**) preinstalled, 512MB RAM and 16GB capacity (at least) - A computer or a smartphone to read this guide and access your server. ## Connect to the server You will need to connect to your server via `ssh`. ================================================ FILE: docs/admin/05.get_started/20.install_on/virtualbox.mdx ================================================ --- title: In a virtual machine description: For testing and debugging purposes sidebar_position: 5 sidebar_custom_props: doc_card_image: /img/icons/icon-virtualbox.png pagination_next: admin/get_started/guidelines sidebar_class_name: hidden --- import InitialConfiguration from "./_configuration.mdx"; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import YunoHostImagesList from '@site/src/components/YunoHostImagesList'; :::warning Installing YunoHost in a VirtualBox is usually intended for testing or development. It is not convenient to run an actual server on the long-term, because the machine it's installed on probably won't be up 24/7, and because Virtualbox adds an additional layer of complexity in exposing the machine to the Internet. ::: ## Pre-requisites - An x86 computer with [VirtualBox installed](https://www.virtualbox.org/wiki/Downloads) and enough RAM capacity to be able to run a small virtual machine with 1024MB RAM and 8GB capacity (at least) ## Download the YunoHost image :::warning If your host OS is 32 bits, be sure to download the 32-bit image. ::: :::note (FIXME: this bit is currently broken...) Optionally, you can [download the project's public key](https://forge.yunohost.org/keys/yunohost_bookworm.asc) to check the authenticity of the images. ::: ## Create a new virtual machine ![](/img/softwares/virtualbox_1.png) :::warning It's okay if you can only have 32-bit versions, just be sure that you downloaded the 32-bit image previously. ::: ## Tweak network settings :::warning This step is important to properly expose the virtual machine on the network ::: Go to **Settings** > **Network**: - Select `Bridged adapter` - Select your interface's name: **wlan0** if you are connected wirelessly, or **eth0** otherwise. ![](/img/softwares/virtualbox_2.png) ## Boot up the virtual machine Start the virtual machine after selecting the YunoHost image. ![](/img/softwares/virtualbox_2.1.png) :::warning If you encounter the error "VT-x is not available", you probably need to enable Virtualization in the BIOS of your computer. ::: ## Launch the graphical install You should see a screen like this:
:::danger Once you have validated the keyboard layout, the installation will be launched and will completely erase the data on your hard disk! ::: 1. Select `Graphical install` 2. Select your language, your location, your keyboard layout, and eventually your timezone. 3. The installer will then download and install all required packages. The YunoHost project simplified the classic installation as much as possible in order to avoid as many people as possible being lost with questions that are too technical or related to specific cases. With the expert mode installation, you have more possibilities, especially concerning the exact partitioning of your storage media. You can also decide to use the classic mode and [add your disks afterwards](/admin/tutorials/external_storage). ### Summary of the steps in expert mode 1. Select `Expert graphical install`. 2. Select your language, location, keyboard layout and possibly your timezone. 3. Partition your disks. This is where you can set up a RAID or encrypt all or part of the server. 4. Specify a possible HTTP proxy to use for the installation of the packages 5. Specify on which volumes grub should be installed ### Regarding partitioning In general, we recommend against partitioning `/var`, `/opt`, `/usr`, `/bin`, `/etc`, `/lib`, `/tmp` and `/root` on separate partitions. This will prevent you from having to worry about full partitions that could crash your machine, cause app installations to fail, or even corrupt your databases. For performance reasons, it is recommended to mount your fastest storage (SSD) on the root `/`. If you have one or more hard drives to store data, you can choose to mount it on one of these folders depending on your usage. | Path | Contents | |--------|---| | `/home` | User folders accessible via SFTP | | `/home/yunohost.backup/archives` | YunoHost backups to be placed ideally elsewhere than on the disks that manage the data | | `/home/yunohost.app` | Heavy data from YunoHost applications (nextcloud, matrix...) | | `/home/yunohost.multimedia` | Heavy data shared between several applications | | `/var/mail` | User mail | If you want flexibility and don't want to (re)size partitions, you can also choose to mount on `/mnt/hdd` and follow this [tutorial to mount all these folders with `mount --bind`](/admin/tutorials/external_storage). ### About encryption Be aware that if you encrypt all or part of your disks, you will have to type the passphrase every time you restart your server, which can be a problem if you are not on site. There are however solutions (quite difficult to implement) that allow you to type the passphrase via SSH or via a web page (search for "dropbear encrypted disk"). ### About RAID Keep in mind that: - the disks in your RAIDs must be of different brands, wear and tear or batches (especially if they are SSDs) - a RAID 1 (even without a spare) is more reliable than a RAID 5 from a probability point of view - hardware raids are dependent on the raid card, if the card fails you will need a replacement to read and rebuild the array :::tip If the YunoHost installer fails and you can't solve the issue, know that it's also possible to install Debian and then install YunoHost on top. See [these instructions](/admin/get_started/install_on/on_top_of_debian). ::: ================================================ FILE: docs/admin/05.get_started/20.install_on/wsl.mdx ================================================ --- title: On WSL description: Experimental, for people who like cyberfrankensteins sidebar_position: 8 sidebar_custom_props: doc_card_image: /img/icons/logo-wsl.png pagination_next: admin/get_started/guidelines sidebar_class_name: hidden --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import InstallScript from "./_install_script.mdx"; import InitialConfiguration from "./_configuration.mdx"; :::danger This setup is mainly meant for local testing by advanced users. Due to limitations on WSL's side (changing IP address, notably), selfhosting from it can be tricky and will not be described here. ::: ## Pre-requisites - Windows 10 and above - Administration rights - Windows Subsystem for Linux, installed from the Optional Features menu of Windows - *Recommended:* Windows Terminal (Preview) app, installed from the Microsoft Store. Much better than the standard Terminal, as it offers shortcuts to the WSL distros. ## Introduction WSL is a nice feature of Windows 10, making Linux pseudo-distributions available through command line. Let's say pseudo, because even though they are not really like virtual machines, they rely on virtualization capacities that make their integration with Windows almost seamless. Docker for Windows can now rely on WSL instead of Hyper-V, for example. :::warning Bear in mind, this setup itself is *not* a container of any kind. If something breaks, there is no rollback capability. You may need to delete the Debian distro altogether and restore it whole. ::: ## Install Debian Let's install YunoHost into its own distro, not altering the default one. In a PowerShell terminal: ```bash # Let's go in your home directory and prepare the working directories cd ~ mkdir -p WSL\YunoHost # Download the Debian appx package and unzip it curl.exe -L -o debian.zip https://aka.ms/wsl-debian-gnulinux Expand-Archive .\debian.zip -DestinationPath .\debian # Import the Debian base into a new distro wsl --import YunoHost ~\WSL\YunoHost ~\debian\install.tar.gz --version 2 # Cleanup rmdir .\debian -R ``` You can now access it: run `wsl.exe -d YunoHost` It is under Debian 9 Stretch, so let's upgrade it: ```bash # In WSL sudo sed -i 's/stretch/bookworm/g' /etc/apt/sources.list` sudo apt update sudo apt upgrade # optional sudo apt full-upgrade # wget needed for later setup sudo apt install wget -y ``` ## Prevent WSL from tweaking configuration files Edit `/etc/wsl.conf` and put the following code in it: ```text [network] generateHosts = false generateResolvConf = false ``` ## Force the use of iptables-legacy :::warning[FIXME] YunoHost now uses nftables, these instructions might be out of date. ::: Somehow the YunoHost post-installation does not like `nf_tables`, the new software replacing `iptables`. We can still explicitely use the good ol' `iptables` though: ```bash # In WSL sudo update-alternatives --set iptables /usr/sbin/iptables-legacy sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy ``` ## Install Systemd Debian on WSL does not have `systemd`, a service configuration software. This is a key element for YunoHost, and for any decent Debian distro (seriously MS, what the heck). Let's install it: 1. Install dotNET runtime: ```bash # In WSL wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb sudo apt update sudo apt install -y apt-transport-https sudo apt update sudo apt install -y dotnet-sdk-3.1 ``` 2. Install [Genie](https://github.com/arkane-systems/genie): ```bash # In WSL # Add their repository echo "deb [trusted=yes] https://wsl-translinux.arkane-systems.net/apt/ /" > /etc/apt/sources.list.d/wsl-translinux.list # Install Genie sudo apt update sudo apt install -y systemd-genie ``` ## Install YunoHost ```bash # In WSL # Let's switch to the root user, if you were not already sudo su # Initialize the Genie bottle to have systemd running genie -s # Your hostname should have been appended with "-wsl" ``` ### Access the command line Always call `genie -s` while starting your distro. ```bash wsl -d YunoHost -e genie -s ``` ## Backup and restore the distro ### Make your first distro backup As said before, there is no rollback capability. So let's export your fresh distro. In PowerShell: ```bash cd ~ wsl --export YunoHost .\WSL\YunoHost.tar.gz ``` ### In case of crash, delete and restore the whole distro ```bash cd ~ wsl --unregister YunoHost wsl --import YunoHost .\WSL\YunoHost .\WSL\YunoHost.tar.gz --version 2 ``` ================================================ FILE: docs/admin/05.get_started/40.post_install/10.find_ip.mdx ================================================ --- title: Find your server's local IP hide_table_of_contents: true --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; On an installation at home, your server should typically be accessible using the `yunohost.local` domain. If for any reason this does not work, you may need to find the *local* IP of your server. ## What is a local IP? The local IP is the address used to refer to your server inside the local network (typically your home) where multiple devices are connected to a router (your internet box). The local IP typically looks like `192.168.x.y` (or sometimes `10.0.x.y` or `172.16.x.y`) ## How to find it? Any of these tricks should allow you to find the local IP of your server: You can use the [AngryIP](https://angryip.org/download/) software to achieve that. You can scan these local IP ranges in this order until you find the active IP corresponding to your server: ``` 192.168.0.0 -> 192.168.0.255 192.168.1.0 -> 192.168.1.255 192.168.2.0 -> 192.168.255.255 10.0.0.0 -> 10.0.255.255 172.16.0.0 -> 172.31.255.255 ``` ![](/img/angryip.png) :::tip - you can order by ping like on this screenshot to easily see effectively-used IP. - your server should typically be displayed as listening on port 80 and 443 - when in doubt, just type `https://192.168.x.y` in your browser to check if it's a YunoHost or not. ::: Connect to your internet box / router interface to list the machines connected. If you're using Linux, you can open a terminal and use `sudo arp-scan --local` to list the IP on your local network (this may also work in Windows); If the `arp-scan` command displays a confusing number of devices, you can check which ones are open to SSH with `nmap -p 22 192.168.1.0/24` to sort them out (adapt the IP range to your local network) Plug a screen on your server, log in and type `hostname --all-ip-address`. The default credentials (before post-installation!) to log in are: - login: `root` - password: `yunohost` (If you are using a raw Armbian image instead of the pre-installed YunoHost image, the credentials are root / 1234) ## I still can't find my local IP If you are unable to find your server using any of the previous tricks, maybe your server did not boot correctly: - Make sure that your server is properly plugged in; - If you're using an SD card, make sure the connector is not too dusty; - Plug a screen on your server and try to reboot to check that it's properly booting; - Make sure that your ethernet cable is working and properly plugged in; ================================================ FILE: docs/admin/05.get_started/40.post_install/15.port_forwarding.mdx ================================================ --- title: Configure port-forwarding description: "Make your server accessible from outside your home" --- If you are self-hosting at home and without a VPN, you will probably want to forward ports on your home router ("Internet box") if you want your server to be reachable from outside your local network. The sketch below tries to briefly summarize the role and necessity of port forwarding when setting up a server at home.
### 0. Diagnose ports opened The diagnosis tool can be used to verify that all necessary ports are exposed to the Internet. ### 1. Access your box/router administration interface Your box/router admin interface is usually reachable via [http://192.168.0.1](http://192.168.0.1) or [http://192.168.1.1](http://192.168.1.1). Then, you will probably need to authenticate yourself the credentials given by your internet server provider. ### 2. Find the local IP of your server Identify the *local* IP of your server using one of the method listed [on the corresponding page](/admin/get_started/post_install/find_ip). A local IP address typically looks like `192.168.xx.yy`, or `10.0.xx.yy`. The local IP address needs to be static, so that the port forwards that you are going to configure in the next step will always reach your server. You should go into your box/router and make sure that the local IP address of your server is static instead of dynamic. ### 3. Forwarding ports In your router admin interface, look for something like "router configuration" or "port forwarding". The naming differs among the various kinds of router models. Opening the ports listed below is necessary for the various services available in YunoHost to work. For each of them, the 'TCP' forwarding is needed. Some interfaces refer to 'external' and 'internal' ports: these are the same in our case. - Web: `80` (HTTP), `443` (HTTPS) - [SSH](/admin/command_line): `22` - [Email](/admin/email): `25`, `587` (SMTP), `993` (IMAP) If you use both a modem and a router, then you need to do the following: 1. first on the modem (the box closest to the internet) create rules to forward the above ports to your router; 2. then on the router (the box between the modem and your devices) create rules to forward the above ports to the static IP address for your server. :::warning Many internet service providers (ISPs) block outgoing traffic on port 25 by default, to fight spam. Port 25 is however necessary if you want your server to be able to send email. In other extreme cases, some ISPs may not even allow you to use port 80/443 (web) freely... Depending on the ISP, it might be possible to open them in the admin interface... Check [this page](/admin/get_started/providers/isp/) for more info. ::: ================================================ FILE: docs/admin/05.get_started/40.post_install/20.dns_config.mdx ================================================ --- title: DNS zone configuration --- DNS (domain name system) is a system that converts human-readable addresses (domain names) into machine-understandable addresses (IP). For your server to be easily accessible by human beings, and for some services like mail to work properly, DNS must be configured. If you're using an [automatic domain](/admin/tutorials/domains/dns_nohost_me) provided by the YunoHost Project, the configuration should be performed automatically. If you're using your own domain name (e.g. bought via a registrar), you should manually configure your domain on your registrar's interface. ## Recommended DNS configuration NB: Examples here use the placeholder `your.domain.tld`, you have to replace it with your real domain, such as `www.yunohost.org`. YunoHost provides a recommended DNS configuration, available via: - the webadmin, in Domain > your.domain.tld > DNS configuration; - or the command line, `yunohost domain dns suggest your.domain.tld` For specific needs or specific setups, and if you know what you're doing, you might want or have to tweak these, or add additional ones (e.g. to handle subdomains). The recommended configuration typically looks like this: ```bash # # Basic ipv4/ipv6 records # @ 3600 IN A 111.222.33.44 * 3600 IN A 111.222.33.44 # (If your server is IPv6 capable, there are some AAAA records) @ 3600 IN AAAA 2222:444:8888:3333:bbbb:5555:3333:1111 * 3600 IN AAAA 2222:444:8888:3333:bbbb:5555:3333:1111 # # Mail (MX, SPF, DKIM and DMARC) # @ 3600 IN MX 10 your.domain.tld. @ 3600 IN TXT "v=spf1 a mx -all" mail._domainkey 3600 IN TXT "v=DKIM1; k=rsa; p=someHuuuuuuugeKey" _dmarc 3600 IN TXT "v=DMARC1; p=none" ``` Though it might be easier to understand it if displayed like this: | Type | Name | Value | | :-----: | :--------------------: | :--------------------------------------------------: | | **A** | **@** | `111.222.333.444` (your IPv4) | | A | * | `111.222.333.444` (your IPv4) | | AAAA | @ | `2222:444:8888:3333:bbbb:5555:3333:1111` (your IPv6) | | AAAA | * | `2222:444:8888:3333:bbbb:5555:3333:1111` (your IPv6) | | **MX** | **@** | `your.domain.tld.` (and priority: 10) | | TXT | @ | `"v=spf1 a mx -all"` | | TXT | mail._domainkey | `"v=DKIM1; k=rsa; p=someHuuuuuuugeKey"` | | TXT | _dmarc | `"v=DMARC1; p=none"` | ### A few notes about this table - Not all these lines are absolutely necessary. For a minimal setup, you only need the records in bold. - The dot at the end of `your.domain.tld.` is important ;); - `@` corresponds to `your.domain.tld`, and e.g. `muc` corresponds to `muc.your.domain.tld`; - These are example values ! See your generated conf for the actual values you should use; - We recommend a [TTL](https://en.wikipedia.org/wiki/Time_to_live#DNS_records) of 3600 (1 hour). But you can use something else if you know what you're doing; - Don't put an IPv6 record if you're not sure IPv6 really works on your server! You might have issues with Let's Encrypt if it doesn't. - If you're using the domain provider Namecheap the SRV DNS entries are formatted as **Service**: `_xmpp-client` **Protocol**: `_tcp` **Priority**: `0` **Weight**: `5` **Port**: `5222` **Target**: `your.domain.tld` ## Reverse DNS If your ISP or VPS provider let you define a [Reverse DNS lookup](https://en.wikipedia.org/wiki/Reverse_DNS_lookup) for your public IPv4 and/or IPv6 addresses, you must configure it. It will prevent you to be marked as spam by anti-spam filters. **N.B.: the reverse DNS configuration happens on your Internet Service Provider or VPS provider. It is *not* handled by your domain's registrar.** If your public IPv4 address is `111.222.333.444` and your DNS domain is `domain.tld`, you should get following answer when using `nslookup` command tool: ```bash nslookup 111.222.333.444 444.333.222.111.in-addr.arpa name = domain.tld. ``` The diagnosis system available in the webadmin performs this checks automatically (in section Email). ## Dynamic IP If your global IP address is constantly changing, follow this [tutorial](/admin/tutorials/domains/dns_dynamicip). ================================================ FILE: docs/admin/05.get_started/40.post_install/_category_.yaml ================================================ label: After installation link: type: generated-index description: Configure your network to access your server ================================================ FILE: docs/admin/05.get_started/90.guidelines.mdx ================================================ --- title: Advices and guidelines --- This page lists some advice and guidelines which every YunoHost administrator should be aware to take care of a YunoHost server :) ## Do not break YunoHost To put it another way: your server is either a production server (meant to work) or a test server on which you allow yourself to experiment. If your goal is to run a production server: - be aware that servers are fragile system. Stay cautious, methodical and patient; - limit experimentations and customizations (for instance of config file); - do not install dozens of apps just to see how they look; - use non-official apps with caution, and do not use apps that are still 'in progress', 'not working' or level 0; - if something gets broken, think twice about fixing it by yourself if you don't know what you are doing. (For instance, do not attempt to recreate yourself the admin user just because it mysteriously disappeared...) ## Keep it simple! YunoHost is designed to work with general and simple use cases in mind. Deviating from those conditions will make things harder and you will need technical knowledge to make it work. For instance: - do not try to run YunoHost in a context where you cannot have control over ports 80 and 443 (or no internet at all); - do not try to host five servers behind the same internet connection if you are not already an advanced user; - do not fall into nerd whims such as willing to replace NGINX with Apache (or run both at the same time); - do not try to use custom SSL certificates if you don't really need them; - ... Keep things as simple as you can! ## Do not reinstall every day Some people tend to fall into "the reinstallation spiral" - where each time something breaks in the server and it is not obvious how to fix it, or because the server became "dirty", one ends up reinstalling the whole server from scratch because it looks like an "easy" and quick solution to clean the table. Please don't do this. Reinstalling is a heavy operation and is not a good long-term strategy for fixing problems. You will get tired and won't learn anything. Forget the dream of having a "clean" server. A real-life server always end up being a bit "dirty". Also, you need to (progressively) learn how to solve issues when you encounter them. Reach for [help](/community/help) with detailed symptoms of what you are trying to do and what is happening, and fix the issues. Over time, you will get a much better control over your server than just blindly reinstalling every time. ## Do backups If you host services and data that are important for your users, it is important that you setup a backup policy. Backups can be easily created from the webadmin - you can download it from the webadmin or via your favorite FTP client, such as FileZilla or your own terminal. You should perform backup regularly and keep them in a safe and different physical location from your server. More info on [the backup documentation](/admin/backups). ## Check root’s email As an administrator, you should configure an email client to check emails sent to `root@your.domain.tld` (which should be an alias to the first user your added) or otherwise forward them to another address that you actively check. Those mails may contain information on what is happening on your server such as automated periodic tasks. ## YunoHost is free software, maintained by volunteers Finally, keep in mind that YunoHost is a free software maintained by volunteers - and that the goal of YunoHost (to democratize self-hosting) is not an easy one! It is provided without any warranty. The team of volunteers does its best to maintain and provide the best possible experience - yet features, applications and YunoHost as a whole are far from being perfect and you will experience small and big shortcomings at some points. When this happens, kindly [reach for help on the chat or forum, or report the issue](/community/help)! :) If you like YunoHost and want to see the project being kept alive and make progress, feel free to leave a thank you note and to [donate](https://yunohost.org/donate.html) to the project and talk about it around you! Last but not least, since YunoHost is a free software project, you are legitimate and welcomed to come and [contribute](/dev/) to the project, be it on the technical aspects (i.e. code) and less-technical aspects (such as contributing to this documentation! ;)) ================================================ FILE: docs/admin/05.get_started/_category_.yaml ================================================ label: "🚀 Get started" link: type: "generated-index" title: "🚀 Get started" ================================================ FILE: docs/admin/12.webadmin.mdx ================================================ --- title: ⭐ Webadmin interface hide_table_of_contents: true --- YunoHost has an administrator web interface. The other way to administrate your YunoHost install is through the [command line](/admin/command_line). The webadmin can be accessed at `https://yourdomain.tld/yunohost/admin` or using the local IP or global IP of your server (`https://1.2.3.4/yunohost/admin`)
================================================ FILE: docs/admin/15.command_line.mdx ================================================ --- title: 🛠️ SSH and command line --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## What's SSH? **SSH** stands for Secure Shell, and refers to a protocol that allows you to remotely control and administer a machine using the command line interface (CLI). It is available by default in any terminal on GNU/Linux and macOS. On Windows, you may want to use [MobaXterm](https://mobaxterm.mobatek.net/download-home-edition.html) (after launching it, click on Session then SSH). The command line interface (CLI) is, in the computer world, the original (and more technical) way of interacting with a computer compared to graphical interface. Command line interfaces are generally said to be more complete, powerful or efficient than a graphical interface, though also more difficult to learn. ## How to connect ### Credentials *before* running the postinstall - If you are **installing at home**, the default credentials are login: `root` and password: `yunohost` (or `1234` if you flashed an armbian image) - If you are **installing a remote server (VPS)**, your provider should have communicated the login and password to you (or allowed you to configure an SSH key) ### Credentials *after* running the postinstall During the postinstall, you've been asked to choose a user and an administration password. This user account allows you to connect to the server through SSH. The password also becomes the new password for the `root` user. Additionally, **the `root` SSH login becomes disabled after the postinstall and you should log in using the user account created during postinstall !**. The only exception is that you may still be able to login using `root` *from the local network - or from a direct console on the server* (this is to cover the event where the LDAP server is broken and the users who are members of the `admins` group are unusable). :::tip If you connected with the administration account and would like to become `root` for convenience (e.g. to avoid typing `sudo` in front of every command), you can become `root` using the command `sudo su` or `sudo -i`. ::: ### Address to use If you are **installing at home** (e.g. on a Raspberry Pi or OLinuXino or old computer): - you should be able to connect to your server using `yunohost.local` (or `yunohost-2.local`, depending on how many servers are on your network). - if `yunohost.local` and the like do not work, your need to [find out the local IP of the server](/admin/get_started/post_install/find_ip). - if you installed a server at home but are attempting to connect from outside your local network, make sure port 22 is correctly forwarded to your server. If your server is a remote server (VPS), your provider should have provided you with the IP address of the machine In any cases, if you already configured a domain name pointing to the appropriate IP, it's much better to use `your.domain.tld` instead of the IP address. ### Connecting The SSH command typically looks like: ```bash # before the postinstall: ssh root@11.22.33.44 # or after the postinstall: ssh username@11.22.33.44 # using the domain name instead of the IP (more convenient) ssh username@your.domain.tld # using the local domain name instead of the IP (for local access) ssh username@yunohost.local # if you changed the SSH port ssh -p 2244 username@your.domain.tld ``` :::note `fail2ban` will ban your IP for 10 minutes if you perform 10 failed login attempts. If you need to unban the IP, have a look at the page about [Fail2Ban](/admin/troubleshooting/fail2ban) ::: ## Which other users may connect to the server? By default, only YunoHost users in the `admins` group can log in to YunoHost's SSH and SFTP servers. Non-admin YunoHost users can't connect via SSH for security reasons. With the permissions system it is possible to specifically grant SFTP or even SSH access to non-admin users. :::caution Be careful who you give SSH access to. This increases even more the attack surface available to a malicious user. ::: Go to `Users > Manage groups and permissions`. From here, you can add SFTP or SSH permissions to any user or group. If you want to add an SSH public key to the user, you have to do it from the command line, as the web interface does not yet offer this feature. To allow a user or group to access via SFTP or SSH: ```bash # SFTP yunohost user permission add sftp # SSH yunohost user permission add ssh ``` To remove permission: ```bash # SFTP yunohost user permission remove sftp # SSH yunohost user permission remove ssh ``` Finally, it is possible to add, delete and list SSH keys, to improve SSH access security, using the commands: ```bash yunohost user ssh add-key yunohost user ssh remove-key yunohost user ssh list-keys ``` ## Security and SSH A more extensive discussion about security & SSH can be found on the [dedicated page](/admin/security). ## The command line :::info Providing a full tutorial about the command line is quite beyond the scope of the YunoHost documentation : for this, consider reading a dedicated tutorial such as [this one](https://ryanstutorials.net/linuxtutorial/) or [this one](http://linuxcommand.org/). But be reassured that you don't need to be a CLI expert to start using it ! ::: ### The `yunohost` command The `yunohost` command can be used to administer your server and perform the various actions similarly to what you do on the webadmin. The command must be launched either from the `root` user or from a user who is a member of the `admins` group by preceding the command with `sudo`. (ProTip™: you can become `root` with the command `sudo su` as a user who is a member of the `admins` group). YunoHost commands usually have this kind of structure : ```text yunohost app install wordpress --label Webmail ^ ^ ^ ^ | | | | category action argument options ``` Don't hesitate to browse and ask for more information about a given category or action using the the `--help` option. For instance, those commands : ```bash yunohost --help yunohost user --help yunohost user create --help ``` will successively list all the categories available, then the actions available in the `user` category, then the usage of the action `user create`. You might notice that the YunoHost command tree is built with a structure similar to the YunoHost admin pages. ### The `yunopaste` command This command allow you to share with an other person the output of a command. Example: ```bash tail -n 100 /var/log/mail.info | yunopaste ``` ### The `ynh-vpnclient-loadcubefile.sh` command This command is only available and relevant in the context of the `VPN Client` application installed. You can use it to load a new .cube in case you can't get to the VPN Client interface to do so. ```bash ynh-vpnclient-loadcubefile.sh -u -p -c .cube ``` ### Some useful commands If your administration web interface indicates that the API is unreachable, try starting `yunohost-api`: ```bash systemctl start yunohost-api ``` If you can no longer connect with an user member of `admins` group via SSH and via the web interface, the `slapd` service may be down, try restarting it: ```bash systemctl restart slapd ``` If you have manually modified configurations and want to know the changes: ```bash yunohost tools regen-conf --with-diff --dry-run ``` ================================================ FILE: docs/admin/20.users/groups_and_permissions.mdx ================================================ --- title: Users groups and permissions --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; You can access the *groups and permissions* management interface from the webadmin by going into the 'Users' section and clicking the corresponding button: ![screenshot of users permission button](/img/webadmin/button_to_go_to_permission_interface.png) ## Managing groups The group mechanism can be used to define groups of users which then can be used to restrict permissions for applications and other services (such as mail or XMPP). Note that it is *not* mandatory to create a group to do so: you can also restrict access to an app or service on a user-per-user basis. Using groups is however useful for semantics, for example if you host multiple groups of friends, associations or businesses on your server, you might want to create groups like `association1` and `association2` and add members of each association to the relevant group. It's also possible to define mail aliases for a group, such that mails sent to `groupe@domain.tld` will be dispatched to all members of the group. ### Default groups By default, these special groups are created: - `all_users`, that contain all users registered on YunoHost, - `visitors`, that applies to people viewing the server while not logged in. - `admins`, that contains YunoHost administrators, who will have SSH access as well as to the webadmin. The content of those groups cannot be changed, only the permissions given to them. ### List existing groups The existing groups are listed at the top of the *groups and permissions* page. ![](/img/webadmin/groups_default-groups.png) To list the currently existing groups in CLI : ```bash yunohost user group list groups: all_users: members: - alice - bob - charlie - delphine ``` ### Creating a new group To create a new group, simply click on the "New Group" button at the top of the page. You may only choose a name formed with letters (uper- and lowercase) and spaces. The group is created empty and without any permission. ![screenshot of new group button](/img/webadmin/groups_button-new-group.png) In CLI, to create a new group called `yolo_crew` ```bash yunohost user group create yolo_crew ``` ### Updating a group Let's add a first to this group: in the group panel, click the button "add a user" and scroll to the desired user, then click on it. ![](/img/webadmin/groups_button-add-user.png) To remove a user, click on the cross next to their username, in the group panel. ![](/img/webadmin/groups_button-remove-user.png) In CLI, use the following command to add `charlie` and `delphine`to the `yolo_crew` group: ```bash yunohost user group add yolo_crew charlie delphine ``` (similarly, `remove` can be used to remove members from a group) Now in the group list we should see: ```bash yunohost user group list groups: all_users: members: - alice - bob - charlie - delphine yolo_crew: members: - charlie - delphine ``` ### Deleting groups To delete a group, click on the red cross on the top right of the group panel. You will be asked for confirmation. ![](/img/webadmin/groups_button-delete-group.png) To delete the group `yolo_crew` in CLI, you may run ```bash yunohost user group delete yolo_crew ``` ## Managing permissions The permission mechanism allow to restrict access to services (for example mail, XMPP...) and apps, or even specific parts of the apps (for example the administration interface of WordPress). ### List permissions The groups page lists the permissions given to each group, including the special groups `all_users` and `visitors`. ![](/img/webadmin/groups_default-with-permissions.png) To list permissions and corresponding accesses in CLI: ```bash yunohost user permission list permissions: mail.main: allowed: all_users wordpress.admin: allowed: wordpress.main: allowed: all_users xmpp.main: allowed: all_users ``` Here, we find that all registered users can use email, XMPP, and access the WordPress blog. However, nobody can access the WordPress admin interface. More details can be displayed by adding the `--full` option which will display the list of users corresponding to groups allowed, as well as urls associated to a permission (relevant for web apps). ### Add accesses to group or users To add a permission to a group, simply click the "+" button in the group panel, scroll to the desired permission, then click on it. ![](/img/webadmin/groups_add-permission-group.png) Note that you can also allow a single user, by using the specific panel at the bottom of the page. ![](/img/webadmin/groups_add-permission-user.png) To allow a group to access the WordPress admin interface in CLI: ```bash yunohost user permission update wordpress.admin --add yolo_crew ``` Note that you can also allow a single user, by using the specific panel at the bottom of the page. ```bash yunohost user permission update wordpress.admin --add alice ``` And now we may see that both the YoloCrew and Alice have access to the WordPress admin interface: ```bash yunohost user permission list [...] wordpress.admin: allowed: - yolo_crew - alice [...] ``` Note that, for example, if we want to restrict permission for email so that only Bob is allowed to email, we should also remove `all_users` from the permission, by deleting it from the `all_users` group panel, or in CLI: ```bash yunohost user permission update mail --remove all_users --add bob ``` Note that some permissions may be "protected", meaning that you won't be able to add/remove the visitor group to this permission. Generally, this is because it would make no sense (or is a security risk) to do so. The webadmin will issue a warning if you set a permission that is superseded by a wider permission. ![](/img/webadmin/groups_alerte-permission.png) ### Hide/display specific tiles in the user portal Since YunoHost 4.1, you can choose to hide/display specific tiles in the SSO. In the webadmin, you can do so by going in the corresponding app view, go in `Manage label and tiles` and check/uncheck the option `Display the tile in the user portal` for the corresponding permission. In command line, this may be done with: ```bash # Enable the tile for the WordPress admin interface yunohost user permission update wordpress.admin --show_tile True ``` ## Configuring group aliases Each group can use mail aliases, but their configuration is only available from the CLI so far. For example, the `admins` group is configured with aliases such as `admins@domain.tld`, `root@domain.tld` ... : mail sent to these addresses will be dispatched to all members of the `admins` group. The command `yunohost user group info` will list them. ```bash yunohost user group info admins [...] mail-aliases: - root@maindomain.tld - admin@maindomain.tld - admins@maindomain.tld - webmaster@maindomain.tld - postmaster@maindomain.tld - abuse@maindomain.tld [...] ``` To add a new mail, use the action `add-mailalias` or `remove-mailalias` to delete it. ```bash yunohost user group add-mailalias ``` ================================================ FILE: docs/admin/20.users/index.mdx ================================================ --- title: 👥 Accounts and portal --- ## Users Users are human being who have access to applications and other services on your server. The administrator can add and manage users through the web administration (in the User category) or through the command line (see `yunohost user --help`). After that, users obtain a personal email address (chosen by the admin), and can log in the user portal to access applications they have permissions over and configure other parameters. The first user created also automatically gets email aliases `root@main.domain.tld` and `admin@main.domain.tld`, such that mail sent to these addresses will end up in the first user's mailbox. :::caution You should be careful about who you give your server access to. In terms of security, this largely increase the attack surface for someone who wants to mess with the server one way or another. ::: ## The user portal, or SSO ![User panel screenshot](/img/user_panel.jpg) The user portal, also called the SSO for 'Single Sign On' allows user to browse easily between the different apps they have access to. In particular, the term 'Single Sign On' comes from the fact that user only need to log in the portal to automatically be logged to all apps that require authentication (or at least those who are integrated with the SSO/LDAP, since this is sometimes technically complicated or not possible at all). In the portal, users can also click on the avatar in the top-left to configure some other settings such as their identify, mail aliases, automatic mail forwards, or change their password. :::info You should be aware that the SSO can only be reached through the actual domain name (i.e. `https://the.domain.tld/yunohost/sso`), and NOT by just using the IP of the server (i.e. `https://11.22.33.44/yunohost/sso`), contrarily to the webadmin ! This is a bit confusing but is necessary for technical reason. If you are in a situation where you need to access the SSO without having your DNS properly configured for some reason, you might consider tweaking your `/etc/hosts` as described in [this page](/admin/tutorials/domains/dns_local_network). ::: ## Creating new users Only the administrator can create new users. From the webadmin, open the `Users` menu and click on the `+ New user` main button. Fill in all the whole form. Users are created with an associated email address with the format `username@domain.tld`. Additional email aliases and email forwards can later be added by the admin and the user. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters). Finalize the user creation by clicking on the `Save` button.
## User groups and permissions See [this dedicated page](/admin/users/groups_and_permissions). ## SSH access See [this dedicated page](/admin/command_line). ================================================ FILE: docs/admin/25.domains/certificate.mdx ================================================ --- title: Certificate hide_table_of_contents: true --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; Certificates are used to guarantee the confidentiality and authenticity of the communication between a web browser and your server. In particular, they protect against attackers trying to impersonate your server. YunoHost provides a **self-signed** certificate, it means that your server guaranties the certificate validity. It's enough **for personal usage**, because you trust your own server. But this could be a problem if you want to open access to anonymous like web user for a website. In practice, visitors will see a screen list this: ![](/img/postinstall_error.png) Which basically asks the visitor : **"Do you trust the server hosting this website?"**. This can rightfully frighten a lot of people. To avoid this confusion, it's possible to get a certificate signed by a known authority named **Let's Encrypt** which provides free certificates directly recognized by browsers. YunoHost allows you to directly install this certificate from the web administration interface or from the command line. ## Install a Let's Encrypt certificate Before attempting to install a Let's Encrypt certificate, you should make sure that your DNS is correctly configured (your.domain.tld should point to your server's IP) and that your domain is accessible through HTTP from outside your local network (i.e. at least port 80 should be forwarded to your server). Go to the 'Domain' part of the admin interface, then in the section dedicated to your.domain.tld. You should find a 'SSL certificate' button: ![](/img/webadmin/domain-certificate-button.png) In the 'SSL certificate' section, you can see the status of the current certificate. If you just added the domain, it should be a self-signed certificate. ![](/img/webadmin/certificate-before-LE.png) If your domain is correctly configured, it is then possible to install the Let's Encrypt certificate via the green button. ![](/img/webadmin/certificate-after-LE.png) Once the install is made, you can check that the certificate is live via your browser by going to your domain in HTTPS. The certificate will automatically be renewed every three months. ![](/img/softwares/certificate-signed-by-LE.png) Connect to your server through SSH. You can check the status of your current certificate with: ```bash yunohost domain cert status your.domain.tld ``` Install a Let's Encrypt certificate with ```bash yunohost domain cert install your.domain.tld ``` This should return : ```bash Success! The SSOwat configuration has been generated Success! Successfully installed Let's Encrypt certificate for domain DOMAIN.TLD! ``` Once this is done, you can check that the certificate is live via your browser by going to your domain in HTTPS. The certificate will automatically be renewed every three months. ## Troubleshooting If due to some bad tweaking, your certificate ends up in a bad state (e.g. lost the certificate or unable to read the files), you should be able to clean the situation by regenerating a self-signed certificate: ```bash yunohost domain cert install your.domain.tld --self-signed --force ``` If YunoHost thinks that your domain is badly configured despite the fact that you checked the DNS configuration and you have access in HTTP to your server from outside your local network, then you can: - add a line `127.0.0.1 your.domain.tld` to the file `/etc/hosts` on your server; - if the certificate installation still doesn't work, you can disable the checks with `--no-checks` after the `cert install` command. ================================================ FILE: docs/admin/25.domains/index.mdx ================================================ --- title: 🌐 Domains --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; YunoHost lets you manage and serve multiple domains on a single server. So you can host, for example, a blog and Nextcloud on a first domain `yolo.com`, and a webmail client on a second domain `swag.nohost.me`. Each domain is automatically configured to handle web services and e-mail. Domains can be managed in the 'Domains' section of the webadmin, or via the `yunohost domain` category of the command line. Whenever you add a domain, it is assumed that you have purchased (or at least control) the domain, so that you can manage its [DNS configuration](/admin/get_started/post_install/dns_config). An exception is [domains in `.nohost.me`, `.noho.st` and `ynh.fr`](/admin/tutorials/domains/dns_nohost_me) which are offered by the YunoHost Project, and can be directly integrated with YunoHost through automatic DynDNS configuration. To limit abuse and costs, an instance can only have one domain offered at a time, but you can add as many sub-domains to it as you like. For example, if you choose `example.ynh.co.uk` you can then add the domains `video.example.ynh.co.uk` or `www.exemple.ynh.fr` or any other sub-domain you may require. Domains can be managed in the 'Domain' section of the webadmin, or through the `yunohost domain` category of the command line. ![Screenshot of the webadmin domain interface with an "Add domain" button and a list of domains](/img/webadmin/webadmin_domain.png) ## 3 types of domains In order to make self-hosting as accessible as possible, the YunoHost Project provides a *free* and *automatically configured* domain name service. By using this service, you won't have to [configure DNS records](/admin/get_started/post_install/dns_config) yourself, which can be tedious and technical. The following (sub)domains are offered: - `whateveryouwant.nohost.me`; - `whateveryouwant.noho.st`; - `whateveryouwant.ynh.fr`. In more, YunoHost uses an integrated dynamic DNS mechanism, so your server can stay reachable even if your public IP change. To get one of this domain you simply need to choose `I don't have a domaine name…` during the initial configuration (postinstall) or on the `Add domain` page. ![Screenshot of the "Add domain" page where you can choose "I don't have a domain name"](/img/webadmin/webadmin_dyndns.png) :::info To limit resources costs and abuses, each instance may only have one of these domains setup at any given time, however you can add as many sub-domains of it as you wish. For example, if you choose `example.noho.st` you can later add the domains `video.example.noho.st` or `www.example.ynh.noho.st` or any other sub-domain you may need. In this case you need to select `I already have a domain name`. ::: [More information on this domains](/admin/tutorials/domains/dns_nohost_me) Having your own domain brings several advantages: - more control and autonomy - simpler domain name (for example directly in .net or .org) However, you have to pay for it each year (about 15€/year ... depending on the TLD) and you have to do some extra configuration to [setup a correct DNS zone](/admin/get_started/post_install/dns_config). Our diagnosis tool can trigger alert to help you to do this configuration. If you already have your own domain, you can simply click "I already have a domain name…". If you don't, in order to simplify and automate the DNS configuration, we suggest you to buy it from a [registrar whose API is supported by YunoHost](/admin/get_started/providers/registrar/). ![Screenshot of the "Add domain" page where you can choose "I already have a domain name"](/img/webadmin/webadmin_domain_owndomain.png) [Know more on DNS zone configuration](/admin/get_started/post_install/dns_config) Starting from YunoHost v4.3, domains ending by `.local` are fully supported, in addition to the default `yunohost.local`. They do not use the DNS protocol, but the mDNS one (also known as Zeroconf, Bonjour), which allows them to be published with no specific configuration but exclusively on your local network or VPN. Their use is this especially suitable when you do not need your apps to be available on the Internet. ![Screenshot of the "Add domain" page where you can choose "I already have a domain name" and setup your domain ending by .local](/img/webadmin/webadmin_domain_local.png) :::info mDNS protocol does not allow for subdomains to be created. So `domain.local` will work, while `sub.domain.local` is not possible. ::: `Yunomdns` service takes care of publishing your `.local` domains on your network. It has a configuration file, `/etc/yunohost/mdns.yml`, which allows you to choose which domains are published, and on which network interfaces. This file is automatically regenerated whenever you add or delete a `.local` domain. The service will always try to publish `yunohost.local`. If you have multiple YunoHost servers on your network, try `yunohost-2.local`, and so on. The number may change depending on which server starts first, so do not rely on it to use actual apps and create your own domains. :::caution Unfortunately, Android devices before version 12 (released in 2021) do not seem to be listening to mDNS protocol. To be able to reach `.local` domains on your Android devices, you will have to add in their DNS settings your YunoHost server's local IP address. ::: ## DNS configuration DNS (Domain Name System) is a system that enables computers worldwide to translate human-readable domain names (such as `yolo.com`) into machine-readable IP addresses (such as `11.22.33.44`). For this translation (and other features) to work, DNS records need to be carefully configured. YunoHost can generate a recommended DNS configuration for each domain, including the records required for e-mail. The recommended DNS configuration is available in the web administrator via Domains > (the domain) > DNS configuration, or with the command `yunohost domain dns suggest the.domain.tld`. ## About Non-latin characters If your domain has special, non-latin characters, it will be transformed by YunoHost into its [internationalized version](https://en.wikipedia.org/wiki/Internationalized_domain_name) through [Punycode](https://en.wikipedia.org/wiki/Punycode). So when you use the command line, you have to use the punycode format return for example by `yunohost domain list`. ## SSL/HTTPS certificates Another important aspect of domain configuration is the SSL/HTTPS certificate. YunoHost is integrated with Let's Encrypt, so once your server is correctly reachable from anybody on the internet through the domain name, the administrator can request a Let's Encrypt certificate. See the documentation about [certificates](/admin/domains/certificate) for more information. ================================================ FILE: docs/admin/30.apps/custom_apps.mdx ================================================ --- title: Installing "custom" apps --- While YunoHost has many apps available in the catalog, you may want to install apps that are not available in the official catalog, or set up your very own website that you crafted using HTML / CSS / PHP .. ## Installing your very own webapp A special application exists called [My webapp](https://apps.yunohost.org/app/my_webapp). It can be seen as "an empty shell" in which you can drop your own HTML, CSS, JS, etc files through SFTP or other means. It also supports PHP, and an SQL database can be initialized. ## Adding a reverse proxy to an app that you manually installed, for example using Docker While YunoHost apps do not use Docker for reasons that are beyond the scope of this page, you can manually install Docker apps on your server (assuming you know what you're doing and won't tinker too much with the base system ...). However, this is not limited to Docker, you may have deployed an app "manually" using Python, Ruby or another language, and such an app usually listens on a specific port. Once your app or container is set up, you will probably need to actually *expose* the container on the web on a specific URL. This can be done using another special app called [Redirect](https://apps.yunohost.org/app/redirect). Make sure to choose the reverse proxy mode, and point it to something like `http://127.0.0.1:PORT` where `PORT` is the port of your custom app. It will add the appropriate configuration bits in Nginx, SSOwat and a tile in the user portal. ## Adding a custom tile in the portal pointing to an external app The [Redirect app](https://apps.yunohost.org/app/redirect) can also be used to add a "shortcut" tile in the user portal that points to an app or page located on a completely different server. Make sure to use the "explicit redirect" mode and the URL of the external page or app. Generally, you should refrain from manually tinkering and installing apps, except if you are sure they will not interfere with your server. YunoHost proposes two generic apps to help you out: ================================================ FILE: docs/admin/30.apps/index.mdx ================================================ --- title: 📦 Applications --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import Highlight from '@site/src/components/Highlight'; import {HighlightApplications, HighlightAppInstall} from '@site/src/components/Highlight'; One of the key feature of YunoHost is the ability to easily install applications which are then immediately usable. Example of applications include a blog system, a "cloud" (to host and sync files), a website, an RSS reader... Applications can be installed and managed through the webadmin interface in or through commands of the `yunohost app` category.
The application catalog and its categories can be browsed directly from the webadmin by clicking on the button in the apps list, or from this documentation.
:::caution Be careful and stay reasonable on the number of installed applications. Each additional installation increases the attack surface and the risk of failure. Ideally, if you want to test, do it with another instance for example in [a virtual machine](/admin/get_started/install_on/virtualbox). ::: ## Installing an app Let's say you want to install a *Custom Webapp*. Before actually running the installation steps, YunoHost will usually have you fill in a form to properly set it up for you.
### Subpaths vs. individual domains per apps Among specific questions, forms usually ask you to choose a domain and a path onto which the app will be accessible. In the context of YunoHost, it is quite common to have a single (or a few) domains on which several apps are installed in "subpaths", so that you end up with something like this: ```text yolo.com ├── /blog : WordPress (a blog) ├── /cloud : Nextcloud (a cloud service) ├── /rss : TinyTiny RSS (a RSS reader) ├── /wiki : DokuWiki (a wiki) ``` Alternatively, you may choose to install each (or some) apps on a dedicated domain. Beyond the aesthetic, using sub-domains instead of sub-paths allows the possibility to move a service to another server more easily. Also, some applications may need an entire domain dedicated to them, for technical reasons. The disadvantage is that you have to add a new domain each time, and therefore potentially configure additional DNS records, restart the diagnostics and install a new Let's Encrypt certificate. This might look prettier for end users, but is generally considered more complicated and less efficient in the context of YunoHost, since you need to add a new domain each time. Nevertheless, some apps might need an entire domain dedicated to them, for technical reasons. If all apps from the previous example were installed on a separate domain, this would give something like this: ```text blog.yolo.com : WordPress (a blog) cloud.yolo.com : Nextcloud (a cloud service) rss.yolo.com : TinyTiny RSS (a RSS reader) wiki.yolo.com : DokuWiki (a wiki) ``` :::info Many applications integrate a feature that allows you to change the URL of your application. This choice between subpath and subdomain can be reversed in some cases via a simple manipulation in the administration interface. ::: ### User access management and public apps The installation form usually asks whether or not the app should be publically accessible. If you choose to not make it public, only users logged in YunoHost will be able to reach it. :::tip After installation, this can be configured via the webadmin in the [Groups and permissions panel](/admin/users/groups_and_permissions), or similarly via the command-line subcategory `yunohost user permission`. ::: ### Instructions after installation Some applications need to give you instructions, URLs or credentials once they are installed. So remember to check the email of the first user account or the admin user selected before installation, if it was prompted. ### Multi-instance applications Some applications support the ability to be installed several times (at different locations) ! To do so, just go another time in , and select again the application to install. ## LDAP / SSO integration Applications that allow users to register may support integration with the LDAP / Single Sign On of YunoHost, so that users who connect to the user portal can be automatically logged in all these apps. However, some applications do not support this as it can be either not implemented in the upstream, or the package does not work on this part yet. This information is usually available on the README of the application package. ## Application configuration After installation, some settings handled by YunoHost can be tweaked, such as user and group permissions, application's tile and label in the SSO page, or its access URL. You can access the app's operations page by clicking its name in the applications list.
You can also delete the application from this page. From the command line, you can change: - the app's label in the SSO: `yunohost app change-label ` - the app's url: `yunohost app change-url app [-d ] [-p ]` You can also delete the app: `yunohost app remove ` `` is to be replaced with the app's ID. If this is the first instance of the app, like Nextcloud, the ID is `nextcloud`. If this is the second, then it's `nextcloud__2` and so on. To list all your apps and check their ID, you can run `yunohost app info`. ### Configuration panels Some apps include a *configuration panel*, which features actions and settings specific for each app that they usually do not handle themselves. They can also spare you the need for altering configuration files by hand. :::info Configuration panels are *not* meant to tweak every aspects of the apps. You will surely use their own administration panels more often than YunoHost's configuration panels. ::: The configuration panels are accessible in the webadmin in their operations page, trough the Config panel button.
From the command line, you can list the configuration panel settings with the following command: `yunohost app config get ` ```bash $ yunohost app config get my_webapp main.php_fpm_config.phpversion: ask: PHP version value: none main.sftp.password: ask: Set a password for the SFTP access value: ************** main.sftp.with_sftp: ask: Do you need a SFTP access? value: yes ``` To change a setting, either use `yunohost app config set ` to get prompted about all the settings, or use `yunohost app config set -v ` to alter a specific one. The `` is the setting name, for example `main.sftp.with_sftp` from above. ## Execute commands within the app Starting YunoHost v11.1.21.4, if you need to execute commands with the app's binary, or PHP commands, etc., you can execute the command `yunohost app shell `. It will: - open a new Bash shell as the app's system user - open the app's working directory (e.g. `/var/www/`) - preload the environment with variables taken from the app's service, if it exists - override `php`, so that it points to the PHP version used by the app ## Applications packaging Applications must be packaged manually by application packagers/maintainers. Apps can be integrated with YunoHost to support upgrades, backup/restore and LDAP/SSO integration among other things. If you want to learn or contribute to app packaging, please check the [contributor documentation](/dev/). ### Integration and quality levels Automated tests are being run regularly to test the integration and quality of all apps who were declared to be `working` by packagers. The result is a level between 0 and 8, whose meaning is detailed on [this page](/dev/packaging/test). Some tests results may also be available [on this dashboard](https://apps.yunohost.org/dash). By default, only applications of sufficient quality are offered. When the quality of an application drops and until the problem is reolved, the app is hidden from the catalog to prevent its installation and its upgrades are put on hold. ================================================ FILE: docs/admin/35.email/05.clients.mdx ================================================ --- title: Configure email clients --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; You can fetch and send emails using your YunoHost instance from desktop email clients such as Thunderbird Desktop or on your smartphone with applications like K-9 Mail. Modern mail clients should be able to configure themselves automatically. If autoconfiguration fails, you can do it manually following the instructions below. (If the autoconfiguration fails though, it should be understood as a bug in YunoHost, and we would be glad to read your feedback to try to reproduce the issue on our side!) ### Generic settings Here are the element you should enter to manually configure your mail client (`domain.tld` refers to what's after the @ in your email address, and `username` what's before @). | Protocol | Port | Encryption | Authentication | Username | | :--: | :-: | :--: | :--: | :--: | | IMAP | 993 | SSL/TLS | Normal password | `username` (without the `@domain.tld`) | | SMTP | 587 | STARTTLS | Normal password | `username` (without the `@domain.tld`) | ### Client by client ##### Configure Thunderbird Desktop (on a desktop computer) To manually configure a new account in Thunderbird Desktop, add the account information, then click on 'Configure manually'. - For the incoming server, use IMAP with port 993 and SSL/TLS. - For outgoing server, use port 587 with STARTTLS. - Select 'Normal Password' for the the authentication method of both. You may need to accept the certificate exceptions for fetching mails and after you send your first mail. Don't forget to remove the dot before the domain name. ![](/img/softwares/thunderbird_config_1.png) ![](/img/softwares/thunderbird_config_2.png) - [Manage alias mails](https://support.mozilla.org/en-US/kb/configuring-email-aliases) ##### Configure K-9 Mail / Thunderbird Mobile (on Android) Follow the following steps. (As for Thunderbird Desktop, you might need to accept certificates at some points) - Enter your email address then click "Next" - Enter your domain name in the "Server" field, fill the "Security" and "Port" fields as per the IMAP row in the table above, then enter your password in the "Password" field and click "Next" - Again, your domain name in the "Server" field, but fill the "Security" and "Port" fields as per the SMTP row in the table above, then enter your password in the "Password" field and click "Next" ##### Configure Dekko (on Ubuntu Touch) The first time you can simply choose "Add account". If you already have an account configured, tap the hamburger menu then tap the gear, choose Mail, Accounts and press the '+'-symbol. Then you choose IMAP. Fill in the fields and press Next. Now Dekko will look for the configuration. Check that all fields are correct. Make sure you have your YunoHost username, NOT your email address and choose "Allow untrusted certificates". Do this for IMAP and SMTP and press Next. Dekko will now synchronise the account after which you are done. Congratz! ================================================ FILE: docs/admin/35.email/10.migration.mdx ================================================ --- title: Migrate emails to YunoHost --- *[Documentation linked to YunoHost email](/admin/email)*. Migration of emails from one server to another can be done with two recommended tools: ImapSync or Larch. This tool must be installed on your desktop computer. The transfer method looks at this schema: **`Old email server −> desktop computer with ImapSync or Larch −> new email server`** ### ImapSync [ImapSync site](http://imapsync.lamiral.info/) Install ImapSync on your client computer by following this [guide](http://imapsync.lamiral.info/INSTALL): ```bash sudo dnf install imapsync # Under Fedora ``` Transfer emails from one server to another: ```bash imapsync --host1 --port1 993 --ssl1 --user1 --password1 \ --host2 --port2 993 --ssl2 --user2 --password2 ``` Note that transfer settings `--port 993` and `--ssl` are specific to YunoHost email server. ### Larch [Larch site](https://github.com/rgrove/larch/) After beforehand installed `gem`, install `larch` on your client computer: ```bash sudo gem install larch ``` Transfer emails from one server to another: ```bash larch -a -f imaps://server_of_origin.org -t imaps://server_of_destination.org ``` For other types of transfer refer to [Larch documentation](https://github.com/rgrove/larch#label-Usage). ================================================ FILE: docs/admin/35.email/index.mdx ================================================ --- title: 📬 Emails --- import Highlight from '@site/src/components/Highlight'; import {HighlightWebAdmin, HighlightDiagnosis, HighlightApplications, HighlightAppInstall} from '@site/src/components/Highlight'; YunoHost comes with a complete mail stack allowing you to host your own email server, and therefore to have your own email addresses in `something@your.domain.tld`. The mail stack includes an SMTP server (Postfix), an IMAP server (Dovecot), antispam (Rspamd) and DKIM configuration. ## Making sure your setup is right Email is a complicated ecosystem and quite a few details can prevent it from working properly. To validate your setup: - if you are self-hosting at home and not using a VPN, ensure [your ISP doesn't block port 25](/admin/get_started/providers/isp/) ; - route ports according to [this documentation](/admin/get_started/post_install/port_forwarding) ; - carefully configure mail DNS records according to [this documentation](/admin/get_started/post_install/dns_config) ; - test your configuration using the diagnostic features ( Email ). You can also use [mail-tester.com](https://mail-tester.com); a score of at least 8~9/10 is a reasonable goal (be careful: only 3 tests per domain per day are allowed) ## Email clients To interact with the email server (read and send emails), you can either install a webmail client such as Roundcube or Rainloop on your server or configure a desktop/mobile client as described in [this page](/admin/email/clients). Desktop and mobile clients have the advantage of copying your emails to the device, allowing offline viewing and relative protection against possible hardware failures of your server. ## Configuring email aliases and auto-forwards Mail aliases and forwards can be configured for each user. For instance, the first user created on the server automatically has an alias `root@the.domain.tld` configured—meaning that an email sent to this address will end up in the inbox of the first user. Automatic forwards may be configured, for instance if a user doesn't want to configure an additional email account and just wants to receive emails from the server on, say, his/her Gmail address (a copy of each email will be kept on the YunoHost server). Another feature which few people know about is the use of suffixes beginning with "+". For example, emails sent to `johndoe+booking@the.domain.tld` will automatically land in the `booking` directory (lowercase) of John Doe's mailbox or in John Doe's inbox if the `booking` directory doesn't exist. It is a practical technique, for example, to provide an email address to a website, then easily sort (via automatic filters) the mail coming from this website. Groups also can use alias features; by default, the group `admins` has aliases such as `root@` and `webmaster@`. [More info on the groups and permissions page](/admin/users/groups_and_permissions). ## What happens if my server becomes unavailable? If your server becomes unavailable, emails sent to your server will stay in a pending queue on the sender's side for as long as ~5 days. The sender's host will regularly try to resend the email, until it drops it if it was unable to send it. ## See also - [Removing your server’s IP/domain from antispam listings](/admin/troubleshooting/blacklist_forms). - [Migrating from an email provider to a YunoHost instance](/admin/email/migration) - [Configuring an SMTP relay](/admin/tutorials/email_configure_relay). ================================================ FILE: docs/admin/40.backups/05.evaluate.mdx ================================================ --- title: Backup strategies --- In the context of self-hosting, backups are an important element to compensate for unexpected events (fire, database corruption, loss of access to the server, compromised server...). The backup policy to implement depends on the importance of the services and data you manage. For example, backing up a test server will be of little interest, while you will want to be very careful if you are managing critical data for an association or a company - and in such cases, you will want to store the backups *in a different location or locations*. ## What is a good backup? A good backup consists of at least **3 copies of the data** (including the original data), on at least **2 separate storages**, in at least **2 separate locations** (far enough apart) and ideally with 2 separate methods. If your backups are encrypted **these rules also apply to the decryption phrase/key**. A good backup is also in many cases, a recent backup, so it takes either a lot of rigor or to **automate** the process. A good backup is checked regularly to ensure the effectiveness and integrity of the data. Finally, a good backup is one that is **restorable within an acceptable timeframe** for you. Remember to document your restoration method and to estimate the transfer time of a copy, especially if the Internet connections involved are not symmetrical. :::info Example of **a robust and comfortable combination**: - a remote and automatic backup with borg - a backup on external disk and automatic with borg - a regular snapshot/image (and before updates) - a monitored RAID 1 array (or a commercial VPS that will also be on an array) - a decryption passphrase stored on 3 media in 2 locations ::: ## Some possible methods - [generate an archive and download it manually (default method of YunoHost)](/admin/backups) - [backup automatically (recommended method)](/admin/backups/backup_methods) - [generate an archive directly on another disk](/admin/tutorials/external_storage) - [make a disk image or snapshot](/admin/backups/clone_filesystem) - [save useful data via a custom method](/admin/backups/custom_backup_methods) ## Risks Below, a list of risks sorted from the most to the least probable, whose probability remains to be adapted according to your situation (location of the server, quality of the installations, user profiles, etc.). It is up to you to put the cursor where it should be, especially considering the consequences of a data loss. :::caution Keep in mind that real accidents are linked to the occurrence of 2 events simultaneously. ::: - **Lack of rigor**: strategies based on manual backups require a lot of rigor in the regularity - **Bad handling**: it can happen that a backup is erased by mistake during a restoration or if you rely on a synchronization system, you could delete a file and the deletion would be synchronized instantly - **Cryptolocker**: this is a virus that encrypts files and demands a ransomware. If your users are using nextcloud and windows, an infected windows could synchronize encrypted files and thus you lose your copy. - **Hardware failure**: SD cards are the least reliable media over time (~2 years of life in a server), followed by SSD disks (about 3 years of life) and hard drives (3 years). Note that a new equipment has also probability to break down during the first 6 months. In all cases, your copies should not be on the same physical media. - **Software failure/bug**: a software bug may result in data deletion or you may not know how to fix a problem and want to restore your system. - **Electricity or internet failure**: do you have a plan if this happens? What if you are on vacation? - **Disaster or natural or unnatural event**: a small child, a cat, lightning or a simple leak can destroy your equipment. Fires or floods can also destroy your backup copy at the other end of your home... - **Server compromise**: a malicious person or a robot could attack your server and delete your data - **Machine theft**: a burglary or theft of a computer on which your password manager is located to decrypt your backups - **Search**: whether you are guilty or not, a search can result in the seizure of the entire computer equipment of a place (or even several) - **Death/health problem**: you may not be able to type your passphrase anymore ## About Nextcloud or Thunderbird (IMAP) synchronization A method that allows a partial backup is to backup files and emails via synchronization software like Nextcloud client or ThunderBird. This way, you avoid the risk of hardware failure. If this method is easy to set up, it is not without risk because of the synchronization itself. For example, if you are on Windows or Mac, you increase the risk of data loss following the encryption of files by a [cryptolocker](https://en.wikipedia.org/wiki/Ransomware) type virus. On any type of system, a false manipulation can delete all your copies on the server and on the equipment that synchronizes. This concern is aggravated by the fact that the deletion synchronization is usually rather instantaneous. While the risk of false manipulation can be mitigated by desktop backup software such as TimeShift, the risk of false manipulation can only be mitigated by a backup on a hard drive. Only a backup on a disconnected external hard drive really protects you from ransomware. ================================================ FILE: docs/admin/40.backups/10.backup_methods.mdx ================================================ --- title: Backup methods --- YunoHost currently has three apps integrating backup solutions offering more features than the simple ".tar" mechanism shipped in YunoHost, in particular automatic and remote backups. ## [BorgBackup](https://www.borgbackup.org/) (cf the [Borg "client"](https://apps.yunohost.org/app/borg) and [Borg "server"](https://apps.yunohost.org/app/borgserver) apps) - backup of data on an external disk or on a remote Borg repository - deduplication and compression of files, which makes it possible to keep many previous copies without too much storage overhead - data encryption, which allows you to store data with a third party - to define the frequency and type of data to be backed up - a mail alert system in case of backup failure. There are [remote borg repository providers](https://www.borgbackup.org/support/commercial.html), it is also possible to create your own repository on another YunoHost with the [borgserver application](https://github.com/YunoHost-Apps/borgserver_ynh). ## [Restic](https://restic.net/) (cf the [Restic app](https://apps.yunohost.org/app/restic)) - backup of data to remote storage (support for different types of storage: SFTP, S3, Backblaze B2, Azure, etc. *SFTP is recommended* for simplicity) - deduplication and compression of files, which makes it possible to keep many previous copies without too much storage overhead - data encryption, which allows you to store data at a third party - to define the frequency and type of data to be backed up - a mail alert system in case of backup failure. ## [Archivist](https://apps.yunohost.org/app/archivist) :::warning This application is currently broken! ::: - based on rsync and GPG - backup of data on a remote storage (support for different types of storage) - data encryption, which allows you to store data at a third party The package also allows you to finely define the frequency and type of data to be backed up and integrates an email alert system in case of backup failure. More info [on the forum](https://forum.yunohost.org/t/new-app-archivist/3747). ================================================ FILE: docs/admin/40.backups/15.clone_filesystem.mdx ================================================ --- title: Snapshotting the entire filesystem --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; YunoHost's backup tool only backs up useful files and relies on restore scripts to reinstall the dependencies of your applications. In other words, YunoHost's mechanism amounts to reinstalling and then reincorporating the data. Making full system images can be a complementary or alternative way to backup your machine. The advantage is that your system can be restored to the exact state it was in at the time of the backup. Depending on your type of installation, you can either create a snapshot or clone the storage medium by removing it from your server (turned off). ## Creating a snapshot A snapshot allows you to freeze an image of the file system. Snapshots are very useful when doing an update or testing, because they allow you to easily go back in case of a glitch. On the other hand, apart from some very high availability clusters, snapshots do not really protect you against hardware failures or disasters (cf. OVH fire in Strasbourg in 2021). In general, snapshots are quite disk space saving, the principle is that your file system will store the differences that occurred since your snapshot. Thus, only the modifications consume space. :::info Remember to delete the old snapshots to avoid wasting your storage space by storing all the differences since that date! ::: You can use this method with most VPS (often paying), virtual machine managers or if you have installed YunoHost with an advanced filesystem like btrfs, ceph or ZFS, you can also create snapshots via the command line Below, some documentation for the most known suppliers: - [DigitalOcean (EN)](https://docs.digitalocean.com/products/images/snapshots/) - [Gandi](https://docs.gandi.net/fr/simple_hosting/operations_courantes/snapshots.html) - [OVH](https://docs.ovh.com/fr/vps/snapshot-vps/) - [Scaleway (EN)](https://www.scaleway.com/en/docs/backup-your-data-with-snapshots/) Select the virtual machine and click `Snapshots`, then specify the snapshot name and click `OK`. ![The snapshot button is located at the top right](/img/softwares/virtualbox-snapshot2.webp) To restore, select the virtual machine, click on `Snapshots` then `Restore Snapshot option`. ![](/img/softwares/virtualbox-snapshot3.webp) Then click on `Restore Snapshot`. ![](/img/softwares/virtualbox-snapshot4.webp) - Select the virtual machine - Go to the `Backup` tab - Click on `Backup now`. - Choose `Snapshot` mode - Validate Below we consider that `/pool/volume` is the volume to snapshot. Create a read-only snapshot ```bash btrfs subvolume snapshot /pool/volume /pool/volume/$(date +"%Y-%m-%d_%H:%M") ``` List snapshots ```bash btrfs subvolume show /pool/volume ``` Restore a snapshot ```bash btrfs sub del /pool/volume btrfs sub snap /pool/volume/2021-07-22_16:12 /pool/volume btrfs sub del /pool/volume/2021-07-22_16:12 ``` Delete a snapshot ```bash btrfs subvolume delete /pool/volume/2021-07-22_16:12 ``` :::caution Be careful not to delete the original volume ::: :::tip See [this tutorial](https://www.linux.com/training-tutorials/how-create-and-manage-btrfs-snapshots-and-rollbacks-linux-part-2/) for more info ::: Below we consider that `pool/volume` is the volume to snapshot. Create a snapshot ```bash rbd snap create pool/volume@$(date +"%Y-%m-%d_%H:%M") ``` List snapshots ```bash rbd snap ls pool/volume ``` Restore a snapshot ```bash rbd snap rollback pool/volume@2021-07-22_16:22 ``` Delete a snapshot ```bash rbd snap rm pool/volume@2021-07-22_16:12 ``` Below we consider that `pool/volume` is the volume to snapshot. Create a snapshot ```bash zfs snapshot pool/volume@$(date +"%Y-%m-%d_%H:%M") ``` List snapshots ```bash zfs list -t snapshot -o name,creation ``` Restore a snapshot ```bash zfs rollback pool/volume@2021-07-22_16:22 ``` Delete a snapshot ```bash zfs destroy pool/volume@2021-07-22_16:12 ``` ## Create a cold image of the file system You can clone your media (SD card, ssd disk, VPS volume...) to create a disk image. This image before compression will be the exact size of your media, that's why this method applies rather to machines of less than 64GB. Unless you can read a snapshot, this method requires you to stop the server while you create the image. With a VPS, you have to restart in rescue mode from your provider's interface. This can be done with [USBimager](https://bztsrc.gitlab.io/usbimager/) (Note: make sure you download the 'Read-write' version! Not the 'Write-only' version!). The process then consists of the "reverse" of the SD card flashing process: - Turn off your server - Retrieve the SD card and plug it into your computer - In USBimager, click on "Read" to create an image ("photograph") of the SD card. You can use the resulting file to restore the whole system later. More details in [USBimager documentation](https://gitlab.com/bztsrc/usbimager/#creating-backup-image-file-from-device) It is possible to achieve the same thing with `dd` if you are comfortable with the command line: ```bash dd if=/dev/mmcblk0 | gzip > ./my_snapshot.gz ``` (replace `/dev/mmcblk0` with the real name of your SD card or hard drive) ================================================ FILE: docs/admin/40.backups/20.avoid_hardware_failure.mdx ================================================ --- title: Avoid hardware failure --- ## Physically secure your server Very often people who self-host don't have proper storage for their system. Leaving the server in several parts, in a high traffic area, accessible to children or pets, or in a poorly ventilated area can quickly turn into a disaster. ## Secure your hard drives Ideally, your hard disks should be fixed to prevent vibrations which can accelerate the wear of the equipment or even reduce its performance, especially if there is another disk next to it. ## Reduce swapiness for SD cards and SSDs If you use a swap file with an SSD or SD card with too much swapiness, your storage media could give up the ghost prematurely due to too many writes. To prevent this: ```bash cat /proc/sys/vm/swappiness ``` If it is above 10: ```bash sysctl vm.swappiness=10 nano /etc/sysctl.conf ``` If present, change the vm.swappiness value to 10. Otherwise add the line: ```text vm.swappiness = 10 ``` ## Storage redundancy In order to limit hardware failures of storage media, it can be relevant to set up a cluster of mirrored disks (RAID, ZFS). The idea here is that everything that is written to one disk will be written to the other. This way, if one fails, the other continues to work and the server is still fully functional. There are also more advanced clusters that maximize fault tolerance (failure of 2 disks like RAID6) or storage (see RAID 5). However, these disk clustering techniques should not be considered as backups. A RAID array should be considered as a single storage medium. Indeed, if this technique prevents having to reinstall in case of a probable disk crash, it is far from zero risk. Some examples of situations known to professional system administrators: - the disks of a cluster mounted with disks of the same brand can fail almost at the same time within a few hours - without monitoring the health of the disks, there is a good chance that the failure of one disk in the cluster will only be noticed when a second one fails (\>\<) - if you don't have a spare disk, the delay in purchasing one may result in the other disk crashing - a half-functional disk that produces errors can propagate its error through the cluster - the disk connectors or the RAID controller can also produce errors or fail - the more complex you make the architecture with many components, the more likely it is that one of them will fail :::info If you want to set up a RAID array or use btrfs, the easiest way is to do it at installation with the YunoHost iso in expert mode (when partitioning the system). ::: ================================================ FILE: docs/admin/40.backups/25.include_exclude_files.mdx ================================================ --- title: Include or exclude files --- ## Include files YunoHost usually already knows what needs to be backed up. However, if you have made manual changes, such as installing an app outside of the YunoHost application system, you may want to extend YunoHost's mechanism to specify other files to be backed up. By default, if configurations tracked by YunoHost are changed, they will be backed up. On the other hand, a database or an app added by hand, changes on some configurations not tracked, will not be backed up. You can create a backup hook and a restore hook to add data to backup. Here is an example: `/etc/yunohost/hooks.d/backup/99-conf_custom` ```bash #!/bin/bash # Source YNH helpers source /usr/share/yunohost/helpers ynh_backup_dest (){ YNH_CWD="${YNH_BACKUP_DIR%/}/$1" mkdir -p $YNH_CWD cd "$YNH_CWD" } # Exit hook on subcommand error or unset variable ynh_abort_if_errors # Openvpn ynh_backup_dest "conf/custom/openvpn" ynh_backup "/etc/sysctl.d/openvpn.conf" ynh_backup "/etc/openvpn" ynh_backup "/etc/fail2ban/jail.d/openvpn.conf" ynh_backup "/etc/fail2ban/filter.d/openvpn.conf" # Samba ynh_backup_dest "conf/custom/samba" ynh_backup "/etc/samba" ynh_backup "/var/lib/samba" ynh_backup "/etc/yunohost/hooks.d/post_user_create/99-samba" ynh_backup "/etc/yunohost/hooks.d/post_user_delete/99-samba" ynh_backup --src_path="/etc/yunohost/hooks.d/post_user_update/99-samba" --not_mandatory ynh_backup "/etc/cron.daily/clean-trash" # MISC ynh_backup_dest "conf/custom/misc" ynh_backup "/etc/sysctl.d/noipv6.conf" ynh_backup "/usr/local/bin/" ynh_backup "/etc/yunohost/hooks.d/backup/99-conf_custom" ynh_backup "/etc/yunohost/hooks.d/restore/99-conf_custom" ``` `/etc/yunohost/hooks.d/restore/99-conf_custom` ```bash #!/bin/bash # Source YNH helpers source /usr/share/yunohost/helpers ynh_restore_dest (){ YNH_CWD="${YNH_BACKUP_DIR%/}/$1" cd "$YNH_CWD" } # Exit hook on subcommand error or unset variable ynh_abort_if_errors # Openvpn app="custom_openvpn" # This variable is important for the following helper ynh_install_app_dependencies "openvpn openvpn-auth-ldap samba" ynh_restore_dest "conf/custom/openvpn" ynh_restore_file "/etc/sysctl.d/openvpn.conf" ynh_restore_file "/etc/openvpn" ynh_restore_file "/etc/fail2ban/jail.d/openvpn.conf" ynh_restore_file "/etc/fail2ban/filter.d/openvpn.conf" # Samba app="custom_samba" # This variable is important for the following helper ynh_install_app_dependencies "samba" ynh_restore_dest "conf/custom/samba" ynh_restore_file "/etc/samba" ynh_restore_file "/var/lib/samba" ynh_restore_file "/etc/yunohost/hooks.d/post_user_create/99-samba" ynh_restore_file "/etc/yunohost/hooks.d/post_user_delete/99-samba" ynh_restore_file --src_path="/etc/yunohost/hooks.d/post_user_update/99-samba" --not_mandatory ynh_restore_file "/etc/cron.daily/clean-trash" chown -R openvpn:openvpn /etc/openvpn # MISC ynh_restore_dest "conf/custom/misc" ynh_restore_file "/etc/sysctl.d/noipv6.conf" ynh_restore_file "/usr/local/bin/" ynh_restore_file "/etc/yunohost/hooks.d/backup/99-conf_custom" ynh_restore_file "/etc/yunohost/hooks.d/restore/99-conf_custom" ``` ## Exclude files There is no mechanism to exclude specific files from a YunoHost backup, other than the 2 options presented below: ### Avoid backing up certain `/home` folders If needed, you can specify that certain user `home` folders not be backed up by the `yunohost backup` command, by creating an empty file named `.nobackup` inside. Caution: this setup only works with **first-level subfolders of `/home`**, such as `/home/user1` or `/home/yunohost.multimedia`. It does not work for other levels of subfolders, like `/home/user1/bigfolder/`. ### Do not backup large amounts of data Some apps like Nextcloud are potentially attached to large amounts of data. It is possible to not backup them by default. In this case, the app is said to "backup only the core" (of the app). During an update, apps containing a large amount of data usually make a backup without these data. To temporarily disable backup of large data, for applications that implement this feature, you can set the `BACKUP_CORE_ONLY` variable. To do this, the variable must be set before the backup command: ```bash BACKUP_CORE_ONLY=1 yunohost backup create --apps nextcloud ``` Be careful: you will have to backup Nextcloud users' data yourself. If you want this behavior to be permanent: ```bash yunohost app setting nextcloud do_not_backup_data -v 1 ``` ================================================ FILE: docs/admin/40.backups/30.custom_backup_methods.mdx ================================================ --- title: Custom backup methods --- It is possible to create your own backup method and link it to YunoHost's backup file collection system. This can be useful if you want to use your own backup software or conduct disk mount/dismount operations for example. This operation is done with a hook and will allow you to launch a backup this way: ```bash yunohost backup create --method custom ``` Below is a simplistic example that can be used to set up a rotational backup with different disks that are changed every week: `/etc/yunohost/hooks.d/backup_method/05-custom` ```bash #!/bin/bash set -euo pipefail work_dir="$2" name="$3" repo="$4" size="$5" description="$6" case "$1" in need_mount) # Set false if your method can itself put files in good place in your archive true ;; backup) mount /dev/sda1 /mnt/hdd if [[ "$(df /mnt/hdd | tail -n1 | cut -d" " -f1)" != "/dev/sda1" ]] then exit 1 fi pushd "$work_dir" current_date=$(date +"%Y-%m-%d_%H:%M") cp -a "${work_dir}" "/mnt/hdd/${current_date}_$name" popd umount /mnt/hdd ;; *) echo "hook called with unknown argument \`$1'" >&2 exit 1 ;; esac exit 0 ``` ================================================ FILE: docs/admin/40.backups/35.migrate_or_merge_servers.mdx ================================================ --- title: Migrate or merge servers --- ## Migrate a server If YunoHost's archive system is not convenient enough to migrate a server, you can also [migrate from server to server with rsync](https://www.man42.net/blog/2017/07/how-to-migrate-a-debian-server/). ## Merge 2 YunoHost servers If you merge 2 servers together, you will need to recreate the users, domains and permissions of the first server on the destination server. Then you can restore app by app. :::danger There is a limitation concerning apps that have the same ID. It will not be possible to restore them easily. Also be careful not to delete the eponymous app from the destination server :/ ::: ================================================ FILE: docs/admin/40.backups/index.mdx ================================================ --- title: 🚑 Backups --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; In the context of self-hosting, backups are essential for mitigating the impact of unexpected events—such as fires, database corruption, server access issues, or security breaches. The backup strategy you implement should be tailored to the importance of the services and data you are managing. For instance, backing up a test server will be of little interest, whereas when handling critical data for an NGO or business, backups become much more vital. In these cases, it’s crucial to store backups in one, or ideally **several** locations. ## Manual backup YunoHost comes with a backup system that allows you to back up (and restore) system configurations and data (e.g. emails) and apps, if they support it. You can manage backups either from the command line (`yunohost backup --help`) or from the web administration (in the Backups section), though some features are not yet available in the webadmin. The current default method consists of creating a `.tar` archive containing all relevant files. #### Creating backups You can easily create backup archives from the webadmin by going to `Backups > Local storage` and clicking on `New backup`. You will then be asked to select which configuration, data and apps you want to back up. ![Screenshot of YunoHost's backup panel](/img/webadmin/backup.png) You can create a new backup archive from the command line. Here are a few simple examples of commands and their corresponding behavior: - Backing up everything (all system parts and apps): ```bash yunohost backup create ``` - Backing up only apps: ```bash yunohost backup create --apps ``` - Backing up only two apps (WordPress and shaarli): ```bash yunohost backup create --apps wordpress shaarli ``` - Backing up only emails: ```bash yunohost backup create --system data_mail ``` - Backing up emails and WordPress: ```bash yunohost backup create --system data_mail --apps wordpress ``` For more information and options regarding backup creation, consult `yunohost backup create --help`. You can also list the system parts that can be backed up with `yunohost hook list backup`. ### Downloading backups After creating backups, it is possible to list and inspect them using the corresponding views in the web administration interface. A button allows you to download the archive. If the archive is larger than 3GB, it may be better to proceed via SFTP. `Backup > Local Archives > > Download` Currently, the most accessible way to download big archives is to use the program FileZilla as explained in [this page](/admin/tutorials/filezilla). By default, backups are stored in `/home/yunohost.backup/archives/`. The `yunohost backup list` and `yunohost backup info ` commands provide information about the names and sizes of backups. It is possible to use `scp` (a program based on [`ssh`](/admin/command_line)) to copy files between two machines via the command line. So, from a GNU/Linux machine, you can use the following command to download an archive: ```bash scp admin@your.domain.tld:/home/yunohost.backup/archives/.tar ./ ``` If your SSH port is different from 22 ```bash scp -P ssh_port admin@your.domain.tld:/home/yunohost.backup/archives/.tar ./ ``` :::caution Don't forget to store your backup in a different location from your server. ::: :::info If you want, you can connect an external disk to your server so that the archives are saved directly to it. See this guide on [adding external storage to your server](/admin/tutorials/external_storage). ::: ### Testing You should regularly test your backups by at least listing the contents of the archives and checking the size of the associated data. It is best to practice restoration regularly. ```bash # List the files tar -tvf /home/yunohost.backup/archives/ARCHIVE.tar | less # List database exports tar -tvf /home/yunohost.backup/archives/ARCHIVE.tar | grep "(db|dump)`.sql" # Check the weight ls -lh /home/yunohost.backup/archives/ARCHIVE.tar ``` ### Restoring backups :::info SPOILER: The larger your data volume and the more applications you have, the more complex your recovery will be. ::: #### Simple case: little data, archive already present Go in `Backup > Local storage` and select your archive. You can then select which items you want to restore, then click on 'Restore'. ![Screenshot of YunoHost's restore panel](/img/webadmin/restore.png) From the command line, you can run `yunohost backup list` to get the available archive names. They are basically their filenames without extensions. You can then run `yunohost backup restore ` (hence without its `.tar` extension) to restore an archive. As for `yunohost backup create`, this will restore everything in the archive by default. If you want to restore only specific items, you can use something like `yunohost backup restore --apps wordpress`, which will restore only the WordPress app. :::tip In the case of a complete restoration, it is possible to restore instead of launching the initial configuration. ::: To restore an app, the domain on which it was installed should already be configured (or you need to restore the corresponding system configuration). You also cannot restore an app that is already installed... which means that to restore an old version of an app, you must first uninstall it. #### Uploading an archive In many cases, the archive is not on the server on which you want to restore it. So it has to be uploaded, which depending on its size can take more or less time. Currently, the most accessible solution for uploading backups is to use the FileZilla program as explained in [this page](/admin/tutorials/filezilla). By default, backups are to be placed in `/home/yunohost.backup/archives/`. You can use `scp` (a command built on `ssh`) to copy files between two machines from the CLI. For example, for a Linux terminal: ```bash scp /path/to/your/.tar admin@your.domain.tld:/home/yunohost.backup/archives/ ``` If your SSH port is different from 22 ```bash scp -P ssh_port /path/to/your/.tar admin@your.domain.tld:/home/yunohost.backup/archives/ ``` ================================================ FILE: docs/admin/42.security.mdx ================================================ --- title: 🔒 Security --- :::info When thinking and discussing security — whether in the context of YunoHost or any other system —, please keep in mind that security is not a binary state, but an ongoing practice. The term "security" is essentially meaningless without specifying what exactly we are securing against. The 'threats' to consider depend on your context, and can range from automated attacks from bots roaming the Internet, to sophisticated state actors like the NSA, or supply chain vulnerabilities (e.g., compromised software dependencies), or basic risks such as your own users employing overly simple passwords, or your worst enemy from elementary school 20 years ago trying to hack into your server... ::: YunoHost is developed with security in mind, and designs good tradeoffs between security and usability. Here's a non-exhaustive list of security aspects that the project is implementing: - a firewall based on `nftables` to restrict incoming traffic to relevant ports ; - `fail2ban`, a software that automatically rejects traffic from malicious IPs trying to brute force SSH and other services ; - using [Mozilla's recommendations for NGINX, Postfix, Dovecot, SSH ciphers etc.](https://wiki.mozilla.org/Security/Server_Side_TLS) ; - checking that user password/passphrase are not too simple when defining them ; - hashing user passwords (salted SHA512 in LDAP for example) ; - being vigilant on UNIX file/dir permissions across the whole system ; - apps are typically run using a dedicated user, and with [restricted capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) ; - auto-redacting sensitive information from YunoHost operation logs and when sharing them with Yunopaste ; - ... In addition, the project has mid-term goals to implement: - [password self-reset for users](https://github.com/YunoHost/issues/issues/878) ; - [automatic warnings about vulnerabilities](https://github.com/YunoHost/yunohost/pull/2077) (via the Diagnosis, not via the forum or social media) ; - supporting [OIDC](https://github.com/YunoHost/yunohost/pull/2149) and [2FA](https://github.com/YunoHost/issues/issues/238) ; - better support for SSH keys, in particular [making them configurable from the webadmin](https://github.com/YunoHost/issues/issues/175) ; - further constraining and limiting application capabilities to only what they need (cf. packaging v3) ; - ... :::info To discuss security flaws in YunoHost, contact the [project's security team](/community/security_team). ::: ## Basic security advice Security is not a one-time setup, it's an active, ongoing practice. Here are some basic practices that you should implement: :::warning Using stupidly simple passwords is arguably the number one reason why servers get "hacked". You and your users using reasonably complex passwords/passphrases is the basis of any good security. ::: 1. as an admin, forget traditional passwords. *[Use reasonably complex **passphases**](https://imgs.xkcd.com/comics/password_strength_2x.png)*. Learn about password managers. 2. keep your server and apps **reasonably up to date**. Consider using the [unattended upgrades](https://apps.yunohost.org/app/unattended_upgrades) app for automatic upgrades ; 3. be aware that **each app you install is an additional "attack surface"**. Ideally, check the security reputation of every app you install. **Do not** just install random apps and then forget about them. Uninstall apps that you no longer use ; 4. only create accounts for people that you have some amount of trust into, in particular that they will use **decent passwords/passphrases** and decent security hygiene in general ; 5. **regularly check the forum and social media** (e.g. [YunoHost's Mastodon account](https://toot.aquilenet.fr/@yunohost)) to stay informed when vulnerabilities are discovered or important fixes are released. --- The following sections describe possible ways to further harden the security of your server. ## SSH authentication via key By default, the SSH authentication uses the administration password. Deactivating this kind of authentication and replacing it by a key mechanism is advised. **On your client**: ```bash ssh-keygen ssh-copy-id -i ~/.ssh/id_rsa.pub ``` :::tip If you run into permissions issues, set `username` as owner of the dir `~/.ssh` with `chown`. Be careful, for security reasons this directory should be in mode `700`. If you are on Ubuntu 16.04 you should run `ssh-add` to initialize the SSH agent. ::: Type your admnistration password and your key will be copied onto your server. **On your server**, editing the SSH configuration file to deactivate password authentication is handled by a system setting: ```bash sudo yunohost settings set security.ssh.ssh_password_authentication -v no ``` :::danger Never close your current SSH connection before checking that your alterations work. Test your new configuration by opening a new terminal or window. That way, you can undo your alterations if anything goes wrong. ::: ## Using a custom port for SSH To prevent SSH connection attempts by robots that scan the internet for any server with SSH enabled, you can change the SSH port. This is handled by a system setting, which takes care of updating the SSH and Fail2Ban configuration. Note that changing the port is still useful even if you've disabled password authentication, because that significantly reduces noise from brute force attempts in SSH logs. :::warning If you manually modify anything in the SSH server configuration (`/etc/ssh/sshd_config`), YunoHost's regen-conf mechanism will no longer automatically update this file. For this reason, always use the YunoHost admin tools to make changes to the systems configuration files! ::: ```bash sudo yunohost settings set security.ssh.ssh_port -v ``` **For subsequent SSH connections**, you need to add the `-p` option followed by the SSH port number. ```bash ssh -p admin@ ``` :::danger Never close your current SSH connection before checking that your alterations work. Test your new configuration by opening a new terminal or window. That way, you can undo your alterations if anything goes wrong. ::: ## Hardening ciphers used by NGINX, SSH, Dovecot, Postfix The default TLS configuration for services tends to offer good compatibility to support old devices. You can tune this policy for specific services like SSH and NGINX. By default, the NGINX configuration follows the [intermediate compatibility recommendation](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29) from Mozilla. You can choose to switch to the 'modern' configuration which uses more recent security recommendations, **at the cost of decreasing compatibility**, which may be an issue for your users and visitors using older devices. More details about compatibility can be found on [this page](https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility). Changing the compatibility level is not definitive and can be reverted if it doesn't fit with your environment. **On your server**, change the policy for NGINX ```bash sudo yunohost settings set security.nginx.nginx_compatibility -v modern ``` **On your server**, change the policy for SSH ```bash sudo yunohost settings set security.ssh.ssh_compatibility -v modern ``` ## Disabling the YunoHost API YunoHost administration is accessible through an **HTTP API**, which is the API used by the webadmin. This may be an additional, unnecessary attack surface if you are not planning to use it. In this case, you can disable the corresponding service entirely via command line: :::warning This will completely disable both YunoHost's API and the web administration panel that relies on it. Proceed only if you are comfortable with exclusively using the command line from now on. ::: ```bash sudo systemctl disable yunohost-api sudo systemctl stop yunohost-api ``` As `yunohost-api` is now disabled and not running, Diagnosis will report an error. This error can be ignored using: ```bash sudo yunohost diagnosis ignore --filter services service=yunohost-api ``` ================================================ FILE: docs/admin/43.upgrade/11.0-bullseye.mdx ================================================ --- title: Migrating from 4.x to 11.x --- This page is dedicated to help you migrating an instance from YunoHost 4.4.x (running on Debian Buster/10.x) to YunoHost 11.x (running on Debian Bullseye/11.x). Note: we decided to skip the version numbers from 5 to 10 to follow the Debian version numbers. ## Important notes - The YunoHost team did its best to make sure that the migration is as smooth as possible and was tested over the course of several months in several cases. - With that said, please be aware that this is a delicate operation. System administration is a complicated topic and covering every particular case is quite hard. Therefore, if you host critical data and services, please [make backups](/admin/backups). And in any case, be patient and attentive during the migration. - Please don't rush into thinking that you should need to reinstall your system from scratch thinking it would be "simpler" (sigh). (A common attitude is to be willing to reinstall a server at the slightest complication...). Instead, if you happen to run into issues, we encourage you to try to investigate and understand what's going on and [reach for help on the chat and the forum](/community/help). - **You should watch the known issues at the bottom of this page, to be sure your migrations will work properly.** ## Migration procedure ### From the webadmin After upgrading to 4.4.x, go to Tools > Migrations to access the migrations interface. You will have to read carefully and accept the disclaimer then launch the migration. ### From the command line After upgrading to 4.4.x, run: ```bash sudo yunohost tools migrations run ``` then read carefully and accept the disclaimer. ## During the migration Depending on your hardware and packages installed, the migration might take up to a few hours. The logs will be shown in the message bar (you can hover it to see the whole history). They will also be available after the migration (like any other operations) in Tools > Logs. Note that even if you close the webadmin page for some reason, the migration will continue in the background (but the webadmin will be partially unavailable). ### If the migration crashed / failed at some point If the migration failed at some point, it should be possible to relaunch it. If it still doesn't work, you can try to [get help](/community/help) (please provide the corresponding messages or whatever makes you say that it's not working). ## What to do after the upgrade ### Check that you actually are on Debian Bullseye and YunoHost 11.x For this, go to Diagnosis (category Base system) or look at the footer of the webadmin. In the command line, you can use `lsb_release -a` and `yunohost --version`. ### Run the migration to repair your python app After upgrading, your python apps should be unavailable because their virtual environment (venv) needs to be rebuilt. To do that you can run the pending migrations in `Webadmin > Update`. The apps below won't be automatically repaired, you need to force-upgrade them manually instead with `yunohost app upgrade -F APP`. Apps which won't be automatically repaired and need a force upgrade: - calibreweb - django-for-runners - ffsync (this app is in python2 and no longer maintained, no guarantee) - jupiterlab - librephotos - mautrix - mediadrop - mopidy - pgadmin - tracim - synapse - weblate :::tip If needed, you can disable the automatic rebuild for a specific python app, by removing the dedicated file ending with `.requirements_backup_for_bullseye_upgrade.txt` before applying the migration. You can find this file near the venv (Python virtual environment) of your app inside `/opt` or `/var/www`. ::: ### Check that no issue appeared in the diagnosis Also in the webadmin Diagnosis section, make sure that no specific issue appeared after running the migration (for example a service that crashed for some reason). If the service `php7.3-fpm` appears to be dead, you should upgrade your PHP apps like the custom web app. Next, you can run `apt autoremove`. ### Check that your applications are working Test that your applications are working. If they aren't, you should try to upgrade them (it is also a good idea to upgrade them even if they are working anyway). If your app is broken and you were already with the latest version, you can rerun the upgrade thanks to the `-F|--force` option: ```bash yunohost app upgrade --force APP_NAME ``` ## Current known issues after the migration ### Can't run the migration due to `libc6-dev : Breaks: libgcc-8-dev issue` Note: This issue should be resolved in `yunohost_version`: `4.4.2.13` You have an app that depends on the `build-essential` package. See this [solution](https://forum.yunohost.org/t/migration-to-11-wont-start-libc6-dev-breaks-libgcc-8-dev/20617/42) to fix it manually ### DNSmasq is not running anymore We haven't yet found solution for this issue. ### No ethernet connexion after rebooting following a migration on a Raspberry Pi 4 :::warning If you have not yet rebooted your server, don't do it (we are looking for a solution). This will avoid you the use of a keyboard and screen. ::: We found this in the Raspberry Pi documentation > when the dhcpcd5 package is updated to the latest version (1:8.1.2-1+rpt1 -> 1:8.1.2-1+rpt2), the Raspberry Pi will fail to obtain a DHCP IP address following the next reboot or startup. This problem can be avoided by disabling and re-enabling the "System Options -> Network at Boot" option using the latest raspi-config after the dhcpcd5 package has been updated and prior to the system being shutdown or rebooted If you are using a Raspberry Pi 4 (or maybe 3), see this [solution](https://forum.yunohost.org/t/aucun-acces-a-internet-suite-a-migration-4-4-to-11-depuis-raspberry-pi-4-pi-400/20652/17) ### Restore ynh4 backup onto a fresh ynh11 If you can't restore your app but your system has been restored, you probably should use the regen conf to fix the nginx issues: ```bash yunohost tools regenconf nginx --force ``` After that you should be able to restore your apps. Don't forget to force upgrade them if you have 502 errors. ================================================ FILE: docs/admin/43.upgrade/12.0-bookworm/05.issues_faq.mdx ================================================ --- title: Migration isues FAQ --- This page lists all the known issues encountered after a migration from YunoHost 11 to 12. If the suggested solutions don't work, please [ask for help](/community/help). ## Python apps After upgrading, some python apps should be unavailable because their virtual environment (venv) needs to be rebuilt. To do that you can run the pending migrations in `Webadmin > Update`. In addition, the apps below won't be automatically repaired, you need to force-upgrade them manually instead, with `yunohost app upgrade -F APP`. Apps which won't be automatically repaired and need a force upgrade: - **borgserver** and all its instances (eg. `borgserver__2`, `borgserver__3`, ...) - **borg** ([Borg on the app store](https://apps.yunohost.org/app/borg)) : rebuilt using `yunohost app upgrade -F borg` (otherwise, will sent emails notifying that "The backup miserably failed to backup", with error `ModuleNotFoundError: No module named 'borg'`) TODO: list those apps FIXME:??!!! If needed, you can disable the automatic rebuild for a specific python app, by removing the dedicated file ending with `.requirements_backup_for_bullseye_upgrade.txt` before applying the migration. You can find this file near the venv (Python virtual environment) of your app inside `/var/www`. ## Error 500 everywhere The web server, nginx, might need a restart before being fully operational. Please run this command: ```bash sudo systemctl restart nginx ``` ## Mailman3 failed in diagnostics A manual change in a configuration file is needed for Mailman3 to work, see [the relevant issue](https://github.com/YunoHost-Apps/mailman3_ynh/issues/48#issuecomment-2536194377). ================================================ FILE: docs/admin/43.upgrade/12.0-bookworm/index.mdx ================================================ --- title: Migrating from 11.x to 12.x --- This page is dedicated to help you migrating an instance from YunoHost 11.x (running on Debian Bullseye) to YunoHost 12 (running on Debian Bookworm). ## Important notes - The YunoHost team did its best to make sure that the migration is as smooth as possible and was tested over the course of several months in several cases. - Please [backup your data and server](/admin/backups)! This migration is a complex operation and covering every pitfall is quite hard. And in any case, be patient and attentive during the migration. - Please don't rush into thinking that you should need to reinstall your system from scratch thinking it would be "simpler" (sigh). (A common attitude is to be willing to reinstall a server at the slightest complication...). Instead, if you happen to run into issues, we encourage you to try to investigate and understand what's going on and [reach for help on the chat and the forum](/community/help). - **You should watch the known issues at the bottom of this page, to be sure your migrations will work properly.** ## Migration procedure You first need to ensure your system is up to date. The migration is available starting with the version 11.3. It is recommended to run the migration from the command line, but it can still be done from the webadmin. ### From the webadmin Go to Tools > Migrations to access the migrations interface. You will have to read carefully and accept the disclaimer then launch the migration. Note that even if you close the webadmin page for some reason, the migration will continue in the background (but the webadmin will be partially unavailable). ### From the command line Run : ```bash sudo yunohost tools migrations run ``` then read carefully and accept the disclaimer. ## During the migration Depending on your hardware and installed apps and packages, the migration can take up to one or two hours. Logs will be displayed in the webadmin's modal window in the middle of the page. They will also be browsable after the migration like any other major operation under Tools > Logs. ## If the migration fails at some point If the migration fails, the first thing to try should be relaunch it. If it still doesn't work, your should [ask for help to the community](/community/help) (please provide error message, full logs and any context element that would help debugging the issue). ## After the migration ### Check that you actually are on Debian Bookworm and YunoHost 12.x Go to Diagnosis (category Base system) or look at the bottom-right of the webadmin to check YunoHost's version. From the command line, you can use `lsb_release -a` and `yunohost --version`. ### Run the new pending migrations Some more migrations appeared after the upgrade: - Rebuilding the virtualenvs of your Python apps - Migrate from PostgreSQL 13 to 15 You should run those as soon as possible to ensure your apps work properly. #### Agreeing to the new Terms of Service via command line YunoHost 12.x now requires that you agree to the new [Terms of Service](https://doc.yunohost.org/terms_of_services/). After reading and accepting them you can run: ``` yunohost tools migrations run 0031_terms_of_services --accept-disclaimer ``` ### Check the Diagnosis In the webadmin Diagnosis section, make sure that no specific issue appeared after running the migration (for example a service that crashed for some reason). ### Check that your applications are working Test that your applications are working. If they aren't, you should try to upgrade them (it is also a good idea to upgrade them even if they are working anyway). If your app is broken and you were already with the latest version, you can rerun the upgrade thanks to the `-F|--force` option: ```bash yunohost app upgrade --force APP_NAME ``` ## Current known issues after the migration Please check the [issues FAQ](/admin/upgrade/12.0-bookworm/issues_faq/). ================================================ FILE: docs/admin/43.upgrade/index.mdx ================================================ --- title: ✨ Upgrades --- ## From the webadmin On the administraton panel, click on Upgrade the system. YunoHost will refresh the system package catalog as well as the application catalog, and display available upgrades. Click on green upgrade buttons to upgrade the system and applications. ## From the command line Here are some example of corresponding command lines: ```bash # Fetch available updates yunohost tools update # Upgrade all system packages yunohost tools upgrade system # Upgrade all apps yunohost tools upgrade apps # Upgrade a specific application yunohost app upgrade wordpress ``` ================================================ FILE: docs/admin/45.tutorials/05.domains/_category_.yaml ================================================ label: "Domains" link: type: "generated-index" title: "Domains" ================================================ FILE: docs/admin/45.tutorials/05.domains/dns_dynamicip.mdx ================================================ --- title: DNS with a dynamic IP --- :::warning Before going further, make sure your global IP address is dynamic with: [`ip.yunohost.org`](http://ip.yunohost.org/). The global IP address of your box changes almost every day. ::: This tutorial aim to get around dynamic IP issue which is: when the IP public address of your (Internet Service Provider-) box changes, the DNS zone is not updated to point towards the new IP address, and consequently your server is no more reachable via its domain name After setting up the solution proposed in this tutorial, the redirection from your domain name to the actual IP address of your server will not be lost anymore. The method proposed here consists of automatizing the fact the box announces its global IP address change to the dynamic DNS, so that the DNS zone will automatically be updated. ### Registrars Here are some examples of registrars, companies where you can buy domain names: - [OVH](http://ovh.com/) - [GoDaddy](https://godaddy.com/) - [Gandi](http://gandi.net/) - [Namecheap](https://www.namecheap.com/) - [BookMyName](https://www.bookmyname.com/) If you own a domain name at **OVH**, you may go to step 4 and follow this [tutorial](/admin/get_started/providers/registrar/ovh/manualdns), given that OVH proposes a DynDNS service. #### 1. Create an account to a Dynamic DNS service Here are sites which offer a DynDNS service free of charge: - [DNSexit](https://www.dnsexit.com/Direct.sv?cmd=dynDns) - [No-IP](https://www.noip.com/remote-access) - [ChangeIP](https://changeip.com) - [DynDNS.it (in italian, paid plan)](https://dyndns.it) - [DynDNS with your own domain](https://github.com/opi/DynDNS-with-HE.NET) - [Duck DNS](https://www.duckdns.org/) - [ydns.io](https://ydns.io/) Register to one of them. It should provide you with one (or more) IP address to reach the service, and a login (that you may be able to self-define). #### 2. Move the DNS zones Copy the [DNS zones](/admin/get_started/post_install/dns_config), except for the NS fields, from the registrar where you bought your domain name from to the dynamic DNS service you registrer at in step 1. #### 3. Switch the management of your domain name to the dynamic DNS server This step consists in declaring to your registrar that the DNS service will now be managed by the DynDNS service provider. For this, first declare in the NS field(s) the IP address provided by the DynDNS service. Then, remove any other item in the [DNS zones](/admin/get_started/post_install/dns_config) (except the previous NS fields), from the registrar. #### 4. Configure the client This client could be your ISP-box, or a package installed on your server, such as `ddclient`. Here, we will use the client provided by the box, which is the more easy way. Enter the login of the dynamic DNS and its public IP address in your box (interface details may vary by ISP). ![](/img/providers/dns_dynamic-ip_box_conf.png) You're good to go ! ================================================ FILE: docs/admin/45.tutorials/05.domains/dns_local_network.mdx ================================================ --- title: Local network access to your server --- After completing your server installation, it is possible that your domain will not be accessible through the local network. This is an issue known as [hairpinning](http://en.wikipedia.org/wiki/Hairpinning) - a feature that is not well supported by some internet routers. To solve this issue you can: - configure your router's DNS - or alternatively - your `/etc/hosts` files on your clients workstation ## Find the local IP address of your server First you need to find out the local IP of your server - either using the tricks listed [here](/admin/get_started/post_install/find_ip) - or if in the webadmin, in the Diagnosis section, under Internet Connectivity, IPv4, click on 'Details' and you should find an entry for 'Local IP' - or using the command line on the server : `hostname -I` ## Configure DNS on your Internet router The goal here is to create a network wide redirection handled by your router. The idea is to create a DNS redirection to your server's IP. You should access your router's configuration and look for DNS configuration, then add a redirection to your server's IP (e.g. redirect `yunohost.local` to `192.168.1.21`). ## Configure [hosts](https://en.wikipedia.org/wiki/Host_%28Unix%29) file on client workstation Modifying hosts file should be done only if you cannot alter your box's DNS or router, because hosts file will only impact the workstation where the file was modified. - Windows hosts file is located at: `%SystemRoot%\system32\drivers\etc\` > You MUST activate hidden and system file display to see the hosts file. - UNIX systems (GNU/Linux, macOS) hosts file is located at: `/etc/hosts` > You MUST have root privileges to modify the file. Add a line at the end of the file containing your server private IP followed by a space and your domain name ```bash 192.168.1.62 domain.tld ``` ================================================ FILE: docs/admin/45.tutorials/05.domains/dns_nohost_me.mdx ================================================ --- title: Nohost.me domains --- In order to make self-hosting as accessible as possible, the YunoHost Project provides a *free* and *automatically configured* domain name service. By using this service, you won't have to [configure DNS records](/admin/get_started/post_install/dns_config) yourself, which can be tedious and technical. The following (sub)domains are offered: - `whateveryouwant.nohost.me`; - `whateveryouwant.noho.st`; - `whateveryouwant.ynh.fr`. To use this service, you simply have to choose such a domain during the post-installation set up. It will then be automatically configured by YunoHost! :::tip As a fairness measure, each instance may only have **one such domain** setup at any given time. ::: ### Subdomains The `nohost.me`, `noho.st` and `ynh.fr` domain service allows the creation of subdomains. YunoHost allows the installation of applications on subdomains (for example, having the Nextcloud application accessible from the `cloud.mydomain.org` address), this feature is also allowed with the `nohost.me`, `noho.st` and `ynh.fr` domains and so it is possible to have a subdomain such as `my.application.mydomain.nohost.me`. To create a subdomain on `nohost.me`, `noho.st` and `ynh.fr`, you just have to add the subdomain to YunoHost like any other domains. ### Adding a `nohost.me`, `noho.st` or `ynh.fr` domain after the post-installation If you already did the postinstall and want to add an automatic domain, you may do so from the "Domains" web interface, selecting the option "I don't have a domain name..." Alternatively, the following commands can be used. ```bash # Add the domain yunohost domain add whateveryouwant.nohost.me # Subscribe/register to the dyndns service yunohost dyndns subscribe -d whateveryouwant.nohost.me # [ wait ~ 30 seconds ] # Update the DNS conf yunohost dyndns update # Set it as the main domain yunohost domain main-domain -n whateveryouwant.nohost.me ``` ### Retrieve a `nohost.me`, `noho.st` or `ynh.fr` domain If you reinstall your server and want to use a domain already used previously, you must request a domain reset on the forum [in the dedicated thread](https://forum.yunohost.org/t/nohost-domain-recovery/442). ### Change a `nohost.me`, `noho.st` or `ynh.fr` domain If you wish to use a different automatic domain, you first have to remove your present domain registration. This is done in 3 steps: 1. Remove the domain from your instance (via webadmin or the `yunohost domain remove` in the CLI). 2. Since YunoHost 11.2, you can now define a recovery password for your nohost.me, noho.st or ynh.fr domain **during postinstall**, so that the recovery is automatic and no longer requires intervention from the YunoHost team via [the old, deprecated forum thread](https://forum.yunohost.org/t/nohost-domain-recovery/442). - If you didn't set the recovery password during postinstall, you can use `yunohost domain dyndns set-recovery-password` (add `--help` for help) to define one. 3. Remove automatic domain configuration files on your server, via CLI only: `sudo rm /etc/cron.d/yunohost-dyndns && sudo rm -r /etc/yunohost/dyndns` You may then add a new domain. ================================================ FILE: docs/admin/45.tutorials/05.domains/dns_subdomains.mdx ================================================ --- title: DNS and subdomains for the applications --- ### Subdomains YunoHost allows the use of subdomains. If one owns a domain name `mydomain.com`, one first needs to create the subdomains in the DNS configuration (with one's registrar like Gandi). ### Configuration example with Gandi The DNS configuration needs an A record with an IPv4 address, an AAAA record with an IPv6 address, and various CNAME records, one for each desired subdomain. If your DNS configuration looks like: ```text @ A XYZ.XYZ.XYZ.XYZ @ AAAA 1234:1234:1234:FFAA:FFAA:FFAA:FFAA:AAFF * CNAME mydomain.com. agenda CNAME mydomain.com. blog CNAME mydomain.com. rss CNAME mydomain.com. ``` then you can access `agenda.mydomain.com`, `blog.mydomain.com` and `rss.mydomain.com` subdomains. ### Install an application on a subdomain To install an application on a subdomain in YunoHost, for example `blog.mydomain.com`, the configuration is done in the administration panel. One first add the subdomain to the available domains list. The creation of a subdomain in YunoHost will create the corresponding configuration files for NGINX (the web server used in YunoHost). Then, in the applications>install panel, one follows the classic installation process by choosing the desired subdomain as domain (for example `blog.mydomain.com`). One needs to choose the path `/` (in place of `/wordpress` for example). A warning message will appear telling that it won't be possible to install other application to this subdomain. After validation, the installation starts. The application is then available at `blog.mydomain.com` (and not `mydomain.com/wordpress`). ### Moving an application to a subdomain What happens if the application is already installed? For example, one wants to move `mydomain.com/wordpress` to `blog.mydomain.com`. It depends on the application. Some applications allow the change of domain. In that case, one can proceed to the change through the administration panel: Applications > the_app_name > change URL. If the application doesn't allow URL change, then there is no easy way to do it. The best solution is to reinstall the application. ### Reinstalling an application First, save the application data through the backup process. Then uninstall the application with the administration panel. Then reinstall the application to the desired domain. Finally, restore the backup. ================================================ FILE: docs/admin/45.tutorials/10.theming.mdx ================================================ --- sidebar_label: Theme the portal title: Customize the appearance of the user portal --- The portal is customizable from the webadmin: `Domains` > Choose a top level domain > `Features` ## Options for the Portal customization ### Show the list of public apps to visitors Visitors will see a 'public apps' page when ending up on the portal instead of just the login form. ### Show other domain's apps All apps from all domains will be visible on the portal. Default value is `true`. ### Custom title Choose a Title for the Portal ### Custom logo Choose a image. Accept .svg, .png and .jpeg. Prefer a monochrome .svg with `fill: currentColor` so that the logo adapts to the themes. ### Default color theme Choose a color theme. Users are allowed to choose another one in their settings. * App tiles display theme * simple = display apps icons * descripitive = display apps icons and a descpriction of the application * periodic = display tiles with name apps. ### Search engine URL This is an optional feature, allowing to display a search bar in the portal (for example if you like to use your YunoHost portal as your browser's home page). This should be an URL with an empty query string such as `https://duckduckgo.com/?q=, with q=` as duckduckgo's empty query parameter ### Custom user intro You can use HTML, basic styles will be applied to generic elements. ### Custom public intro You can use HTML, basic styles will be applied to generic elements. * Custom CSS stylesheet This is for advanced admins willing to customize the appearance of the portal. ================================================ FILE: docs/admin/45.tutorials/15.filezilla.mdx ================================================ --- sidebar_label: Transfer files title: Exchange files with your server using a graphical interface --- This page explains how to exchange files (backup archives, music, pictures, movies...) with your server using a graphical interface for the (S)FTP protocol. This is an alternative to using `scp` which can be deemed technical and cryptic, or using an app like Nextcloud. [FileZilla](https://filezilla-project.org/) can be used for this. It is free software and is available for Windows, GNU/Linux and macOS. ## Download and install FileZilla Get the client from the [download page](https://filezilla-project.org/download.php?type=client). It should automatically detect the version needed for your computer. Otherwise, follow the instructions to [install the client](https://wiki.filezilla-project.org/Client_Installation) Install the program and run *Filezilla*. ## Configuration 1. Click the *Site Manager* icon in the upper left to begin. ![Main screen of Filezilla](/img/softwares/filezilla_1.png) 2. Click **New Site** and give a name the server you will be using : *Family* here. Fill the settings as on the screenshot (replace the server address with your own and leave the port field empty unless you changed your SSH port number, in which case use this port number), and click on **Connect**. (N.B. : if you want to interact with the [custom webapp](https://github.com/YunoHost-Apps/my_webapp_ynh) files, you should use a different user than `admin`. Refer to the custom webapp documentation.) ![Site manager screen](/img/softwares/filezilla_2.png) 3. You will get a warning as you connect for the first time to the server. *You can ignore it safely the first time you get it.* ![warning about the unknown fingerprint of the server](/img/softwares/filezilla_3.png) 4. Filezilla is now asking the `admin` password to connect to your server. ![credential screen asking for the password](/img/softwares/filezilla_4.png) 5. Once bookmarked, your server will be backup up and you will get this screen. ![View of the "site manager" with the newly server added](/img/softwares/filezilla_5.png) ## Usage 1. Connect to the Site created previously. *Your passwork might be asked again* The left panel corresponds to your computer. The right panel corresponds to your remote YunoHost server. You can browse folders and drag-and-drop files between the two panels. ![view while connected to a remote server](/img/softwares/filezilla_6.png) 2. In the right panel, you can browse to `/home/yunohost.backup/archives/` to find [backup archives](/admin/backups/). ![path where backups are located on YunoHost](/img/softwares/filezilla_7.png) :::warning Be sure to download both the `.tar.gz` and `.json` files. ::: ![Copy backups from YunoHost to local computer](/img/softwares/filezilla_8.png) --- Sources - [Official documentation](https://wiki.filezilla-project.org/FileZilla_Client_Tutorial_(en)) - [General tutorial about using FileZilla](https://www.rc.fas.harvard.edu/resources/documentation/sftp-file-transfer/) ## Alternatives to Filezilla ### GNU/Linux From any recent GNU/Linux, you should be able to use the `file manager` to reach your server. Nautilus from Gnome3 and Dolphin from KDE have features similar to FileZilla, out of the box. - [Nautilus Connect](https://help.gnome.org/users/gnome-help/stable/nautilus-connect.html.en) - [Dolphin](https://docs.kde.org/stable5/en/dolphin/dolphin/location-bar.html#location-bar-editable-kioslaves) - [Tutorial for Nautilus and SFTP](https://www.techrepublic.com/article/how-to-use-linux-file-manager-to-connect-to-an-sftp-server/) ### Windows - [WinSCP](https://winscp.net/) is also a nice candidate for Windows ### macOS - [Cyberduck](https://cyberduck.io/) is a free software available on macOS ================================================ FILE: docs/admin/45.tutorials/25.external_storage.mdx ================================================ --- sidebar_label: Add external storage title: Adding an external storage to your server --- ## Introduction Apart from the monitoring system that ensures that your system's partitions are not too small, YunoHost does not currently deal with the organisation of your partitions and disks. If you are hosting on an ARM card with an SD card or on a server with a small SSD drive, you may, for reasons of reliability or lack of space, want to add a drive or drives to your server. :::warning If you have no space left on your server at all, you can now type `apt clean` to try and save some space while you clean up or follow the steps below. ::: Below you will find explanations on how to move your data to a hard disk in a correct way with a minimum of impact on the functioning of YunoHost. This operation can be done during installation or, afterwards, when your storage needs have increased or when you no longer trust your SD card. :::tip The method presented here will first mount the single partition of the hard disk, then use one or more sub-folders of this disk to create different mount points on your system tree. This method is preferable to the use of symbolic links, as the latter may interfere with some applications including the YunoHost backup system. You could also choose to mount partitions rather than subfolders, but it is sometimes difficult to estimate the weight of a folder in advance. ::: ## Prerequisites - Schedule a moment when it'll be OK to shutdown the server. The steps to be performed, even if they are relatively simple, can sometimes seem technical and require in any case **to take your time**. - You'll need to know how to connect as root on your system, typically via [SSH](/admin/command_line). (Note: while logged in as an admin user, you can become `root` with `sudo su` or `sudo -i`, which is sometimes more convenient than prefixing every command with `sudo`) - Know the basic commands `cd`, `ls`, `mkdir`, `rm`. - Prepare a backup in case things don't work out as planned - Have extra storage (SSD, hard drive, USB stick) connected to your server via USB or SATA ## 1. Identify directories to be moved The `ncdu /` command allows you to browse the folders on your server to see how big they are. Below is an explanation of some of the paths that can take up weight with some comments to help you reduce their weight or choose to move them. | Paths | Contents | Tips | | --------------------------- | ------------------------------------------------------------ | ----------------------- | | `/home` | User folders accessible via SFTP | Moveable to a hard disk | | `/home/yunohost.backup` | YunoHost's backups | Depending on your backup strategy, you may want to place this folder on a separate drive from your data or databases. | | `/home/yunohost.app` | Heavy data from YunoHost applications (nextcloud, matrix...) | Moveable to a hard disk | | `/home/yunohost.multimedia` | Heavy data shared between several applications | Moveable to a hard disk | | `/var/lib/mysql` | Database used by applications | Ideally leave on SSD for performance reasons | | `/var/lib/postgresql` | Database used by applications | Ideally leave on SSD for performance reasons | | `/var/mail` | User e-mails | Movable to a hard disk | | `/var/www` | Program of installed web applications | Ideally leave on SSD for performance reasons | | `/var/log` | Event logs (pages consulted, connection attempts, hardware errors...). | This directory should not take up too much space, if it grows quickly, it may be a looping error that should be resolved. | | `/opt` | Program and dependency of some YunoHost applications. | Ideally leave it on the SSD for performance reasons. For nodejs applications it is possible to do some cleanup of unused versions. | | `/boot` | Kernels and boot files | Do not move unless you know what you are doing. It can happen that too many kernels are kept, it is possible to do some cleanup. | ## 2. Connect and identify the disk Start by connecting your disk to your system. You must then identify the name under which the disk is designated by the system. To do this, use the command : ```bash lsblk ``` It may return something like : ```bash NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 931.5G 0 disk └─sda1 8:1 0 931.5G 0 part mmcblk0 179:0 0 14.9G 0 disk ├─mmcblk0p1 179:1 0 47.7M 0 part /boot └─mmcblk0p2 179:2 0 14.8G 0 part / ``` Here, `mmcblk0` corresponds to a 16GB SD card (you can see that the `mmcblk0p1` and `mmcblk0p2` partitions correspond to the `/boot` partition and the `/` system partition). The hard drive connected corresponds to `sda` which is about 1TB, and contains a single `sda1` partition which is not mounted (no "MOUNTPOINT"). :::warning On another system, it may be that your system is installed on `sda` and your disk is then `sdb` for example. ::: :::tip If the size of the disk is not enough for you to recognise it, you can unplug the disk, run the `lsblk` command, then plug the disk back in, run `lsblk` and deduce the differences. ::: ## 3. (Optional) Format the disk This operation is optional if your disk is already formatted with a file system supported by linux (so not NTFS or FAT32). Let's create a partition on the disk: ```bash fdisk /dev/YOUR_DISK ``` then enter `n`, `p`, `1`, `Enter`, `Enter`, and `w` successively to create a new partition. Check with `lsblk` that you have your disk containing a single partition. Before you can use your disk, it must be formatted. :::warning **Formatting a disk means deleting all the data on it!** Be careful not to get the name wrong, as this may result in formatting a different disk than the one you want! In the example given earlier, it was `/dev/sda`. If your disk is already "clean", you can skip this step. ::: To format the : ```bash mkfs.ext4 /dev/YOUR_DISK1 # then 'y' to validate ``` Replace `YOUR_DISK1` with the name of the first partition on the disk e.g. `sda1`. :::tip It is possible to adapt this step, for example to create a raid 1 volume (mirrored disks) or encrypt the folder. ::: ## 4. Mount the disk Unlike Windows where disks are accessed with letters (C:/), under Linux, disks are made accessible via the file tree. "Mounting" a disk means making it effectively accessible in the file tree. We will arbitrarily choose to mount the disk in `/mnt/hdd` but you can name it differently (e.g. `/mnt/disk` ...). Let's start by creating the directory : ```bash mkdir /mnt/hdd ``` Then we can mount the disk manually with : ```bash mount /dev/YOUR_DISK1 /mnt/hdd ``` (Here, `/dev/YOUR_DISK1` corresponds to the first partition on the disk) ## 5. Mount a `/mnt/hdd` folder on one of the folders you want to move data from Here we will consider that you want to move the big data of the applications which are in `/home/yunohost.app` and the mails on your hard disk. ### 5.1 Creating subfolders on the disk To begin with, we create a folder on the hard drive ```bash mkdir -p /mnt/hdd/home/yunohost.app mkdir -p /mnt/hdd/var/mail ``` ### 5.2 Switching to maintenance mode Then, ideally, we switch to maintenance mode the applications that might be writing data. Example, for nextcloud: ```bash sudo -u nextcloud /usr/bin/php /var/www/nextcloud/occ maintenance:mode --on ``` Example, for mail: ```bash systemctl stop postfix systemctl stop dovecot ``` :::warning If you wish to move databases such as mariadb (mysql), it is imperative that you stop the services for these databases otherwise it is almost certain that your data will be corrupted. ::: ### 5.3 Creating the mount points Next, we will rename the original folder and create an empty eponymous folder. ```bash mv /home/yunohost.app /home/yunohost.app.bkp mkdir /home/yunohost.app mv /var/mail /var/mail.bkp mkdir /var/mail ``` We can then use the `mount --bind` command to mount the folder on our hard drive to the new empty location in the tree. ```bash mount --bind /mnt/hdd/home/yunohost.app /home/yunohost.app mount --bind /mnt/hdd/var/mail /var/mail ``` ### 5.4 Copying the data Next, we copy the data, keeping all the folder and file properties. This operation can take a little time, with another terminal, you can control the evolution by observing the weight associated with the mount point with `df -h` ```bash cp -a /home/yunohost.app.bkp/. /home/yunohost.app/ cp -a /var/mail.bkp/. /var/mail/ ``` Once this is done, check with `ls` that the contents are there: ```bash ls -la /home/yunohost.app/ ls -la /var/mail/ ``` ### 5.5 Exiting maintenance mode From here you can stop maintenance mode, the command below is to be adapted depending on the services you have stopped. ```bash sudo -u nextcloud /usr/bin/php /var/www/nextcloud/occ maintenance:mode --off systemctl start postfix systemctl start dovecot ``` From this point on, your services are running with their data on disk, so it's time to test to see how much of an impact this has on performance (especially if you are using USB 2.0). ## 6. Automatically mount on boot So far we have manually mounted the disk and subfolders. However, it is necessary to configure the system to automatically mount the disk after a boot. If your tests are successful, you should keep the mount points, otherwise you should hurry up and go back to maintenance first. To begin with, let's find the UUID (universal identifier) of our disk with : ```bash lsblk -f ``` Let's add a line to the `/etc/fstab` file that handles the mounting of disks at boot time. So we open the file with `nano` : ```bash nano /etc/fstab ``` Then add these lines to the end of the file: ```bash UUID="cea0b7ae-2fbc-4f01-8884-3cb5884c8bb7" /mnt/hdd ext4 defaults,nofail 0 0 /mnt/hdd/home/yunohost.app /home/yunohost.app none defaults,bind 0 0 /mnt/hdd/var/mail /var/mail none defaults,bind 0 0 ``` (this line must be adapted according to the previous information and choices) Use Ctrl+X then `y` to save. You can then try rebooting the system to check if the disk and subfolders are mounted automatically. ## 7. Clean up old data Once your new setup is validated, you can proceed to delete the old data from step 5.3: ```bash rm -Rf /home/yunohost.app.bkp rm -Rf /var/mail.bkp ``` ## 🎉 Congratulations! If you have made it this far without damage, you now have a server that takes advantage of one or more storage disks. ================================================ FILE: docs/admin/45.tutorials/35.email_configure_relay.mdx ================================================ --- title: Configure SMTP relay --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; If your ISP blocks port 25, if you can't set a reverseDNS on your server, or if you have any other troubles using the built-in SMTP server on YunoHost, you may want to setup your YunoHost server to use an SMTP relay. ## What is an SMTP relay? An SMTP relay is basically a third party hosted SMTP server that will send emails on behalf of your own SMTP server (Postfix service on YunoHost). Once setup correctly on YunoHost, its operation is transparent, both for you and for your correspondents: they will see emails as coming from your YunoHost main URL, but all the sending will be delegated to the SMTP relay you have chosen and configured. ## Disadvantages of SMTP relays It's important to note that using an SMTP relay has to be seen as a (big) compromise in the world of self-hosting. Indeed, when using an SMTP relay, not only a third party sends emails on your behalf, but it has full access to the content of all the emails you'll send and can also possibly modify them (For example, by default, MailJet rewrites the html hyperlinks contained in your emails, in order to track the activity of your correspondents). Be also aware that an SMTP relay is setup for your whole YunoHost server: you can't choose which emails or which users go through it because all future emails will. Beyond the privacy considerations above, an SMTP relay can impose technical limitations that one would not have if port 25 was open. For example, with most relays, if a user of your YunoHost server declares **an external "forwarding address"** in order to automatically forward messages received on your YunoHost server to another mailbox, **such forwarding will not work** for emails originating from outside your server, without any warning. Indeed, relays generally require that the messages they forward have a sender address from your domain (to fight spam and preserve the reputation of their services), which is not the case for an "automatic forward" where the original sender of the mail is kept; the message is then blocked by the relay (which, normally, warns your YunoHost admin, but only afterwards) ## How to use an SMTP relay with YunoHost? YunoHost has a built-in SMTP relay configuration, available from version 4.1. That configuration is not yet available from the admin web interface, though. You will have to use the command line interface. ### Step 1: Register with an SMTP relay provider Many providers exist. Some have free plans with or without limitations, it's up to you. As written above, you have to be careful with your choice as you will basically handover all your emails to that third party. Whether you can trust it or not, that's your call! ### Step 2: Setup your DNS records correctly Once registered, the SMTP relay provider will usually ask you to modify your DNS. Standard procedure is to add a DKIM key and a SPF key to your DNS records. The way to modify these records and the value of the keys you'll have to add depend both on your domain name provider and SMTP relay provider. Usually, the SMTP relay provider will provide you with a guide on how to modify these records, together with an automatic check tool that will tell you when your DNS have been setup correctly. That step is mandatory to prove "the world" that you, owner of your domain name, did explicitly authorize your SMTP relay provider to send emails on your behalf. Please note that modifying your DNS records could sometimes take over 24h to take effect, so be patient! :::warning From now on, a non trusty SMTP relay provider could send emails from your main domain without telling you. ::: ### Step 3: Setup YunoHost correctly It can be configured either from the webadmin or the command line. Go to your web admin, in `Tools` > `Yunohost Settings` and `Email`. Now set all options requests : - **SMTP relay host** : SMTP server url. - **SMTP relay port** : Port use with the distant server. - **SMTP relay user** : Login or identification mail server. - **SMTP relay password** : Your SMTP relay password. :::warning Password with `#` char won't works properly due to postfix limitation (it's possible other chars are forbidden, don't hesitate to report it to update this doc). ::: ![](/img/webadmin/relay_smtp_option_webadmin_en.png) In order to setup your YunoHost to use your SMTP relay, you will have to configure four things: 1. Your SMTP relay URL (for this tutorial we will use `smtprelay.tld`) 2. The port on which you access the relay (for this tutorial we will use port 2525 below) 3. Your SMTP relay username (for this tutorial we will use `username`) 4. Your SMTP relay password (for this tutorial we will use `password`) :::warning Password with `#` char won't works properly due to postfix limitation (it's possible other chars are forbidden, don't hesitate to report it to update this doc). ::: Your SMTP relay will obviously provide you with these four things, that should be available in your control panel or whatsoever. You can log into your YunoHost server using SSH: ```bash ssh admin@yourdomain.tld ``` Then you can update the three values as below: ```bash sudo yunohost settings set email.smtp.smtp_relay_enabled -v yes sudo yunohost settings set email.smtp.smtp_relay_host -v smtprelay.tld sudo yunohost settings set email.smtp.smtp_relay_port -v 2525 sudo yunohost settings set email.smtp.smtp_relay_user -v username sudo yunohost settings set email.smtp.smtp_relay_password -v password ``` It may be a good idea to double confirm your settings by doing: ```bash sudo yunohost settings list ``` Your SMTP relay is now configured! :::warning From now on, a non trusty SMTP relay provider could read or use the data of all the emails you send without telling you (but still won't be able to read nor to use the data from emails you receive). ::: #### Relay all emails, even those from domains managed by YunoHost If you have plenty of trust in your SMTP relay, have a second IMAP server that you wish or are forced to use instead of the YunoHost one, you can choose to relay all emails even those from domain names managed by YunoHost by commenting the following two lines in `/etc/postfix/main.cf` : ```text #virtual_mailbox_domains = ldap:/etc/postfix/ldap-domains.cf #virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf,ldap:/etc/postfix/ldap-groups.cf ``` ### Step 4: Check your setup You can check your setup by sending emails and try if everything works. Some of the SMTP relay will give you insights about the emails you send so that can also be a good way to check that everythings works as needed. Of course, you can always have a try with [mail-tester.com](https://www.mail-tester.com/) to check for any problem or discrepancy. ================================================ FILE: docs/admin/45.tutorials/55.moving_app_folder.mdx ================================================ --- title: Moving an app folder to a different storage location --- Applications folder are (*usually*) located in `/var/www/$appname` If an application folder is expected to get bigger because of the amount of data it contains, it might be relevant to move it to another storage (like an external hard drive). Here's a summary of how to do this the application WordPress. Here, is is assumed that [you already mounted the external hard-drive](/admin/tutorials/external_storage). #### 1. Move the entire WordPress folder to an external hard drive ```bash mv /var/www/wordpress /media/externalharddrive/ ``` #### 2. Create a symbolic link So that programs looking for files in /var/www/wordpress will actually take them from the harddrive ```bash ln -s /media/externalharddrive/wordpress /var/www/wordpress ``` #### 3. Tweak permissions (maybe?) After this, note that you may need to tweak the permissions of `/media/externalharddrive` so that `www-data` (or the user corresponding to the app) is able to read through the folder... Something like : ```bash chgrp www-data /media/externalharddrive chmod g+rx /media/externalharddrive ``` (but it depends on your exact setup... Please update this doc page if you figure out what to do exactly) ================================================ FILE: docs/admin/45.tutorials/65.sftp_on_apps.mdx ================================================ --- sidebar_label: Access apps via SFTP title: Give SFTP permission to edit an app --- In YunoHost permission management web admin interface, you can specify which user can access your system through SFTP. Go to : - Groups and permissions > Individual user permissions. - Click on add a permission and select SFTP However, those user are chrooted in their home directory for security reasons. If you want to give access to a specific apps through SFTP, here are additional steps to do after giving the SFTP permission in the web interface. In instructions below, - USER is the user to whom you wish to give permission to edit WordPress files. - `/var/www/wordpress/wp-config.php` must be replaced by the path your app config file. For example, for yeswiki (`/var/www/yeswiki/wakka.config.php`) ```bash mkdir -p /home/USER/apps/wordpress touch /home/USER/.nobackup mount --bind /var/www/wordpress /home/USER/apps/wordpress echo "/var/www/wordpress /home/USER/apps/wordpress none defaults,bind 0 0" >> /etc/fstab find /var/www/wordpress -type d -exec chmod g+s {} \; setfacl -R -m u:wordpress:rwX /var/www/wordpress setfacl -R -d -m u:wordpress:rwX /var/www/wordpress setfacl -m u:wordpress:r-- /var/www/wordpress/wp-config.php setfacl -R -m u:USER:rwX /var/www/wordpress setfacl -R -d -m u:USER:rwX /var/www/wordpress ``` Quick commands explanation : - `mkdir -p /PATH` creates a folder in the specified PATH - `touch` creates an empty file - `mount --bind` makes the contents of the source file or directory available at the target location without actually moving or copying the data. - `setfacl` set the file permissions ================================================ FILE: docs/admin/45.tutorials/90.freebox_storage.mdx ================================================ --- title: Use Freebox's storage (French ISP) --- This page is only relevant if you're using french ISP's « [Free](https://free.fr) »
Certaines Freebox [sont munies d'un disque dur connecté au réseau (NAS)](https://www.actusfree.fr/nas-freebox/) qui peut être utilisé comme espace de stockage depuis votre serveur. ## Utiliser le NAS de la Freebox Il faut installer le paquet `cifs-utils` ```bash sudo apt install cifs-utils ``` Il faut créer un point de montage (ici `/mount/freebox`) ```bash mkdir -p /mount/freebox ``` On monte le répertoire NAS par défaut avec les droits de lecture / écriture pour tous ```bash sudo mount -t cifs //mafreebox.freebox.fr/Disque\ dur/ /mount/freebox -o guest,iocharset=utf8,file_mode=0777,dir_mode=0777 ``` ### Automatiser le montage Une ligne à ajouter à la fin du `/etc/fstab` : ```text //mafreebox.freebox.fr/Disque\040dur/ /mount/freebox cifs _netdev,guest,uid=monlogin,gid=users,iocharset=utf8 0 0 ``` Le `_netdev` signale que c'est un périphérique réseau, afin que le système ne le monte que s'il a accès au réseau. `guest` est le mode d'identification à la Freebox : pour une connexion authentifiée, placez vos identifiants dans un fichier sous la forme ```text username=your_user password=your_pass domain=FREEBOX ``` et remplacez `guest` par `credentials=/path/to/file` (c'est aussi possible de spécifier directement `username=xx,password=xx` dans le fstab, mais déconseillé pour des raisons de sécurité) `uid` et `gid` sont pour les id user et group auxquels appartiendra le répertoire une fois monté. Par défault (sur la Freebox V5 en tout cas), ils se retrouvent avec les uid/gid de 4242. Il est aussi possible de mettre des droits particuliers avec les paramètres `file_mode=0777,dir_mode=0777`. ================================================ FILE: docs/admin/45.tutorials/_category_.yaml ================================================ label: "📜 Tutorials" link: type: "generated-index" title: "📜 Tutorials" ================================================ FILE: docs/admin/50.troubleshooting/03.cleanup.mdx ================================================ --- title: Cleaning up space hide_table_of_contents: true --- If your system runs out of space, you may an emergency option to get back some bit of space, and investigate what's taking up space ## Execute the basic-space-cleanup tool One may use the following command, to perform basic space cleanup (apt, journalctl, logs, ...) : ```bash sudo yunohost tools basic-space-cleanup ``` Additionaly, you may want to cleanup YunoHost operation logs if they are taking too much space, cf [this issue](https://github.com/YunoHost/issues/issues/2329). ## Explore what's taking up space Install `ncdu`: ```bash sudo apt install ncdu ``` Then use it to scan the filesystem and have a dynamic, browsable report of what's using space: ```bash ncdu / ``` or `ncdu /var/`, for example to scan only `/var/` ================================================ FILE: docs/admin/50.troubleshooting/05.fail2ban.mdx ================================================ --- title: IP address unban hide_table_of_contents: true --- **Fail2Ban** is an intrusion prevention software that protects computer servers against brute-force attacks. It monitors certain logs and will ban IP addresses that show brute-force-like behavior. In particular, **Fail2Ban** monitors `SSH` connection attempts. After 5 failed SSH connection attempts, Fail2Ban will ban the IP address from connecting via SSH for 10 minutes. If this address fails several times, it might get banned for a week. ## Unban an IP address To unblock an IP address, you must first access your server by some means (for example from another IP address or from another internet connection than the banned one). Then, look at the **Fail2Ban’s log** to identify in which `jail` the IP address has been banned: ```bash sudo tail /var/log/fail2ban.log 2019-01-07 16:24:47 fail2ban.filter [1837]: INFO [sshd] Found 11.22.33.44 2019-01-07 16:24:49 fail2ban.filter [1837]: INFO [sshd] Found 11.22.33.44 2019-01-07 16:24:51 fail2ban.filter [1837]: INFO [sshd] Found 11.22.33.44 2019-01-07 16:24:54 fail2ban.filter [1837]: INFO [sshd] Found 11.22.33.44 2019-01-07 16:24:57 fail2ban.filter [1837]: INFO [sshd] Found 11.22.33.44 2019-01-07 16:24:57 fail2ban.actions [1837]: NOTICE [sshd] Ban 11.22.33.44 2019-01-07 16:24:57 fail2ban.filter [1837]: NOTICE [recidive] Ban 11.22.33.44 ``` Here, the `11.22.33.44` IP address has been banned in the `sshd` and `recidive` jails. Then deban the IP address with the following commands: ```bash sudo fail2ban-client set sshd unbanip 11.22.33.44 sudo fail2ban-client set recidive unbanip 11.22.33.44 ``` ## Whitelist an IP address If you don’t want a "legitimate" IP address to be blocked by **YunoHost** anymore, then you have to fill it in the whitelist of the `jail` configuration file. When updating the **Fail2Ban** software, the original `/etc/fail2ban/jail.conf` file is overwritten. So it is on a new dedicated file that we will store the changes. They will thus be preserved over time. 1. Start by creating the new jail configuration file which will be called `yunohost-whitelist.conf`: ```bash sudo touch /etc/fail2ban/jail.d/yunohost-whitelist.conf ``` 2. Edit this new file with your favorite editor: ```bash sudo nano /etc/fail2ban/jail.d/yunohost-whitelist.conf ``` 3. Paste the following content into the file and adapt the IP address `XXX.XXX.XXX.XXX`: ```bash [DEFAULT] ignoreip = 127.0.0.1/8 XXX.XXX.XXX.XXX #<= the IP address (you can put more than one, separated by a space) that you want to whitelist ``` 4. Save the file and reload the Fail2Ban configuration: ```bash sudo fail2ban-client reload ``` Congratulations, no more risks of banning yourself from your own YunoHost server! ================================================ FILE: docs/admin/50.troubleshooting/10.change_root_password.mdx ================================================ --- title: Changing root's password hide_table_of_contents: true --- In the past, YunoHost had a special "`admin`" user in addition to `root`. This is not the case anymore, and each user admin password can be changed via the regular process. `root`, a.k.a "god on the machine", still exists however, and being able to access the root account can sometimes be useful. For example, because LDAP (the user database powering YunoHost account) is broken. In this case, you may be able to connect to root via SSH *from the local network*, via a direct screen/keyboard access, or via a rescue console provided by your VPS provider - depending on the nature of your server. ## Using the web administration interface First, connect to your web administration. Then go to Tools > YunoHost settings > Security tab > Change root password ## Using the command line interface ```bash yunohost tools rootpw ``` ================================================ FILE: docs/admin/50.troubleshooting/15.noaccess.mdx ================================================ --- title: Get access back into YunoHost --- There are several reasons that could lead to one administrator's access being partially or completely blocked off their YunoHost server. In numerous cases, one of the access methods is blocked, but others are not. This page will help you diagnose the issue, get back access, and if needed repair your system. Most common causes are listed first, so follow the tutorial from top to bottom. ## You have access to the server with its local IP address, but not its domain name ### If you are self-hosted at home: fix ports forwarding Check that you are getting access to the server by using its public IP (you can find at [https://ip.yunohost.org](https://ip.yunohost.org). If this does not work: - Make sure you have [set up forwarding](/admin/get_started/post_install/port_forwarding) - Some ISP routers do not support *hairpinning*, which prevents you from reaching your server by its domain name from within your local network. If so, you can use one of the following workaround: - use a cellular connection (4/5G) - tweak your `/etc/hosts` file on each of your client devices - add YunoHost's local IP as DNS resovler in your router (usually in the DHCP section) and open port `53` (UDP) in YunoHost's firewall, making sure to **not** enable UPnP forwarding. (Do **not** open port 53 on your router) ### Configure DNS records :::tip This is not a problem if you are using a domain from `nohost.me`, `noho.st` or `ynh.fr`) ::: You have to configure your [DNS records](/admin/get_started/post_install/dns_config) (at least `A` records, and `AAAA` if you have an IPv6 connection). You can check that the DNS records are correct by comparing the results given by [this service](https://www.whatsmydns.net/) with the [IP given by our service](https://ip.yunohost.org). ### Other probable causes - You domain `noho.st`, `nohost.me`, or `ynh.fr` is unreachable following a failure on YunoHost's infrastructure. Check the [forum](https://forum.yunohost.org/) for announcements or people posting about the same issue. - Your domain name may be expired. Check that on your registrar's client panel, or by using the command `whois yourdomain.tld`. - You have a dynamic IP address. In that case, you need to set up a script or a client that takes care of regularly update it. Refer to the page on [DNS with a dynamic IP](/admin/tutorials/domains/dns_dynamicip) to see how. You can also use a domain `nohost.me`, `noho.st` or `ynh.fr` that includes this features. ## You are getting a certificate error that prevents you from reaching the webadmin - A certificate error may be displayed if you have made a typo in the address bar of your browser. - If you have just installed your server, or just installed a new domain, it uses a self-signed certificate. In that case, it is possible and understandable to add a *temporary* security exception so that you can [install a Let's Encrypt certificate](/admin/domains/certificate), provided you have a secure Internet connection. ## You have access via SSH but not via the webadmin, or inversely ### You are trying to log in with SSH as `root` instead of `admin` user By default, SSH connection has to be made as `admin`. It possible to log into the server as `root` *only from the local network of the server*. If your server is a VPS, the web console or VNC provided by VPS providers may work. If you are running `yunohost` commands in the CLI as `admin`, you have to call them with `sudo` before (for example `sudo yunohost user list`). You can also become `root` by running `sudo su`. ### You have been temporarily banned Your YunoHost server includes a service, Fail2ban, which automatically bans IPs that fail several times in a row to log in. In some cases it can be software (e.g. Nextcloud client) that are confifured with an old password, or a user who has the same IP as you have. If you have been banned while trying to access a web page, and only web pages are unreachable, you may have access to your server via SSH. Similarly, if you have been banned from SSH, webadmin access may work. If you have been banned from both SSH and webadmin, you can try to reach your server through another IP address. For example through the cellular network of your phone, a VPN, Tor, or another proxy. See also : [unban an IP on Fail2Ban](/admin/troubleshooting/fail2ban) :::note Ban are usually 10 to 12-minute-long, and on IPv4 only. ::: ### NGINX web server is broken Maybe the NGINX web server is out of order. You can check that [trough SSH](/admin/command_line) with the command `yunohost service status nginx`. If it is failing, check that its configuration is correct by running `nginx -t`. If it is indeed broken, it may be due to the installation or removal of a low-quality app... If you need support, [ask for it](/community/help). The NGINX or SSH servers may have been killed due to a lack of storage space, RAM, or swap. - Try restarting the service with `systemctl restart nginx`. - You can check used storage with `df -h`. If one of your partitions is full, you need to identify what fills it and make room. You can use `ncdu` command (install it with `apt install ncdu`) to browse from the root directory: `ncdu /` - You can check RAM and swap usage with `free -h`. Depending on the result, it may be necessary to optimize your server to use less RAM (removal of heavy or unused apps...), add more RAM or add a swap file. ### Your server is reachable by IPv6, but not IPv4, or inversely You can check that by `ping`ing it: ```bash ping -4 yourdomain.tld # or its IPv4 ping -6 yourdomain.tld # or its IPv6 ``` If one of the two is working, use it to connect by SSH or the webadmin. If none are working, you need to resolv your connection issue. In some cases, an update of your router may have enabled IPv6 and DNS configuration may be disrupted. ## Webadmin is working, but some web apps are returning 502 errors It is highly probable that the underlying service for these apps is failing (e.g. PHP apps requiring `php7.0-fpm` or `php7.3-fpm`). You can then try to restart the services, and/or ask for [help](/community/help) ## You have lost your admin password, or the password is seemingly wrong If you can reach the webadmin login page (force reload with `CTRL + F5` to be sure), and you cannot log in, your password is probably wrong. If yoy are sure of your passord, it may be due to the `slapd` service failing. If that's the case, log into the server by SSH as `root`. - If your server is at home, you most likely have access to the local network. From this network, you can follow the [SSH instructions](/admin/command_line)`. - If your server is a VPS, your provider may offer a web console. Once logged in, you have to check the state of the service with `yunohost service status slapd` and/or reset your admin password with `yunohost tools adminpw`. If this is still failing, on a VPS you may be able to reboot in rescue mode. Do not hesitate to ask for [help](/community/help) :::warning To be completed ::: ## Your VPN expired or does not connect any more If you have a VPN with fixed IP, maybe it has expired, or the provider's infrastructure is failing. In that case, contact your VPN provider to renew it and update the parameters of the VPN Client app. Meanwhile, try reaching your server if it is at home, by: - its local IP, using one of the method listed [on the corresponding page](/admin/get_started/post_install/find_ip) - reaching it at `yunohost.local`, assuming your client supports the Bonjour protocol (or `yunohost-2.local`, etc. depending on how many YunoHost servers are on your network) :::warning To be completed ::: ## Your server does not boot In some cases your server may be stuck at boot. It may come from a new, buggy, kernel. Try changing to another kernel on the boot screen (via VNC for VPS). If you are in "rescue" mode with `grub`, it may be due a misconfiguration of `grub`, or a corrupted drive. In that case, access the storage drive from another system (your provider's "rescue" mode, live USB drive, read the SD or drive on another computer) and try to check partitions integrity with `smartctl`, `fsck`, and `mount`. If disks are corrupted or hard to mount, you have to save your data and maybe reformat, reinstall, and/or change the drive. If you succeed in mounting the drive, you can use `systemd-nspawn` to access its database. Otherwise, run `grub-update`, `grub-install` again with `chroot` or with `systemd-nspawn`. ## VNC or screen access does not work It may be due hardware issue on your server, or with the hypervisor if it is on a VPS. If you are renting your server, contact the support of your provider. Otherwise, try fixing your machine by replacing failing components. ================================================ FILE: docs/admin/50.troubleshooting/20.ipv6.mdx ================================================ --- title: Setting up IPv6 hide_table_of_contents: true --- IPv6 may work out of the box in many cases. But in some cases or some specific provider, you may need to tweak things manually to enable IPv6. ## With a VPS from OVH OVH gives one IPv4 address and one IPv6 address for VPS but by default, only IPv4 is OK. Please check [The OVH documentation](https://docs.ovh.com/gb/en/vps/configuring-ipv6/). ### Configure the DNS server Also check [the documentation for subdomains](/admin/tutorials/domains/dns_subdomains). ### Configure the server On the OVH panel, you will copy 3 elements: - the IPv6 address - the IPv6 gateway address - the IPv6 prefix. On OVH's VPS SSD, prefixes are `/128` because you have only *one* IPv6 address. On your VPS, create a backup of the network configuration with : `cp /etc/network/interfaces ~/interfaces` in home directory. Then, you can edit the configuration file (`/etc/network/interfaces`) with the following. :::note In this example, it is assumed that your network interface is `eth0`. If it's different (check with `ip a`) you need to adapt the example below. ::: ```text iface eth0 inet6 static address netmask post-up /sbin/ip -6 route add dev eth0 post-up /sbin/ip -6 route add default via dev eth0 pre-down /sbin/ip -6 route del default via dev eth0 pre-down /sbin/ip -6 route del dev eth0 ``` Now, save the file and restart the network service with : `service networking restart`. (TODO : ideally we should find a way to validate the content of the configuration, otherwise it could fuck up the network stack and get disconnected from the VPS ?) Check your configuration with these commands : - `ip a` to display network interfaces and addresses - `hostname -I` to display the system IP addresses - try to ping an IPv6 server (for example you can use `ping6 ip6.yunohost.org`) - try to ping your server from your PC (assuming your PC has IPv6 enabled) If it's ok, it's ok ! ================================================ FILE: docs/admin/50.troubleshooting/25.blacklist_forms.mdx ================================================ --- title: Removing your server’s IP/domain from antispam listings --- For various reasons, your IP or domain may end up in blocklists and get rejected by specific email providers, or anti-spam services. If you receive an alert from the diagnosis tool, clicking Details should point you to the appropriate form to contest the listing and get your server removed from it. ## Test your server To check your Email deliverability, YunoHost provide automatic tests in the Diagnosis section of the webadmin, checking the presence of your server on blocklists / RBL (Realtime Blackhole List), as well as compliance with other standard practice demonstrating that your server is legitimately sending email (as opposed to infected machines used by hackers/spammers/botnet), such as DNS records and reverse DNS configuration. The diagnosis will also indicate if there is a suspiciously high number of emails pending in the send queue. Complementary to these checks, you may be interested in the following services: - by sending an email to the random test address indicated on [Mail tester](https://www.mail-tester.com) ... though most of the checks are covered by YunoHost's diagnosis. - by checking your server's public IP on : [MultiRBL Valli](https://multirbl.valli.org/) or [Whatismyip](https://whatismyipaddress.com/blacklist-check) ## Checking email-related logs This command can help you to summarize which emails sent by your server got refused by other SMTP servers, and why: ```bash cat /var/log/mail.log | grep "deferred" | sed -E "s/(:[0-9][0-9]).+.+dsn/\terror/g" | sed -E "s/, status=deferred \(/ /g" | sed -E "s/\)$//g" ``` You might want to compare this to [the list of SMTP return codes](https://en.wikipedia.org/wiki/List_of_SMTP_server_return_codes). ## Specific email providers YunoHost is only able to test generic blocklists using the DNS RBL mechanism. However, Gmail, Microsoft, Yahoo or Free maintains their own blocklisting mechanism. In some situation, you may need to contact their teams through dedicated forms or use dedicated tools. ### Microsoft - No way to test easily IP reputation - [Microsoft guide for postmaster](https://sendersupport.olc.protection.outlook.com/pm/) - [Information about SMTP return code from Microsoft](https://sendersupport.olc.protection.outlook.com/pm/troubleshooting.aspx#Codes) - Reputation Management tools : - [Junk Email Reporting Program (JMRP)](https://postmaster.live.com/snds/JMRP.aspx) - [Smart Network Data Services (SNDS)](https://postmaster.live.com/snds/index.aspx) - [Get support form for deliverability issues](https://support.microsoft.com/supportrequestform/8ad563e3-288e-2a61-8122-3ba03d6b8d75) (Sadly you need a Microsoft account :/ ) ### GMail - No way to test easily IP reputation - [Google guide for postmaster](https://support.google.com/a/topic/1354753) - [Information about SMTP return code from Google](https://support.google.com/a/answer/3726730) - Reputation Management tools : [Google Postmaster Tools](https://postmaster.google.com) - [Get support form for deliverability issues](https://support.google.com/mail/contact/bulk_send_new) ### Yahoo - No way to test easily IP reputation - [Yahoo guide for postmaster](https://senders.yahooinc.com/best-practices) - [Information about SMTP return code from Yahoo](https://senders.yahooinc.com/smtp-error-codes) - Reputation Management tools : [Complaint Feedback Loop](https://io.help.yahoo.com/contact/index?page=contactform&locale=en_US&token=Zh%2FBBVqXzLHlIbokbUqVWTUbuuQeXGkGnZzhKR2JQ4O6mMQdy9JSWdtWFXvjthcYCRj9bUIFfycOfG%2B4GOHPHoOGa8HwDO2%2B0kYRtTcdR8Nja5P9HWkKh3VWfS3pyu4UdjhvwG%2BBCvnYFl5dToDK%2Fw%3D%3D&selectedChannel=email-icon) - [Get support form for deliverability issues](https://senders.yahooinc.com/contact) ### Free (french ISP) You can find a tool to test your IP, advices, explanation of error code and a way to contact Free on [this page](https://postmaster.free.fr/) ## Receving alerts about emails sent without SPF or DKIM If you use your own domains and think that some mails are sent by unauthorized servers (so without SPF/DKIM), you can obtain reports from other mail server by declaring an email address in the DMARC DNS record: ```text _dmarc.DOMAIN 3600 IN TXT "v=DMARC1; p=none; fo=1; rua=mailto:example@domain.tld!10m" ``` ================================================ FILE: docs/admin/50.troubleshooting/index.mdx ================================================ --- title: 🐞 Troubleshooting --- This section contains specific tips to troubleshoot common issues. If you are looking for help, consider having a look at [the forum](https://forum.yunohost.org/), [the support chat room](/community/chat_rooms) and [the 'Help' page](/community/help). ================================================ FILE: docs/admin/80.advanced/40.torhiddenservice.mdx ================================================ --- sidebar_label: Configure Tor Hidden Service title: Using YunoHost as a Tor Hidden Service --- :::warning This tuto is not finished ! Some data could leak with this setup like the main domain of your YunoHost, so it's not a "Hidden Service". See [The official Tor hidden service documentation](https://www.torproject.org/docs/tor-hidden-service.html.en). ::: ###  Installing Tor ```bash apt install tor ``` ###  Configuring our hidden service Edit `/etc/tor/torrc`, and add these lines: ```text HiddenServiceDir /var/lib/tor/hidden_service/ HiddenServicePort 80 127.0.0.1:80 HiddenServicePort 443 127.0.0.1:443 ``` ###  Restart Tor ```bash service tor restart ``` ### Get your Tor Hidden Service hostname ```bash cat /var/lib/tor/hidden_service/hostname ``` Your domain looks like *random123456789.onion* ### Add the .onion domain to YunoHost ```bash yunohost domain add random123456789.onion ``` ### Avoid SSO redirection (optional) If you want to avoid being redirected to the SSO portal at login, you can deactivate SSOwat for this specific tor domain, by editing the file `/etc/nginx/conf.d/random123456789.onion.conf` and commenting the following line (two times): ```text #access_by_lua_file /usr/share/ssowat/access.lua; ``` ### Check for errors in NGINX configuration ```bash nginx -t ``` ### Restart NGINX ```bash service nginx restart ``` ================================================ FILE: docs/admin/80.advanced/45.certificate_custom.mdx ================================================ --- title: Custom certificates --- :::warning Since version 2.5, YunoHost integrates Let's Encrypt certificates automated management. You can easily and freely [install a Let's Encrypt certificate](/admin/domains/certificate). The following document describes the steps for installing a paid certificate from a certification authority (**Gandi**, **RapidSSL**, **StartSSL**, **Cacert**). ::: Some changes have taken place which impact the procedures indicated below: - Metronome group is no longer used directly but ssl-cert. - A `/etc/yunohost/certs/DOMAIN.LTD-history/stamp` directory is used to keep each configuration created and a symlink is created. ### Adding a signed certificate by an authority (other than Let's Encrypt) After the certificate creation with your registration authority, you must have a private key, the key file, and a public certificate, the crt file. :::warning Note that the key file is very sensitive, it is strictly personal and must be very well secured. ::: These two files should be copied to the server, if they are not already there. ```bash scp CERTIFICATE.crt admin@DOMAIN.TLD:ssl.crt scp KEY.key admin@DOMAIN.TLD:ssl.key ``` From Windows, scp can be used with Putty, by downloading the tool [pscp](http://the.earth.li/~sgtatham/putty/latest/x86/pscp.exe) ```bash pscp -P 22 CERTIFICATE.crt admin@DOMAIN.TLD:ssl.crt pscp -P 22 KEY.key admin@DOMAIN.TLD:ssl.key ``` As soon as the files are on the server, the rest of the work will be done on it. In [ssh](/admin/command_line) or locally. First, create a folder to store the obtained certificates. ```bash sudo mkdir /etc/yunohost/certs/DOMAIN.TLD/ae_certs sudo mv ssl.key ssl.crt /etc/yunohost/certs/DOMAIN.TLD/ae_certs/ ``` Then, go to the parent folder to continue. ```bash cd /etc/yunohost/certs/DOMAIN.TLD/ ``` As a caution, back up the certificates of origin from YunoHost. ```bash sudo mkdir yunohost_self_signed sudo mv *.pem *.cnf yunohost_self_signed/ ``` Depending on the registration authority, intermediate and root certificates must be obtained. #### StartSSL ```bash sudo wget http://www.startssl.com/certs/ca.pem -O ae_certs/ca.pem sudo wget http://www.startssl.com/certs/sub.class1.server.ca.pem -O ae_certs/intermediate_ca.pem ``` #### Gandi ```bash sudo wget https://www.gandi.net/static/CAs/GandiStandardSSLCA2.pem -O ae_certs/intermediate_ca.pem ``` #### RapidSSL ```bash sudo wget https://knowledge.rapidssl.com/library/VERISIGN/INTERNATIONAL_AFFILIATES/RapidSSL/AR1548/RapidSSLCABundle.txt -O ae_certs/intermediate_ca.pem ``` #### Cacert ```bash sudo wget http://www.cacert.org/certs/root.crt -O ae_certs/ca.pem sudo wget http://www.cacert.org/certs/class3.crt -O ae_certs/intermediate_ca.pem ``` Intermediate and root certificates must be combined with the obtained certificate to create a unified certificate chain. ```bash cat ae_certs/ssl.crt ae_certs/intermediate_ca.pem ae_certs/ca.pem | sudo tee crt.pem ``` The private key must be converted to `.pem` format. ```bash sudo openssl rsa -in ae_certs/ssl.key -out key.pem -outform PEM ``` To ensure the certificates syntax, check the files contents. ```bash cat crt.pem key.pem ``` The certificates and private key should look like this: ```text -----BEGIN CERTIFICATE----- MIICVDCCAb0CAQEwDQYJKoZIhvcNAQEEBQAwdDELMAkGA1UEBhMCRlIxFTATBgNV BAgTDENvcnNlIGR1IFN1ZDEQMA4GA1UEBxMHQWphY2NpbzEMMAoGA1UEChMDTExC MREwDwYDVQQLEwhCVFMgSU5GTzEbMBkGA1UEAxMSc2VydmV1ci5idHNpbmZvLmZy MB4XDTA0MDIwODE2MjQyNloXDTA0MDMwOTE2MjQyNlowcTELMAkGA1UEBhMCRlIx FTATBgNVBAgTDENvcnNlIGR1IFN1ZDEQMA4GA1UEBxMHQWphY2NpbzEMMAoGA1UE ChMDTExCMREwDwYDVQQLEwhCVFMgSU5GTzEYMBYGA1UEAxMPcHJvZi5idHNpbmZv LmZyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSUagxPSv3LtgDV5sygt12 kSbN/NWP0QUiPlksOkF2NkPfwW/mf55dD1hSndlOM/5kLbSBo5ieE3TgikF0Iktj BWm5xSqewM5QDYzXFt031DrPX63Fvo+tCKTQoVItdEuJPMahVsXnDyYHeUURRWLW wc0BzEgFZGGw7wiMF6wt5QIDAQABMA0GCSqGSIb3DQEBBAUAA4GBALD640iwKPMf pqdYtfvmLnA7CiEuao60i/pzVJE2LIXXXbwYjNAM+7Lov+dFT+b5FcOUGqLymSG3 kSK6OOauBHItgiGI7C87u4EJaHDvGIUxHxQQGsUM0SCIIVGK7Lwm+8e9I2X0G2GP 9t/rrbdGzXXOCl3up99naL5XAzCIp6r5 -----END CERTIFICATE----- ``` Finally, secure your certificate files. ```bash sudo chown root:ssl-cert crt.pem key.pem sudo chmod 640 crt.pem key.pem sudo chown root:root -R ae_certs sudo chmod 600 -R ae_certs ``` Now the certificates (two files with the extension `.pem`) must be copied in `/etc/yunohost/certs/DOMAIN.TLD`. ```bash cp ae_certs/*.pem ./ ``` Reload NGINX configuration to take into account the new certificate. ```bash sudo service nginx reload ``` Your certificate is ready. However, you can ensure that it is in place by testing the certificate using the [geocerts](https://www.geocerts.com/ssl_checker). ================================================ FILE: docs/admin/80.advanced/70.chatons.mdx ================================================ --- title: Create a CHATONS ↗ description: "See the tutorial on chatons.org" --- import {DocumentedHardRedirect} from '@site/src/components/HardRedirects'; ================================================ FILE: docs/admin/80.advanced/_category_.yaml ================================================ label: "👾 Advanced" link: type: "generated-index" title: "👾 Advanced" ================================================ FILE: docs/admin/_category_.yaml ================================================ label: Administration guide link: type: generated-index title: Administration guide slug: admin description: Learn about self-hosting, how to install and use YunoHost ================================================ FILE: docs/admin/index.mdx ================================================ --- title: "Welcome!" sidebar_position: 0 hide_title: true hide_table_of_contents: true --- #
YunoHost logo This is the documentation for YunoHost,
an **operating system** aiming to **simplify server administration**!
If you are an **impatient power user**, you may want to try YunoHost, or jump right away to install:

Are you **new to self-hosting and servers in general**? We recommend taking it slow and go through the pages presenting [self-hosting](/admin/about_self_hosting), the [different modes](/admin/get_started/methods) and [other](/admin/get_started/why_should_you_not_host_yourself) [things](/category/providers) you should know prior to jumping into the action! Are you **already using YunoHost**? You may want to get in touch with the community or reach for help:
Finally, you can **support the project** or get involved in [different ways](/dev):
================================================ FILE: docs/community/05.faq.mdx ================================================ --- title: Frequently Asked Questions description: "Informations about the project" --- ### Under which license is YunoHost distributed? YunoHost packages are under free licenses GNU AGPL v.3. YunoHost is based on Debian, so on Debian's components' licenses. Applications and applications packages have their own licenses. ### What's YunoHost goal? We believe that decentralizing the Internet, and empowering people to take control and responsibility back over their own data and services, is a crucial issue to guarantee a free and democratic society. The YunoHost project aims to democratize self-hosting. It provides a software that aims to make it easy for people to run and administer their own server, with minimal knowledge and required time. ### But what does YunoHost exactly *do*? YunoHost is a distribution, in the sense that it is a purpose-specific version of GNU/Linux-Debian and it distributes a set of application via its catalog, but it is also "just" a program that automatically configures Debian and does most of the hard work for you. For instance, if you wanted to install WordPress, you would need to type a bunch of commands to create some users, setup a web server, setup a SQL server, download the WordPress archive, uncompress it, configure the web server, configure the SQL database, and finally configure WordPress. YunoHost handles the technical details and "types all these commands for you", so that you can focus on what really matters. More info on [this page](/admin/what_is_yunohost)! ### Can I host my own personal website with YunoHost? Yes! Have a look at the [Custom Web app](https://github.com/YunoHost-Apps/my_webapp_ynh). It provides an "empty shell" : after installing it, just upload your files (via SSH/SCP or SFTP) to the right location. You can have PHP and a SQL database if you need. ### Can I host many independent websites with different domain names? Yes! YunoHost is multi-user and multi-domain. Some applications like *WordPress* or *My webapp*, are multi-instances, which means that the application can be installed many times. ### Why can't I access applications via the IP address? The [SSO](https://github.com/Kloadut/SSOwat/) (single sign-on) cannot properly authenticate users when they access your server with only its IP. If you really can't properly configure the DNS, you can temporarily work around it by [modifying the `hosts` file](/admin/tutorials/domains/dns_local_network#configure-hosts-file-on-client-workstation) on your computer. ### What's YunoHost's business model? YunoHost is maintained by volunteers working on their free time. The project regularly receives donations which pay for the servers' bills and stickers. The project received (or continues to receive) grants from organization like [NLnet](https://nlnet.nl/) or [CodeLutin](https://www.codelutin.com/) to fund specific developments Donations to the project are increasing, and we are in the process of defining the way we redistribute this money to main contributors and therefore help make the project sustainable. Additionally, some contributors do have professional activities based (at least partially) on YunoHost. ### Can I donate to the project? Yes, you can! YunoHost needs money to pay servers and domain names. We would also like contributors to be able to spend more time contributing rather than looking for jobs. You can donate using [our donation interface](https://donate.yunohost.org) If you can, you can also make in-kind contributions, like servers (some of our infrastructure relies on servers from a few associations). ### How can I contribute to the project? There are [many ways to contribute](/dev :). Don't hesitate to come talk to us about your ideas! A common misconception for newcomers in free software projects is to think that they are "not skilled enough". In practice, nobody is "skilled" :). What really matter is: [liking what you do](https://www.youtube.com/watch?v=zIbR5TAz2xQ&t=113s), being friendly with other human beings, being patient and stubborn with machines, and having some free time. Other than that, just doing what you can is already awesome! ### How is the YunoHost project organized? It is described in [this document](https://github.com/YunoHost/project-organization/) :). ### Will you port YunoHost to [insert favorite distro]? If you care about distrowars, or think 'Debian is dirty', then YunoHost is not for you. YunoHost is aimed at non-tech people who just want their server to work. Debian has its flaws, but it's (one of?) the most widely known and used distribution for servers. It's stable. Most self-hosted software are one way or another compatible with Debian. It's easily hackable by anybody who's been doing a bit of CLI on their personal Ubuntu/Mint computer. There is no killer feature in other distributions that makes it relevant for YunoHost to switch or port to it. If this does not convince you, there are other projects running on other distributions or with different philosophies. ### I checked how apps packaging work. Why are you reinventing [insert favorite package format]? People have been tempted to compare YunoHost packages to traditional package managers (such as Debian's `.deb`), which hold a different purpose. Traditional package managers are meant to install low-level purpose of installing files, commands, programs and services on the system. It is often your duty to configure them properly, simply because there is no standard server setup. Typically, web apps requires a lot of configuration because they rely on a web server and a database (and the single sign-on). YunoHost manages high-level abstractions (apps, domains, users...) and defines a standard setup (NGINX, Postfix, Metronome, SSOwat...) and, because of this, can handle the configuration for the user. ### When will [this feature] be implemented? Why isn't [that app] packaged yet? I cannot believe you do not do [this] yet! We do not give timelines. We are a bunch of volunteers working on our free time to maintain and develop YunoHost. We have no product owner or project manager handling resources, we are not a business. We do what we can, because we love this software, when we can. If you really want to have a feature implemented or documented, or an app packaged, [consider contributing yourself](/dev! We would love helping you get started. ### What is YunoHost's policy regarding the apps included in the official catalog ? See [this page](/dev/packaging/policy) ### Why won't you include [feature X] ? YunoHost is primarily designed for not-so-tech-savvy users and aims to remain relatively simple in terms of UI/UX. At the same time, the project has limited time and energy available to be maintained and developed. Therefore we may lower the priority of features, or refuse entirely the inclusion of features, based on the criteria that they: - would only be meaningful for advanced / power-users stuff which is out of the scope of the project ; - would introduce too much UI/UX bloat ; - would only cover unrealistic threat models ; - would be there only to satisfy purists ; - or overall would not be worth it in terms of development/maintenance time/energy for what it brings to the project. ================================================ FILE: docs/community/10.help.mdx ================================================ --- title: Looking for help? --- import ReactPlayer from 'react-player' ## How to ask for help Come on [the forum](/community/forum) or the [chat rooms](/community/chat_rooms)! But first, please follow these guidelines : :::tip - **[Be courteous and patient](#be-courteous-and-patient)** - **[Explain the context](#explain-the-context)** of your request in a complete but concise way. - **[Share the error logs with YunoPaste](#show-errors-and-logs)** ::: :::danger - Do not ask about your attempted solution but rather your actual problem (see [the XY problem](https://xyproblem.info/)). - [Avoid phrases like](#do-not-be-vague) "server does not want", "the app does not load", or other meaningless sentences. - Do not trim error messages, but do not paste a wall of illegible unformatted code either. (Use [YunoPaste](https://paste.yunohost.org)) - Do not ask your question like a poll ("does anyone else succeeded in...?"). ::: ## You've found a bug ? Please report bugs on our bugtrackers or contact the developers:
{' '} {' '}
## Do's ### Be courteous and patient Help in the chatrooms or on the forum is given by our users and contributors, all volunteers. You may be in a hurry, you may be exhausted by fruitless trials or overwhelmed by unpleasant emotions... Have a break, have a sip of your preferred soothing beverage, breathe and once you've recovered your composure continue reading. We need you in a good mindset to help you. ### Ask in the right place Support is only available on [the forum](https://forum.yunohost.org?target=_blank) or our [chatrooms](/community/chat_rooms). We are also on Mastodon, but we do not offer help on this platform. On the forum, make sure you open your request in the proper category, to maximize your chances of receiving appropriate help: - [Support](https://forum.yunohost.org/c/support/6?target=_blank) for issues when setting up or using YunoHost itself; - [Support apps](https://forum.yunohost.org/c/apps/11?target=_blank) for issues when setting up or using apps. To allow us to help you on the forum, you absolutely need to fill in the Support request template, it will be displayed upon message creation. ### Explain the context Your request needs to be stated in a complete but concise way. Explain plainly what you want to achieve and in what manner it is not working for you. Don't hesitate to provide any information that may be relevant, even things that may seem obvious, as the person(s) who will be trying to help you may need this information. ### Show errors and logs This is absolutely paramount if YunoHost or a command fails. It always explains why, through a single error code or a full wall of seemingly illegible text. For the latter, YunoHost provides green "Share with YunoPaste" buttons when something fails or in the Services page of the webadmin. Click on it, it will open a new web page, and you can then share its URL. We recommend that you share these logs in their entirety using the link generated by YunoPaste. Avoid extracts from the logs, as decisive information may be elsewhere. Also, avoid copying and pasting them into the forum, as it's unpleasant to go through them like that, share the YunoPaste link.
![YunoPaste button](/img/yunopaste.png)

If your issue is not related to an installation or upgrade process but instead is about an app failing load properly, ideally you can investigate with your browser console (opened with the F12 key): its Network tab can show you HTTP error codes (including the infamous 403, 404, 500...), and its Console can output errors too. Screenshots are most welcome. ## Don'ts ### Avoid the infamous [XY Problem](https://xyproblem.info/) In a nutshell, explain the root cause of your issue. You may share your attempted solution, but explaining ***why*** you need that potential solution is more important. ### Do not be vague Do not assume we understand what you are talking about, do not take shortcuts, do not rephrase, do not simplify, do not trim the error messages. Do not write "it does not work", "it does not want", "it does not load", ["computer says no"](https://en.wikipedia.org/wiki/Computer_says_no). Explain what is wrong, and how it is displayed onscreen. There is, for example, an important difference between a completely blank page and a blank page with a minimalistic error code. ### Do not beat about the bush No need to ask if you can ask. It is a support chat/forum, therefore yes, you can ask your question. Do not ask your question like a poll, as in "Did anyone managed to get app XY working?". If it is not working for you, then explain directly what issue you got, explain the context, share the logs. ### Do not be an asshole Access to the forum or the chatrooms is a courtesy that can be revoked. ================================================ FILE: docs/community/15.forum.mdx ================================================ --- title: Forum ↗ description: "The Forum for support and news" --- import {DocumentedHardRedirect} from '@site/src/components/HardRedirects'; ================================================ FILE: docs/community/20.chat_rooms.mdx ================================================ --- title: Chat rooms description: Chat rooms on Matrix for support and development --- Among other communication tools, YunoHost project use chat rooms to communicate. You could join those chat rooms using: - a [Matrix client](https://matrix.org/ecosystem/clients/) - a [XMPP client](https://xmpp.org/software/) - an [IRC Client](https://en.wikipedia.org/wiki/Comparison_of_Internet_Relay_Chat_clients) for example [KiwiIRC](https://web.libera.chat/#yunohost) (please note that the IRC room is deprecated, prefer Matrix). If you're using KiwiIrc, please change your username, as we got legions of `ynhuser`s. :::caution The IRC bridge is currently down. XMPP and Matrix are still bridged together, but IRC is probably way less active as most of the team coordinates via Matrix. ::: ## 🛟 Help and support chat room There is a [support](/community/help) chat room for YunoHost users mutual support and help. - Matrix: **[`#yunohost:matrix.org`](https://matrix.to/#/#yunohost:matrix.org)** - XMPP: **[`support@conference.yunohost.org`](xmpp:support@conference.yunohost.org?join)** - IRC: **`#yunohost`** on libera.chat ## ⚙️ Development chat room This is where contributors discuss "core" development of the YunoHost pieces such as the CLI/API, webadmin, the user portal, etc. - Matrix: **[`#yunohost-dev:matrix.org`](https://matrix.to/#/#yunohost-dev:matrix.org)** - XMPP: **[`dev@conference.yunohost.org`](xmpp:dev@conference.yunohost.org?join)** - IRC: **`#yunohost-dev`** on libera.chat ## 📦 Application packaging chat room This is where app packagers coordinate around app packaging, help each other, and monitor automatic tests results: - Matrix: **[`#yunohost-apps:matrix.org`](https://matrix.to/#/#yunohost-apps:matrix.org)** - XMPP: **[`apps@conference.yunohost.org`](xmpp:apps@conference.yunohost.org?join)** - IRC: **`#yunohost-apps`** on libera.chat ## 📝 Documentation chat room This is where people discuss and coordinate about documentation. Feel free to also ask questions about stuff that you would like to share such as tutorials, videos, presentations, ... or this can also be done on the forum. - Matrix: **[`#yunohost-doc:matrix.org`](https://matrix.to/#/#yunohost-doc:matrix.org)** - XMPP: **[`doc@conference.yunohost.org`](xmpp:doc@conference.yunohost.org?join)** - IRC: **`#yunohost-doc`** on libera.chat ================================================ FILE: docs/community/25.yunohost_project_organization.mdx ================================================ --- title: Project organisation ↗ description: "The human organization behind the code" --- import {DocumentedHardRedirect} from '@site/src/components/HardRedirects'; ================================================ FILE: docs/community/30.project_budget.mdx ================================================ --- title: Project budget description: "How is money handled" --- # Estimated budget for 2020/2021 ## Expected revenues - Donations: 3000€/year - Grant from NLNet: 20K€ ## Expected expenses - Development: 20K€ - Server renting: 500€ - VPS Scaleway: 20.33*12: 243.96€/year - VPS Digital O. (forum): 172.80€/year - Domain names: ~150€ - `nohost.me`: 11.99€HT/year - `ynh.fr`: 6.99€HT/year (to be confirmed with frju?) - `noho.st`: ~35€ TTC/year - `yunohost.org`: 13.99€HT/year - `yunohost.com`: 9.99€HT/year - `labriqueinter.net`: 12.49€HT/year - `internetcu.be`: 17.99€HT/year - Communication: ~400€ - Travel (e.g. to go to conferences): ~700€ - AG FFDN 2020: 225€ (en tout) - Event colibris: 150€ - FOSDEM ou autre conf: 300€ - Bank account fees: 7x12€ => ~100€ - Brique Camp: 500€ **Balance 2020-2021**: +650€ ================================================ FILE: docs/community/35.security_team.mdx ================================================ --- title: Security team description: "Did you find a vulnerability?" --- Contact the security team by mail: `security@yunohost.org`. We strongly advise you to encrypt your mail with GPG. Our public key is available on key servers. Below is our fingerprint ```bash gpg --fingerprint security@yunohost.org pub 4096R/17351899 2016-07-01 Empreinte de la clef = 6CBC 45EB A625 FBF3 513D 1227 749D 8972 1735 1899 uid YunoHost Security sub 4096R/446838AF 2016-07-01 ``` See [a gist on Github](https://gist.github.com/opi/4496024dc3ff29ab2e068fd57092ab7c) for other trustable fingerprint sources. ================================================ FILE: docs/community/40.press_kit.mdx ================================================ --- title: Media description: "Media and conferences" --- {/* :::note TODO: Add logo and kakemono file TODO: Add kakemono photo TODO: Add "About YunoHost" section TODO: Add email contact ::: */} ## Talks / conf - (EN) [BattleMeshV12 - YunoHost and the Internet Cube (Brique Internet)](https://www.battlemesh.org/BattleMeshV12/Events#YunoHost_and_the_Internet_Cube_.28Brique_Internet.29) - (EN) [FOSDEM 2019 - The operating system to build the decentralized Internet](https://cinema.yunohost.support/videos/watch/1eb49594-0283-4a01-8691-3817a3cb31e6) ([slides](https://github.com/YunoHost/yunohost-fosdem-2019)) - (FR) [Capitole du libre 2018 - YunoHost: un des chemins vers la décentralisation - Bram](https://www.youtube.com/watch?v=OEXEStoOYpw) ([slides](https://psycojoker.github.io/yunohost-cdl-2018/)) - (FR) [Journées du logiciel libre 2018 - YunoHost : vers l’auto-hébergement et au-delà - Bram](https://www.videos-libr.es/videos/watch/45b48b1e-1b10-4e09-b29a-a404bd42c5d0) ([slides](https://psycojoker.github.io/yunohost-jdll-2018/)) - (FR) Ubuntu Party Novembre 2017 - De Framasoft à YunoHost, réapproprions nous le cloud ([slides](https://blog.genma.fr/?De-Framasoft-a-Yunohost-reapproprions-nous-le-cloud)) - (FR) [Capitole du libre 2017 - YunoHost : vers l'auto-hébergement et au-delà - JimboJoe](https://2017.capitoledulibre.org/programme/#yunohost-vers-lauto-hebergement-et-au-dela) ([slides](https://github.com/YunoHost/yunohost-cdl-2017/raw/master/YunoHost-CDL2017.pdf)) - (FR) [PSES 2017 – Construire l’Internet du Futur avec YunoHost – Aleks, ljf](https://data.passageenseine.org/2017/aleks-ljf_internet-futur-yunohost.webm) ([slides](https://data.passageenseine.org/2017/aleks-ljf_internet-futur-yunohost.pdf)) - (FR) [Université de technologie de compiègne 2017 – Agir pour un internet éthique – LJF](http://webtv.utc.fr/watch_video.php?v=O34AA7RBR1AH) - (EN) [FOSDEM 2017 – Internet Cube – kload](https://archive.fosdem.org/2017/schedule/event/internet_cube/) - (EN) [FOSDEM 2017 – YunoHost – Bram](https://archive.fosdem.org/2017/schedule/event/yunohost/) - (FR) [Capitole du libre 2016 – 1 an et ½ de Brique Internet – Bram](https://toulibre.org/pub/2016-11-19-capitole-du-libre/videos/communaute-du-libre/bram-1-an-et-demi-de-brique-internet.mp4) - (FR) [PSES 2015 - La Brique Internet](http://www.youtube.com/watch?v=NCRn0yRfkIE) - (FR) [THSF 2015 – beudbeud](https://vimeo.com/128055751) - (FR) [RMLL 2014 - Hébergez-vous ! – kload & beudbeud](https://rmll.ubicast.tv/videos/hebergez-vous/) - (FR) [Capitole du libre 2013 - L’auto-hébergement pour tous avec YunoHost - beudbeud](http://2013.capitoledulibre.org/conferences/internet-libre/lauto-hebergement-pour-tous-avec-yunohost.html) - (EN) [FOSDEM 2013 — kload](https://www.youtube.com/watch?v=siN1OLAgGJk) ## Articles / Press review [![](/img/Linuxfr.png?resize=180)](https://linuxfr.org/news/yunohost-2-0-l-auto-hebergement-a-portee-de-clic) [![](/img/linux-pratique-96.jpg?resize=150)](https://www.linux-pratique.com/2016/07/et-si-vous-passiez-a-lauto-hebergement/) [![](/img/linux-magazine-208.jpg?resize=150)](https://www.linux-magazine.com/Issues/2018/208/YunoHost) - LinuxFr (french): - [YunoHost 2.0 : self hosting at click range](https://linuxfr.org/news/yunohost-2-0-l-auto-hebergement-a-portee-de-clic) - [Internet cube and YunoHost projects evolutions](https://linuxfr.org/news/evolutions-des-projets-la-brique-internet-et-yunohost-des-versions-2-2-2-4-et-2-5) - (FR) [Linux Pratique n°96 – YunoHost, l’auto-hébergement à portée de main – juillet 2016](http://connect.ed-diamond.com/Linux-Pratique/LP-096/YunoHost-l-auto-hebergement-a-portee-de-main) - (EN) [Linux Magazine n°208 – YunoHost, Personal server for a private cloud – Mars 2018](http://www.linux-magazine.com/Issues/2018/208/YunoHost) - (FR) [Linux Pratique HS n° 044 février 2019 - Le choix de l’auto-hébergement avec YunoHost : rencontre avec l’équipe du projet](https://connect.ed-diamond.com/Linux-Pratique/LPHS-044/Le-choix-de-l-auto-hebergement-avec-YunoHost-rencontre-avec-l-equipe-du-projet) - (FR) [Duhaz.fr: Devenir votre propre hébergeur](https://www.duhaz.fr/blog/devenir-votre-propre-h%C3%A9bergeur/) - (FR) [Faimaison.net: au revoir Google, bonjour liberté!](https://www.faimaison.net/actualites/chatons-leprette-mai2019.html) - (FR) [Tineternet.net: Reprendre la main sur ses données avec l'auto-hébergement](https://www.tinternet.net/article/2019/05/dossier-reprendre-la-main-sur-ses-donnees-avec-lauto-hebergement) - (DE) [YunoHost Serverinstallation auf Laptop](https://www.giammi.com/2019/04/19/yunohost-serverinstallation-auf-laptop/) - (FR) [Cenabumix: Retour d’expérience YunoHost sur Raspberry](https://wiki.cenabumix.org/wordpress/2018/03/17/retour-dexperience-yunohost-sur-raspberry/) - (FR) [Geber.ga: YunoHost, ou l'auto-hébergement à portée de main...](https://www.geber.ga/yunohost-ou-l-auto-hebergement-a-portee-de-main/) - (EN) [Nequalsonelifestyle.com: Self Hosting Without Self Owning](https://www.nequalsonelifestyle.com/2019/05/04/self-hosting-without-self-owning/) - (EN) [Skysilk.com: How to Install YunoHost On a Debian VPS](https://www.skysilk.com/blog/2019/how-to-install-yunohost-on-a-debian-vps/) - (FR) [Alternativelibertaire.org: Auto-hébergement](https://www.alternativelibertaire.org/?Auto-hebergement-1-Un-serveur-a-mon-seul-service) - (ES) [Sololinux.es: Instalar YunoHost en Debian 9 Stretch](https://www.sololinux.es/instalar-yunohost-en-debian-9-stretch/) - (FR) [Bog.hugopoi.net: Le cloud maison](https://blog.hugopoi.net/2019/03/30/le-cloud-maison/) ## Past Events / Workshops - (FR) [INFOTHEMA: Présentation de l’avancée du projet YunoHost INFOTHEMA + Présentation du collectif CHATONS](https://www.infothema.fr/begard-samedi-22-juin-2019-seance-infothema/) - (FR) [Normandie-libre.fr: Héberger ses sites web à la maison](https://normandie-libre.fr/heberger-ses-sites-web-a-la-maison/) - (FR) [Viregul.fr: Auto-hébergement, pour un Internet décentralisé](https://viregul.fr/auto-hebergement-pour-un-internet-decentralise-le-samedi-25-mai-2019/) - (EN) [35C3: Hands-on introduction to self-Hosting with YunoHos](https://events.ccc.de/congress/2018/wiki/index.php/Session:Hands-on_introduction_to_self-Hosting_with_YunoHost) - (FR) [Journées du Logiciel Libre 2019: l'auto-hébergement avec YunoHost](https://pretalx.jdll.org/jdll2019/talk/88GSPH/) ## YunoHost was cited in - [EXPERIMENTA 2018](https://livestream.com/accounts/26482307/events/8034656/player?width=960&height=540&enableInfoAndActivity=true&defaultDrawer=&autoPlay=true&mute=false) at 57.47 (depuis [le site d'Experimenta](https://www.experimenta.fr/direct/)) - [Capitole du libre 2017 - « Contributopia », Dégoogliser ne suffit pas](https://www.youtube.com/watch?v=ip6_VMkWpr8&feature=youtu.be&t=4793) - [Contributopia - Essaimage (Framasoft)](https://contributopia.org/fr/essaimage/) - (FR) [Triple A: Émission Underscore #144 du 19 mai 2019](https://www.triplea.fr/blog/podcast/emission-underscore-144-du-19-mai-2019/) ================================================ FILE: docs/community/40.sponsors_partners.mdx ================================================ --- title: Sponsors and partners description: "Friends of YunoHost" --- In order to advance and make the project works, in addition to the work of volunteers and donations, YunoHost benefits from the support of sponsors and partners. Here is a list of YunoHost sponsors, providing infrastructure and services to the project: - [GITOYEN](https://gitoyen.net): association bringing together several companies and associations acting as a provider of hosting infrastructure and Internet access. - [GLOBENET](http://www.globenet.org): activist association, at the service of freedom of expression, offering internet services. - [LDN-NET](https://ldn-fai.net/) : association for the defense of a free, neutral and decentralized Internet whose main means of action is to be an Internet access provider associative and local. - [NBS System](https://www.nbs-system.com/): company specialized in hosting, securing Clouds, outsourcing (Information Systems, SaaS Applications, Web Platforms) and managed services. - [NLNET](https://nlnet.nl/): The NLnet Foundation supports organizations and people that contribute to an open information society. - [TETANEUTRAL-NET](https://tetaneutral.net/): associative Internet access provider currently operating a radio network in Toulouse and its surroundings and a hoster. Here is a list of YunoHost partners: - [FFDN](https://www.ffdn.org/): The FDN federation gathers associative Internet Access Providers who recognize themselves in common values: volunteering, solidarity, democratic functioning and non-profit; defense and promotion of net neutrality. - [Framasoft](https://framasoft.org/) : popular education association, a group of friends convinced that an emancipatory digital world is possible, convinced that it will happen thanks to concrete actions on the ground and online with you and for you! ================================================ FILE: docs/community/90.terms_of_services.mdx ================================================ --- title: Terms and conditions description: General and Specific Conditions of Services --- # General and Specific Conditions of Services operated by the YunoHost project 01/02/2024 ## Preamble The YunoHost project is a team of volunteers who have made common cause to create a free operating system for servers, called YunoHost. YunoHost is published [under the GNU Affero General Public License v3](https://www.gnu.org/licenses/agpl-3.0.txt). In connection with this software, the project administers and makes available several technical and community services for various purposes. By using these services, you agree to be bound by the following terms. ## Short version (TL;DR) - **"This is a community project" clause**: you accept and respect the fact that the project is maintained by team of volunteers, and that volunteer time and energy are the driving force behind the project. You are welcome to contribute to the project, punctually or over time, in any way you choose (whether it's talking about it around you, giving us constructive feedback, helping others, saying hi, translating, testing, coding, donating, ...). - **"We do what we can" clause**: You accept that the volunteer team does the best it can, and is not subject to any obligation of means or result. The project cannot be held responsible for any consequential damage if a service ceases to operate. The team may decide to stop a service at any time. - **"We are not FAANGs" clause**: We try to minimize as much as possible the personal data that may transit, be stored on our infrastructure or be transferred to third parties. We publish the code that runs our services. We do not resell personal data. We only use data for internal, anonymized statistical purposes. - **"We do not like toxic people" clause**: you must respect other members of the community by showing civic-mindedness, politeness and kindness. - **"Free software is not about volunteers doing your bidding" clause**: messages that simply ask when a feature, fix or update will be available, that are intentionally or unintentionally insistent, without any form of politeness, benevolence or intention to contribute, are not welcome. If you would like a particular point to be addressed, ask yourself how you can contribute, or at the very least, speak kindly of it. - **"We do not read crystal balls" clause**: the forum and support chat clearly state that in order to obtain help, it is necessary to provide basic information (hardware type, YunoHost version, ..), contextual elements and complete logs. Not doing so is extremely annoying for the volunteers trying to help you. - **"We do not want to go to jail" clause**: you must respect the law (whether it's well-made or silly). - **"Any abuse will be punished" clause**: technical or human abuse of the services may result in the closure of your accounts and the banning of access to some or all of the services, possibly without warning or negotiation. ## Distinction between YunoHost as a project, as a service, as software, and as distribution This document details the TOS that apply **to the services provided by the YunoHost project**, but **not** to YunoHost as software **nor** to the applications offered in the YunoHost catalog. YunoHost as software is released [under the AGPLv3 license](https://www.gnu.org/licenses/agpl-3.0.txt) and is therefore provided without warranty of any kind and is not liable for any damages resulting from its use, nor from the use of the applications it allows you to install. *If you use YunoHost to provide services to others, it is your responsibility to define and publish your own terms and conditions of use for your own services, and to inform yourself of any legal implications of the applications you install.* ## General and specific conditions of service The YunoHost project reserves the right to update and modify these conditions. In this case, the YunoHost project will inform those concerned by posting a notice on the forum or, failing that, on the site. A dated version history of these conditions can be [found here](https://github.com/YunoHost/project-organization/commits/master/yunohost_project_tos.md). ## Services overview The services administered and maintained by the project to date are: - a public website, designed to present the project and provide documentation; - hosting of installation scripts, images, packages and cryptographic keys for installing and updating YunoHost; - a public community forum, to support each other and discuss problems or any other topic related to the project; - a public application catalog, to present and vote for available applications, and an API for programs to retrieve this list; - a pastebin service, for easy sharing of logs and other technical information; - a free domain name service, designed to reduce friction for people who don't yet own a domain name, or who want a quick and easy solution in the context of YunoHost; - self-diagnostic services used by YunoHost software to help users diagnose technical problems on their own; - a freely, publicly available YunoHost demo server; - other development and maintenance services. In addition, the project depends on, uses, or encourages the use of services managed by third parties, such as: - software blocks and automatic installation recipes (apps) hosted by third parties such as (non-exhaustive list) `github.com`, `npmjs.org`, `pypi.org`, `debian.org`, `sury.org`, ... - several public community chat rooms using Matrix, XMPP and IRC protocols, hosted by third parties such as (non-exhaustive list) `matrix.org` and `libera.chat`; - the Let's Encrypt certification authority; - a donation interface, where payments are managed by Stripe and sent to Support Self-Hosting, the association that collects and manages donations; It is your responsibility to consult the conditions of use of these third-party services. ## Access to services ### Geographic scope The YunoHost project services are intended for all YunoHost users and contributors worldwide, as long as the regulations of their country do not contravene their use or provision. ### Permission to use services Unless otherwise specified, use of the YunoHost project services is limited to use within the expected framework: - discovering or using the YunoHost operating system - contribution to the YunoHost project Any other use (e.g. use in another distribution, creation of artificial intelligence, etc.) must be approved in advance by the YunoHost project, unless explicitly permitted in the service-specific conditions below. ### Account-based services and termination The following functionalities are accessible via an account: - forum posting ; - voting for applications in the catalog (on `apps.yunohost.org`) ; - reservation and management of dynamic domain names provided by the YunoHost project (`nohost.me`, `noho.st` and `ynh.fr`). The forum account and the account managing your domain name can be terminated using the associated credentials. ## How it works ### Financial conditions **All services are provided free of charge. Don't hesitate to support the YunoHost project by making a donation**. ### Troubleshooting **In the event of an outage, and if there is no message on the forum confirming that the YunoHost project is in the process of correcting the outage, you are encouraged to report it via chat or the forum.** The YunoHost project offers all these services thanks to volunteers who will do their best to resolve any technical problems that may arise. Volunteers are under no obligation to repair a broken service. In the event of failure to fix a technical issue, the YunoHost project may decide to close the service. ### Fate of services The YunoHost project does not guarantee that services will continue to operate forever, and may choose to discontinue services if the project feels it is no longer able to provide said services. If the YunoHost project is able to do so, it will do its best to allow sufficient time for everyone to migrate or adapt serenely. ### YunoHost project responsibility **Under no circumstances may a user claim damages or compensation resulting from technical problems of any kind whatsoever.** The YunoHost project is not subject to any obligation (neither of means nor of result). In the event of failure or interruption of services, the YunoHost project cannot be held responsible for indirect damages such as loss of data, operating losses, commercial prejudice, loss of clientele, sales, profits or anticipated savings, or any other indirect prejudice. In particular, the YunoHost project cannot be held liable if you have made vital interests dependent on its services. ## Misuse of services **Any abuse may result in the closure of your accounts and the prohibition of access to all or part of the services**. The YunoHost project reserves the right to take any measures it deems necessary to put an end to any abuse of its services. The YunoHost project is the sole judge of this notion of "abuse", with the aim of providing the best possible service to all users. The YunoHost project may decide to act without warning or negotiation. ### Illegal use of services **The YunoHost project is not here to cover you and take legal risks on your behalf. Even if your action is legitimate, you are entirely responsible for what you do.** You must abide by the laws and regulations in force when using the services offered by the YunoHost project (in particular the forum, chat, paste and domain name services), whether in terms of privacy, sending large quantities of e-mail, intellectual property, discriminatory comments, hate speech, harassment, infringement of people's fundamental freedoms, and so on. In the event of prohibited use, the YunoHost project may be obliged to suspend all or part of the service, remove content, or take any other action required by law or regulation. ### Respect for the community and volunteers You accept and respect the fact that the YunoHost project is a community project maintained by a volunteer team, and that volunteer time and energy are the driving force behind the project. You understand that project volunteers do their best, and that to abuse their time or energy is to sabotage the project. You must respect other users and the project team by demonstrating civility, politeness and kindness. Any form of pressure, insistence, harassment or toxicity is prohibited. The YunoHost project reserves the right to ban you and delete any content that appears irrelevant or contravenes these principles, at its sole discretion and without prior warning. In particular, the YunoHost project will be uncompromising whenever your behavior consumes too much of the energy of the project's regular contributors. ### Reasonable use **Since services and resources are shared with the rest of the users, their use must be reasonable and take into account the shared aspect**. If you abuse the service, for example by monopolizing shared machine resources, its content or access may be removed. ## Our commitments ### CHATONS Charter **The YunoHost project's long-term aim is to respect the charter of the Collectif des Hébergeurs, Alternatifs, Transparents, Ouverts, Neutres et Solidaires (Collective of alternative, transparent, open, neutral and supportive hosting providers) as part of its service provision activities**. Given its international scope, the YunoHost project is not currently a candidate for membership of this collective. However, members of the C.H.A.T.O.N.S collective are currently using YunoHost. For more information see [the C.H.A.T.O.N.S. charter](https://chatons.org/charte). ### Respect for your personal data and privacy We try to minimize as much as possible the personal data that may transit, be stored on our infrastructure or be transferred to third parties. The YunoHost project prohibits any resale or transfer of personal data to third parties. Below are details of the personal data that may be transferred or stored on YunoHost services: - technical information (IP, User agent) used to interact with the services. This information is used to provide the service, to ensure its maintenance and security, and to create very basic aggregated statistics. - e-mail address and pseudonym used on the forum - personal information contained in messages exchanged via the forum or chat room - personal information included in domain names provided by the project - information contained in logs that you have shared via the dedicated tool - banking and personal information relating to donations made via Stripe or Liberapay. Unless otherwise specified in the specific conditions, these data are located in Paris, Strasbourg and Toulouse. For further information, please refer to the specific conditions of service. ### Exercising your rights In accordance with Article 34 of the French Data Protection Act, you may exercise the following rights by sending an e-mail to `data AT yunohost.org` : - rights of access, rectification, deletion and opposition - right to data processing limitation - right to data portability - right not to be the subject of an automated individual decision ### GDPR The YunoHost project undertakes, with respect to the services it makes available, to comply with the regulations in force applicable to the processing of personal data and, in particular, Regulation (EU) 2016/679 of the European Parliament and of the Council of April 27, 2016 applicable as of May 25, 2018, known as the GDPR. Nevertheless this does not mean in any way that *YunoHost software*, nor the applications offered for installation, would be certified with any GDPR compliance (whatever that may mean for you). ## Disputes and jurisdiction The law applicable to the present contract is French law. In the event of a dispute, the parties shall seek an amicable solution. If this fails, the dispute will be settled by the Tribunal de Grande Instance de Toulouse (FRANCE). The fact that the user or the YunoHost project does not take advantage at a given time of one of the present general conditions and/or tolerates a breach by the other party may not be interpreted as a renunciation by the user or the YunoHost project to take advantage of these conditions at a later date. The nullity of one of the clauses of these conditions in application of a law, regulation or court decision does not imply the nullity of all the other clauses. Furthermore, the general spirit of the clause must be maintained in accordance with the applicable law. --- ## Specific Conditions of Services ### Website and documentation #### Service address `yunohost.org` #### Contribution If you find an error, don't hesitate to suggest a correction, via the "Edit" button (requires a GitHub account) or via a message on the forum. #### Personal data To the best of our knowledge, none of the pages on this website contain trackers. As with any web service, a technical log exists recording the IP and User Agent of requests. ### Donations #### Service address `donate.yunohost.org` #### Stop recurring donation To stop your recurring donation, please send an email to `donate-5542 AT yunohost.org` and indicate the information that will identify your donation (email used, name, amount). #### Personal data To provide this service, the Support Self-Hosting association uses Stripe as its payment infrastructure. It is necessary to use a credit card and your identity, but these data are not stored, or even transit, through the YunoHost project infrastructure, except in emails exchanged as part of a recurring donation cancellation. As with any web service, a technical log exists recording the IP and User Agent of requests. ### Installation media (ISO image, ARM, installation script, etc.) You use this service in 2 situations: - installing or restoring YunoHost - (rarer) to install, update or restore an app whose binary is not supplied by its publisher and whose compilation on your own machine is deemed too long or too resource-intensive. #### Service address `repo.yunohost.org` #### Personal data As with any web service, a technical log exists recording the IP and User Agent of requests. ### IP This service is used automatically by your YunoHost instances to determine their public IPs, enabling you to automate and diagnose certain operations. #### Service addresses `ip.yunohost.org` and `ip6.yunohost.org` addresses #### Free access service Exceptionally, the public IP retrieval service can be used in other contexts, as long as the load induced is minimal relative to that of YunoHost. #### Personal data As with any web service, a technical log exists recording the IP and User Agent of requests. ### Free and dynamic domain names This is the service used if you request a domain name ending in `nohost.me`, `noho.st` or `ynh.fr` in the YunoHost interface. #### Service addresses `dyndns.yunohost.org`, `dynette.yunohost.org`, `ns0.yunohost.org`, `ns1.yunohost.org`. #### Usage limits This service is offered within the limit of one domain per YunoHost server (although it is possible to configure sub-domains of this domain). If abuse is detected (e.g. creation of too many domains from the same machine or IP, or large-scale automated creation), the project reserves the right to delete the domains concerned without warning. #### Automatic deletion The YunoHost project reserves the right to delete a domain if no server appears to be associated with it and the IP address has not been updated for 1 year. #### Termination You can delete your domain using the password you chose when you created it. #### Personal data If your name contains personal data, these will inevitably end up on the servers running the service. Note that, in order to function, this service necessarily stores and transmits your server's public IP addresses. As with any web service, a technical log exists recording the IP and User Agent of requests. ### Diagnostics This service automatically tests whether your services seem to be correctly exposed on the Internet, and thus independently resolves network configuration problems. This service is used automatically twice a day, as soon as you activate the diagnostics feature. #### Service address `diagnosis.yunohost.org` #### Usage limits Due to the resource consumption involved, the diagnosis service is limited to 60 domains to be diagnosed per request. If you exceed this limit, the project recommends that you diagnose your domains yourself. #### Personal data To operate, this service transmits the domain names and ports to be diagnosed. Any personal data contained in the domain names is therefore also transferred, but not stored. As with any web service, a technical log exists recording the IP and User Agent of requests. ### Application catalog This service lets you browse (via a browser or program) the list of applications available for installation in YunoHost. It also allows you to vote for apps to direct contribution efforts. In addition, servers running YunoHost automatically retrieve the application catalog once a day. #### Service addresses `apps.yunohost.org` and `app.yunohost.org`. #### Service misuse Any attempt to falsify votes on catalog or wishlist apps will be considered abuse and may be subject to cancellation, banning and account deletion. #### Personal data To participate in the popularity of apps, you need to use your forum account. See Forum service. The storage of your votes is linked to your forum identity. As with any web service, a technical log exists recording the IP and User Agent of requests. #### Statistics In order to size our services and plan new releases, we use the technical download logs from the list of apps to estimate the number of YunoHost instances running in the wild, and the ratio of major releases. ### Debian package repository This is the channel through which updates to YunoHost as software are made available. The YunoHost project also maintains builds of some software components on which YunoHost depends or on the periphery of the project. #### Service address `forge.yunohost.org` #### Permission to create mirror repositories It is allowed (and even encouraged) to create mirror repositories of YunoHost's Debian package repository. #### Personal data As with any web service, a technical log exists recording the IP and User Agent of requests. ### Tickets and contributions to the code As it stands, development, bug reports and feature requests take place on the repositories of the "YunoHost" and "YunoHost-Apps" organizations on the GitHub platform. #### Respect for volunteers We can only re-emphasize what has already been mentioned in the 'Respect for the community and volunteers' section above: the project is maintained by a volunteer team, volunteer time and energy is the driving force behind the project, and volunteers do their best. You're welcome to contribute to the project (and if necessary to ask questions about how to contribute) to the team. On the other hand, abusing their time or energy is tantamount to sabotaging the project. In particular, YunoHost is *not* a community of volunteers at your command regarding priorities for patches, features or updates, either for YunoHost as software, or for the catalog of applications maintained by the project. Volunteers do not promise support, fixes, features or updates, nor do they provide estimates of "when" a feature, fix or update will be available. Messages that simply ask when a feature, fix or update will be available, without any form of politeness, benevolence or intention to contribute, are not welcome and undermine volunteer morale. Any abuse may be punished by a ban from the project's GitHub organizations, or even from all project services. ### Paste This service is used to share logs of operations carried out with YunoHost to enable the study and resolution of problems. #### Service address `paste.yunohost.org` #### Personal data The logs you share may contain personal information or, in the worst case, secrets that could compromise the security of part or all of your server. Upon publication, YunoHost software automatically tries to remove this information as best it can. Nevertheless, the system is far from being perfect, and it is your responsibility to re-read the information before sharing the generated link with others. As with any web service, a technical log exists recording the IP and User Agent of requests. ### Self-help forum (and chat) #### Service address `forum.yunohost.org` and chats listed on [the documentation](/community/chat_rooms). #### Asking for help The self-help forum and chat clearly state (e.g. [here](/community/help), [here](https://forum.yunohost.org/t/asking-for-support-demander-de-laide/7795) and [here](https://forum.yunohost.org/t/how-to-get-help-efficiently-comment-obtenir-de-laide-efficacement/27)) that in order to get help, it is **necessary** to provide basic information (hardware type, YunoHost version), background information and full logs. Not doing so is extremely annoying for the people trying to help you, especially as we strive to make sharing this information as simple as possible. In addition, it is counter-productive because it wastes everyone's time: nobody can solve a problem that is not diagnosable. If these rules are not respected, the team reserves the right to close your topic without notice. #### Personal data The forum allows you to enter personal information (email, GitHub account, nickname). From the forum interface, you can modify or delete this information. As with any web service, a technical log records the IP and User Agent of requests. In addition, the forum may send or receive e-mails, which are also logged. #### Location Paris ### Demo service #### Service address `demo.yunohost.org` #### Purpose and operation This service allows you to test YunoHost's interfaces (webadmin and user portal) to get a feel for YunoHost without installing it. The data on this server is destroyed and reset approximately every 30 minutes. #### Personal data As with any web service, a technical log exists recording the IP and User Agent of requests. ================================================ FILE: docs/community/index.mdx ================================================ --- title: Community description: YunoHost community description sidebar_position: 1 --- import SidebarDocCardList from '@site/src/components/SidebarDocCardList'; The YunoHost community is centered around [Github](https://github.com/yunohost), the [forum](https://forum.yunohost.org) and chat rooms on [Matrix](https://matrix.org). ================================================ FILE: docs/dev/05.git.mdx ================================================ --- title: 🛠️ Working with Git / Github hide_table_of_contents: true --- The YunoHost project extensively uses Git and GitHub (though we hope to move to a different platform oneday™) In particular: - [the `YunoHost` organization](https://github.com/YunoHost/) hosts the "core" of YunoHost, along with tools that are transversal to the project such that [the app store](https://github.com/YunoHost/appstore), [this very documentation](https://github.com/YunoHost/doc), etc. - [the `YunoHost-Apps` organization](https://github.com/YunoHost-Apps/) hosts the repo corresponding to the different apps Explaining how Git and GitHub works is beyond the scope of this documentation, but we can recommend: - [this super quick intro](https://rogerdudler.github.io/git-guide/) - [this Youtube tutorial](https://www.youtube.com/watch?v=RGOj5yH7evk) - [this guide, on how to make you very first Pull Request in GitHub](https://github.com/firstcontributions/first-contributions/blob/main/README.md) - also available in other languages - c.f. the flags at the top, for example [in french](https://github.com/firstcontributions/first-contributions/blob/main/docs/translations/README.fr.md)! - There are plenty of tutorials about Git and GitHub on the internets, find one that works for you, and come talk with other folks! ================================================ FILE: docs/dev/10.doc.mdx ================================================ --- title: 📝 Working on the documentation --- The YunoHost documentation is managed through [this Git repository](https://github.com/YunoHost/doc) and is powered by [Docusaurus](https://docusaurus.io/). **You do not need Git expertise just to improve an existing page** (you will need an account on the platform, though): there is an "Edit" button at the bottom of each page that will redirect you to the GitHub online editor where you make easily make change proposals (a.k.a Pull Request, PR). However, if you are on an editing spree, you probably want to work locally and submit a set of changes (a.k.a. a Pull Request, PR). In which case, refer to [the section "Working locally on the documentation" below](#working-locally-on-the-documentation). ## Markdown The YunoHost project extensively uses Markdown for its documentation and other things. Documenting how Markdown works is beyond the scope of this documentation, but we can recommend [this guide](https://www.markdownguide.org/basic-syntax/) to get familiar with its syntax. Note that Docusaurus has some additional, special syntax (hence why the files are `.mdx` and not just `.md`). ## Applications documentation The apps documentation (description, special admin instructions, ..) lives in each app's repository. Check [the corresponding section in the packaging documentation](/dev/packaging/doc). ## Working locally on the documentation Using Git, you can clone the documentation locally, edit several pages, add new ones or add new images, and then propose your changes using a Pull Request. To get started, you will need to clone the repo ``` git clone https://github.com/yunohost/doc cd doc ``` If you want to preview your changes, you will need to install npm/nodejs to build the doc. The documentation is built using [Docusaurus](https://docusaurus.io). It generates static pages that can be served by a simple server which can be deployed in production using for example [My Webapp](https://apps.yunohost.org/app/my_webapp) or [Github Pages](https://docusaurus.io/docs/deployment#deploying-to-github-pages). Check the [official Docusaurus doc](https://docusaurus.io/docs/docs-introduction) for more info. Here, we'll only build locally and checkout the result using a local dev server. If your distribution doesn't ship an up to date version of `nodejs`/`npm`, you can use `n` to setup one: ``` # Clone "n" which will be used to fetch a recent version of nodejs git clone https://github.com/tj/n --single-branch --depth 1 # Install the latest node/npm export N_PREFIX="$PWD" n/bin/n install latest # Make sure to use the nodejs/npm we installed NODE_BIN_PATH=$(dirname $(n/bin/n which latest)) export PATH="$NODE_BIN_PATH:$PATH" ``` # Then inside your "doc" clone, install the dependencies with: ``` npm ci ``` Then: ``` npm run start ``` And open http://localhost:3000 while the dev server is running You can also use: ``` npm run build npm run serve ``` ## Contents of the repository - The **actual documentation content** is inside the `docs/` folder, for example `docs/admin/02.what_is_yunohost/index.mdx` is the "What is YunoHost" page. - **Images** are in `static/img` - **Translations** are inside `i18n` folders, in particular `.po`/`.pot` files are regenerated automatically using the `po4a` software. Refer to the dedicated page about [🌐 Working on translations](/dev/translation) for more info. ## Special pages Some pages of the documentation are automatically or dynamically generated. Please do not try to edit them manually... See the [generation script](https://github.com/YunoHost/doc/blob/main/scripts/generate_docs.sh). ================================================ FILE: docs/dev/20.translation.mdx ================================================ --- title: 🌐 Working on translations --- Translating YunoHost — not just the software, but also the documentation and app catalog — is essential to making the project accessible to a wider audience. We primarily use **[Weblate](https://weblate.org)**, an excellent self-hostable FOSS translation platform. **No development tool / skill (such as Git) is required to contribute to translations**: the point of Weblate is precisely to focus on translation. New translations are automatically synced with the development the development repositories behind the scenes. The YunoHost project hosts its own Weblate instance at https://translate.yunohost.org.
If you're interested in contributing but need us to add your language, need help, or require assistance with unlocking components, please **don’t hesitate** to contact us. You can reach out via [the forum](https://forum.yunohost.org) or [the chatrooms](/community/chat_rooms). ## ⚙️ Software YunoHost "core", webadmin, user portal and other software pieces are translated within the main project:
Translations are automatically pushed to the corresponding Git repositories, merged by the team, and included in the next minor release of the corresponding software component. Under the hood, the strings are typically stored in JSON files, for example [here for the core](https://github.com/YunoHost/yunohost/blob/dev/locales/en.json) and [here for the webadmin](https://github.com/YunoHost/yunohost-admin/blob/dev/app/src/i18n/locales/en.json). You are also welcome to help improve the source messages, though this requires using Git/GitHub. ## 📝 Documentation The documentation is also translated on our Weblate instance in a separate, dedicated project:
Translations are regularly synced to [the corresponding Git repository](https://github.com/YunoHost/doc/), merged by the team, and automatically published. Note that only langs with at least 5% global translation are actually published. Each individual page translation must reach at least 10% translated for translations to be published for this page. Currently, only the "admin" section of the documentation is translatable, though we may open specific pages from the contribution and community sections for translation in the future. We also need to integrate a translation workflow for the navigation bar, footer, and other elements. Under the hood, the documentation is written using Markdown [here](https://github.com/YunoHost/doc/tree/main/docs/admin). We use **[po4a](https://www.po4a.org/)** to extract strings out of the `.mdx`, into standard`.po`/`.pot` files, plugged in Weblate, and vice-versa. You are welcome to also improve the [source pages](https://github.com/YunoHost/doc/tree/main/docs/admin), but this requires to use Git/GitHub. Refer to the dedicated page [📝 Working on the documentation](/dev/doc) for more info. ## ✨ Project website and app store The [project website](https://yunohost.org) ("landingpage") and [application store](https://apps.yunohost.org/) are also available to translation.
Here as well, translations are regularly synced to the corresponding Git repositories [here](https://github.com/YunoHost/landingpage) and [here](https://github.com/YunoHost/appstore), merged by the team, and automatically published. Note that for the project website, only langs with more than 40% translated are actually published. :::caution When we refer to the "app store," we are talking about the interface of the store itself, not the individual app descriptions or app-specific content (see the next section). ::: :::caution The catalog categories are not easily translatable yet either. The corresponding file is [here](https://github.com/YunoHost/apps/blob/main/categories.toml) and contains title/description for each category in each language. Ideally this will be in Weblate as well someday™. In the meantime, you can contribute to this as well, but this requires using Git/GitHub. ::: ## 📦 Individual apps Each individual YunoHost app has its own set of messages, such as descriptions, installation questions, and specific admin instructions. :::caution Unfortunately, these are **not yet** easily translatable (= not integrated in Weblate), though it is goal for the project to make enable this in the mid- to long-term. ::: Currently, translation work for apps can only be done through Git/GitHub. App-specific messages are part of each individual app repository (for example [this repo for Nextcloud](https://github.com/YunoHost-Apps/nextcloud_ynh)). More specifically: - the **app's `manifest.toml`**, for example [here for Nextcloud](https://github.com/YunoHost-Apps/nextcloud_ynh/blob/master/manifest.toml), contains: - `description.en`, `.fr`, ... for the short app description in english, french, ... - possibly several `ask.en`, `.fr` for install questions - though some install questions are standardized in YunoHost's core. - the **app's `doc/` folder**, for example [here for Nextcloud](https://github.com/YunoHost-Apps/nextcloud_ynh/tree/master/doc), contains: - `DESCRIPTION.md`, `_fr.md`, ... for the long app description in english, french, ... - `ADMIN.md`, `_fr.md`, ... for specific admin instructions - other notes like `POST_UPGRADE.md`, `_fr.md` for specific infos to be displayed after an upgrade. Similar files may exist to display messages before/after install/upgrades. Check [the corresponding page in the packaging doc](/dev/packaging/doc) for more details. - some apps may include a **`config_panel.toml`** (configuration panel), for example [here for Nextcloud](https://github.com/YunoHost-Apps/nextcloud_ynh/blob/master/config_panel.toml) also containing inline translation such as `name.en`, `.fr` or `ask.en`, `ask.fr` titles or input descriptions. This information appears both in the public app store, and inside YunoHost webadmin or CLI. ================================================ FILE: docs/dev/50.packaging/05.structure.mdx ================================================ --- title: App structure sidebar_position: 1 --- A Yunohost app package is a Git repository with such a structure: ```bash myapp_ynh ├── manifest.toml # The manifest ├── scripts # The scripts │ ├── _common.sh │ ├── install │ ├── remove │ ├── backup │ ├── restore │ ├── change_url │ └── upgrade ├── conf # The configuration files to install │ ├── cinny.json │ └── nginx.conf ├── doc # The documentation │ ├── DESCRIPTION.md │ ├── DESCRIPTION_fr.md │ ├── PRE_INSTALL.md │ └── screenshots │ └── screenshot.png ├── patches # Optional patches ├── tests.toml # The tests manifest ├── LICENSE └── README.md ``` The [manifest](./manifest) contains upstream information, sources, version, installation questions and resources to initialize. The [scripts](./scripts) are called by YunoHost when operations are started by the admin. The configuration files are templates that are filled and installed by the scripts, for example `nginx` or `systemd` or specific configs. Patches are applied when downloading the upstream sources. The [documentation](./doc) is used to show messages before / after install, upgrade, and in the webadmin. ================================================ FILE: docs/dev/50.packaging/10.manifest.mdx ================================================ --- title: manifest.toml --- The app's `manifest.toml` can be seen as the ID card of the app. It declares various basic metadata such as the id, name, description of the app, its version, install questions to be asked to the admin prior to installation, etc. In this page, the data are described according to a somewhat dummy app called `helloworld` :::tip If you want to convert an application from the packaging v1 to v2 format, [please see here](/dev/packaging/advanced/packaging_v2)! ::: ## General information ```toml packaging_format = 2 id = "helloworld" name = "Hello World" description.en = "A dummy basic app to illustrate YunoHost's app packaging." description.fr = "Une app simple et bidon pour illustrer comme le packaging d'app de YunoHost fonctionne" version = "0.1~ynh1" maintainers = ["alexAubin"] ``` - `packaging_format` (`int`) is the packaging version format used to package this app. Newly packaged apps are strongly encouraged to use the new "v2" format (starting with YunoHost 11.1) while older apps may still be in "v1" format. - `id` (`str`) is expected to be lower-case alphanumeric (and possibly `-`). This is what will be used for instance in the syntax `yunohost app install `. This will also be the name of various folder or conf files such as `/etc/yunohost/apps/` or `/etc/nginx/conf.d/.d/.conf` (if applicable), and a dedicated system user. - `name` (`str`) is the display name of the app, shown for example in the webadmin UI or user portal. It is limited to 23 chars (though not sure why this number?). - `description` (`dict` of `lang code`->`str`) contains *short*, *concise* descriptions of the app in different languages (at least `en`). It is limited to 150 chars. It will be displayed on the app catalog and should allow people to understand what this app is about at a glance. A more extensive description of the app can be provided in `doc/DESCRIPTION.md`. - `version` (`str`) is composed of the *upstream* version of the app shipped, and an `~ynhX` suffix. Changing this version is what effectively triggers an available upgrade for YunoHost instances which installed this package (hence no upgrade will be displayed as available if you forget to change it). The point of the `~ynhX` suffix is to have a way to increment the version when commiting changes unrelated to the upstream but still trigger an upgrade. - `maintainers` (`list` or `str`) may allow to declare which person should be the referring person for this package (though packages are often maintained collectively and not really used in practice). This should contain a list of easily identifiable persons (eg your GitHub or Matrix username) ## Upstream section This section is meant to provide various metadata about the app upstream such that YunoHost admins can easily obtain further information regarding this app (or, kinda important, try the upstream's demo before deciding to install it). Apart from the license, all fields are *optional* and should only be provided if they are relevant (e.g. don't provide `website` if the upstream project has no website...) ```toml [upstream] license = "WTFPL" license_url = ... website = "https://www.hello-world.com/" code = "https://github.com/octocat/Hello-World" demo = ... admindoc = ... userdoc = ... ``` - `license` (`str`) : the license identifier of the *upstream* project. (Note that only apps based on free software will be accepted in the official YunoHost app catalog). The license code should be: - [a valid SPDX identifier](https://spdx.org/licenses/). - if there is no corresponding license in SPDX's list, then you can start the identifier with `LicenseRef-` followed by the most appropriate short name/acronym you can think of for the given license, as described in the [SPDX documentation](https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/). You must then link to the license file using the `license_url` property documented below. - (optional) `license_url` (`url`) : the URL of the full text of upstream project's license, if that license is not included in SPDX's list. - (optional) `website` (`url`) : the URL of the upstream project's website, if there is indeed a website (please don't just copypasta the git repo url) - (optional) `demo` (`url`) : a URL where people can try out the app before installing it (ideally maintained by the upstream project) - (optional) `code` (`url`) : the URL of the upstream project's code repository, which is very much expected to exist for free software ... but may not exist for special "no upstream" apps ;) - (optional) `admindoc` (`url`) : the URL of the *upstream* project's admin documentation, which may help YunoHost admins with adminstrating the app (YunoHost-specific documentation can be provided in `doc/ADMIN.md`). - (optional) `userdoc` (`url`) : the URL of the *upstream* project's user documentation, which may help YunoHost end-users with effectively using the app. - (optional) `cpe` (`str`) corresponds to the [Common Platform Enumerations code in NIST db](https://nvd.nist.gov/products/cpe). For example for Wekan this is `cpe:2.3:a:wekan_project:wekan`. Not really used at the moment, but may be used in the future to check for known vulnerabilities (CVE) in the app catalog. ## Integration section This section is meant to contain info related to the relation between the app and YunoHost, or things like typical resource usage. ```toml [integration] yunohost = ">= 11.1" helpers_version = "2.1" architectures = "all" multi_instance = false ldap = "not_relevant" sso = "not_relevant" disk = "1M" ram.build = "1M" ram.runtime = "1M" ``` - `yunohost` (`str`) contains the minimum YunoHost version required for this app to work. - `helpers_version` (`str`) contains the version of the package helpers used by the application; supported versions are [2.0](/dev/packaging/scripts/helpers_v2.0) and [2.1](/dev/packaging/scripts/helpers_v2.1) - `architectures` : `"all"` OR a list of supported archs using the `dpkg --print-architecture` nomenclature, i.e. among : `amd64` (= x86 64bit), `i386` (= x86 32bit), `armhf` (= ARM 32bit), `arm64` (= ARM 64bit) - `multi_instance` (`bool`) : wether or not the app supports being installed multiple time (in which case, during installation, the actual app id is not just the `id` of the manifest, but something like `hellowold__2`, `helloworld__3`, etc. for subsequent installs) - `ldap` (`bool` OR `"not_relevant"`) : not to confused with the `sso` key : this corresponds to wether or not the app is configured to use YunoHost's LDAP DB as the user account DB. This should be set to `"not_relevant"` if and only if there is no notion of user account for this app (for example, Hextris). LDAP integration is often a prerequisite for the SSO to work. - `sso` (`bool` OR `"not_relevant"`) : not to be confused with the `ldap` key : this corresponds to wether or not a user is *automatically logged-in* on the app when logged-in on the YunoHost portal. This should be set to `"not_relevant"` if and only if there is no notion of user account for this app (for example, Hextris). - `disk` (size) : an *estimate* minimum disk requirement. For example: 20M, 400M, 1G, ... - `ram.build` (size) : an *estimate* minimum ram requirement when building the app (this may be way different than `ram.runtime` because some apps have a peak 1~2G RAM when building sometimes...). For example: 50M, 400M, 1G, ... - `ram.runtime` (size) : an *estimate* minimum ram requirement when the app is active and running. For example: 50M, 400M, 1G, ... ## Antifeatures This section is completely optional and, for most apps, doesn't exist at all. Some applications have limitations, they might be due to non-free dependencies, arbitrary limitations, etc. YunoHost provides UI in the catalog to show such antifeatures. The declaration of antifeatures is a 3-steps process: - Find the relevant antifeature in [the list of supported antifeatures](https://github.com/YunoHost/apps/blob/master/antifeatures.toml) - Declare the app's antifeature in the [app catalog](https://github.com/YunoHost/apps/blob/master/apps.toml) - Describe the app's antifeature in its `manifest.toml`: ```toml [antifeatures] arbitrary-limitations.en = "Some description about the specific limitations of this app." ``` The format of this section is a `dict` where keys are antifeature IDs, and the values are translated strings (`dict` of `lang code`->`str`). ## Install questions This section contains questions that should be asked to the admin prior to starting the actual install ```toml [install] [install.domain] # this is a generic question - ask strings are automatically handled by YunoHost's core type = "domain" [install.path] # this is a generic question - ask strings are automatically handled by YunoHost's core type = "path" default = "/helloworld" [install.init_main_permission] # this is a generic question - ask strings are automatically handled by YunoHost's core type = "group" default = "visitors" [install.prefered_pet] ask.en = "Do you prefer cats or dogs?" help.en = "Think carefully!" type = "string" choices.cat = "Cats :3 !" choices.dog = "Doggos <3" choices.both = "OMG Both ! I can't choose !" ``` - `domain` and `path` (with `type = "domain"/"path"`) are classic questions to allow the admin to choose where the app is installed (in terms of web url endpoint) - e.g. if the admin answers `domain.tld` and `/foobar`, the app will be available under `domain.tld/foobar` - some webapp do require a full dedicated domain and do not support the "subpath" install scheme. In that case, you typically want to remove the `path` question entirely - these questions are part of YunoHost's generic app questions and therefore you do not need to define the `ask.en` strings that contain the actual question displayed in the UI along the line of "Choose a domain to install this app on" - `init_main_permission` is also a classic question (similar to `is_public` in v1 packaging) and define what user group will be able to access the app after it is installed. Typical answer are : `visitors` (= everybody including anonymous users, the app is "public"), `all_users` (= only people with a YunoHost account, the app is "private"), or any custom user group that may have been defined by the YunoHost admins prior to the install. - `prefered_pet` is a custom question: - `ask.en` defines the human-readable question to be asked (at least the english version) - `help.en` is an optional additional message to provide further info about this question - `type` is the type of question, in this case `string` - in this example, we don't want a free user input but choosing between `cat`, `dog` or `both` (with proper human-readable versions of these choices) - this will later automatically create a YunoHost app setting named `prefered_pet` - .. and in the bash install script, the bash variable will automatically be available `$prefered_pet` with the chosen value ### Regarding install question types FIXME : This should be way more documented in a separate section (and is also related to config panels...) The full list of question types is : `string`, `text`, `select`, `tags`, `email`, `url`, `date`, `time`, `color`, `password`, `path`, `boolean`, `domain`, `user`, `group`, `number`, `range`, `alert`, `markdown`, `file`, `app`. `password`-type questions have special behavior and are NOT automatically saved as setting (user-chosen password should ideally not be stored, at least not hashed...) Every install question is not necessarily mandatory (e.g. a question to propose to add an api key for a better user experience, although the app still works without). To make those questions optional, just write `optional = true`. ## Resource system The resource section corresponds to recurring app needs that are to be provisioned/deprovisioned by the core of YunoHost. They include for example: downloading the app's sources, creating a system user, installing apt dependencies, creating the install dir, creating the data dir, finding an available internal port, configuring permissions, initializing an SQL database... Each resource is to be provisioned *before* running the install script, deprovisioned *after* the remove script, and automatically upgraded if needed before running the upgrade script (or provisionned if introduced in the new app version, or deprovisioned if removed w.r.t. the previous app version) ```toml [resources] ```toml [resources.sources.main] url = "https://some.domain/url/where/to/download/the/app/sources.tar.gz" sha256 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" [resources.system_user] [resources.install_dir] [resources.permissions] main.url = "/" [resources.apt] packages = "nyancat, lolcat, sl" ``` In this example: - `sources.main`: the URL+checksum from which the app sources will be downloaded + validated - `system_user`: a system (unix) user will be created for this app, using the app id as username. - `install_dir`: an install dir will be initialized, named `/var/www/$app` by default. Additional `owner` and `group` property allow to change the owner/group and r/w/x permissions on the created folder. - `permissions`: an SSOwat `$app.main` permission will be initialized such that the SSO allows access to the app's endpoint according to the chosen `init_main_permission` question. The `main.url = "/"` is here to tell that the main endpoint is the "root" of the app, that is `https://domain.tld/helloworld/` if the app is installed with `domain=domain.tld` and `path=/helloworld` - `apt`: the packages `nyancat`, `lolcat`, `sl` will be installed with `apt`. These are just dummy apt dependencies to illustrate the syntax. ### List of app resources The full documentation on resources is available [here](/dev/packaging/resources). ================================================ FILE: docs/dev/50.packaging/15.resources.mdx ================================================ --- title: App resources toc_max_heading_level: 2 # custom_edit_link: 'https://github.com/YunoHost/yunohost/blob/dev/src/utils/resources.py' --- Doc auto-generated by [this script](https://github.com/YunoHost/doc/blob/da78370c098ca04b590e18fb1c8924242367703e/scripts/resources_doc_generate.py) on 09/01/2026 (YunoHost version 12.1.39) ## Apt Create a virtual package in apt, depending on the list of specified packages that the app needs. The virtual packages is called `$app-ynh-deps` (with `_` being replaced by `-` in the app name, see `ynh_install_app_dependencies`) ### Example ```toml [resources.apt] packages = ["nyancat", "lolcat", "sl"] # (this part is optional and corresponds to the legacy ynh_install_extra_app_dependencies helper) extras.yarn.repo = "deb https://dl.yarnpkg.com/debian/ stable main" extras.yarn.key = "https://dl.yarnpkg.com/debian/pubkey.gpg" extras.yarn.packages = ["yarn"] ``` ### Properties - `packages`: List of packages to be installed via `apt` - `packages_from_raw_bash`: A multi-line bash snippet (using triple quotes as open/close) which should echo additional packages to be installed. Meant to be used for packages to be conditionally installed depending on architecture, debian version, install questions, or other logic. - `extras`: A dict of (repo, key, packages) corresponding to "extra" repositories to fetch dependencies from ### Provision/Update - The code literally calls the bash helpers `ynh_install_app_dependencies` and `ynh_install_extra_app_dependencies`, similar to what happens in v1. - Note that when `packages` contains some phpX.Y-foobar dependencies, this will automagically define a `phpversion` setting equal to `X.Y` which can therefore be used in app scripts ($phpversion) or templates (`__PHPVERSION__`) ### Deprovision - The code literally calls the bash helper `ynh_remove_app_dependencies` --- ## Composer Installs a composer version to be used by the app You may then use `ynh_composer_exec` in your script to run composer actions Note that this resource requires that the app requires an `install_dir`, and installs php dependencies via the `apt` resource. ### Example ```toml [resources.composer] version = "2.7.7" ``` ### Properties - `version`: The composer version needed by the app ### Provision/Update - Download `composer.phar` for the corresponding version from `getcomposer.org` - `composer.phar` is placed in the `$install_dir` of the app - Define `composer_version` as the requested version ### Deprovision - Delete `composer.phar` - Delete the `composer_verison` setting --- ## Data Dir Creates a directory to be used by the app as the data store directory, typically where the app multimedia or large assets added by users are located. The corresponding path is stored in the settings as `data_dir`. This resource behaves very similarly to install_dir. ### Example ```toml [resources.data_dir] # (empty - defaults are usually okay) ``` ### Properties - `dir`: (default: `/home/yunohost.app/__APP__`) The full path of the data dir - `subdirs`: (default: empty list) A list of subdirs to initialize inside the data dir. For example, `['foo', 'bar']` - `owner`: (default: `__APP__:rwx`) The owner (and owner permissions) for the data dir - `group`: (default: `__APP__:rx`) The group (and group permissions) for the data dir ### Provision/Update - if the dir path changed and a folder exists at the old location, the folder will be `mv`'ed to the new location - otherwise, creates the directory if it doesn't exists yet - create each subdir declared and which do not exist already - (re-)apply permissions (only on the folder itself and declared subdirs, not recursively) - save the value of `dir` as `data_dir` in the app's settings, which can be then used by the app scripts (`$data_dir`) and conf templates (`__DATA_DIR__`) ### Deprovision - (only if the purge option is chosen by the user) recursively deletes the directory if it exists - also delete the corresponding setting ### Legacy management - In the past, the setting may have been called `datadir`. The code will automatically rename it as `data_dir`. - As explained in the 'Provision/Update' section, the folder will also be moved if the location changed --- ## Database Initialize a database, either using MySQL or Postgresql. Relevant DB infos are stored in settings `$db_name`, `$db_user` and `$db_pwd`. NB: only one DB can be handled in such a way (is there really an app that would need two completely different DB ?...) NB2: no automagic migration will happen in an suddenly change `type` from `mysql` to `postgresql` or viceversa in its life ### Example ```toml [resources.database] type = "mysql" # or : "postgresql". Only these two values are supported ``` ### Properties - `type`: The database type, either `mysql` or `postgresql` ### Provision/Update - (Re)set the `$db_name` and `$db_user` settings with the sanitized app name (replacing `-` and `.` with `_`) - If `$db_pwd` doesn't already exists, pick a random database password and store it in that setting - If the database doesn't exists yet, create the SQL user and DB using `ynh_mysql_create_db` or `ynh_psql_create_db`. ### Deprovision - Drop the DB using `ynh_mysql_remove_db` or `ynh_psql_remove_db` - Deletes the `db_name`, `db_user` and `db_pwd` settings ### Legacy management - In the past, the sql passwords may have been named `mysqlpwd` or `psqlpwd`, in which case it will automatically be renamed as `db_pwd` --- ## Go Installs a go version to be used by the app, using "goenv" Sourcing the helpers will then automatically tweak the `PATH` variable such that you may call `go` directly. Sourcing the helpers will also automatically define: - `$go_dir`, the directory containing the specific version of Go ### Example ```toml [resources.go] version = "1.20" ``` ### Properties - `version`: The go version needed by the app ### Provision/Update - Fetch/update a copy of the goenv tool and xxenv-latest - Compute the actual "latest" version for the requested version, e.g. `1.20` may corresponds to `1.20.2` - This "actual version" is stored as `go_version` in the app settings - Install the corresponding Go version - Garbage-collect unused versions ### Deprovision - Delete the `go_version` setting - Garbage-collect unused versions --- ## Install Dir Creates a directory to be used by the app as the installation directory, typically where the app sources and assets are located. The corresponding path is stored in the settings as `install_dir` ### Example ```toml [resources.install_dir] # (empty - defaults are usually okay) ``` ### Properties - `dir`: (default: `/var/www/__APP__`) The full path of the install dir - `owner`: (default: `__APP__:rwx`) The owner (and owner permissions) for the install dir - `group`: (default: `__APP__:rx`) The group (and group permissions) for the install dir ### Provision/Update - during install, the folder will be deleted if it already exists (FIXME: is this what we want?) - if the dir path changed and a folder exists at the old location, the folder will be `mv`'ed to the new location - otherwise, creates the directory if it doesn't exists yet - (re-)apply permissions (only on the folder itself, not recursively) - save the value of `dir` as `install_dir` in the app's settings, which can be then used by the app scripts (`$install_dir`) and conf templates (`__INSTALL_DIR__`) ### Deprovision - recursively deletes the directory if it exists ### Legacy management - In the past, the setting was called `final_path`. The code will automatically rename it as `install_dir`. - As explained in the 'Provision/Update' section, the folder will also be moved if the location changed --- ## Nodejs Installs a nodejs version using "n" to be used by the app Sourcing the helpers will then automatically tweak the PATH variable such that you may call `npm` directly. Sourcing the helpers will also automatically define: - `$path_with_nodejs` to be used in the systemd config (`Environment="PATH=__PATH_WITH_NODEJS__"`) - `$nodejs_dir`, the directory containing the specific version of nodejs, which may be used in the systemd config too (e.g. `ExecStart=__NODEJS_DIR__/node foo bar`) ### Example ```toml [resources.nodejs] version = "18.2" ``` ### Properties - `version`: The nodejs version needed by the app ### Provision/Update - Call "n" to install the corresponding nodejs version - Resolve the "actual version" installed (typically if version `20` is requested, the actual version may be `20.1.2`) - This "actual version" is stored as `nodejs_version` in the app settings - Garbage-collect unused versions ### Deprovision - Delete the `nodejs_version` setting - Garbage-collect unused versions --- ## Permissions Configure the SSO permissions/tiles. Typically, webapps are expected to have a 'main' permission mapped to '/', meaning that a tile pointing to the `$domain/$path` will be available in the SSO for users allowed to access that app. Additional permissions can be created, typically to have a specific tile and/or access rules for the admin part of a webapp. The list of allowed user/groups may be initialized using the content of the `init_{perm}_permission` question from the manifest, hence `init_main_permission` replaces the `is_public` question and shall contain a group name (typically, `all_users` or `visitors`). ### Example ```toml [resources.permissions] main.url = "/" # (these two previous lines should be enough in the majority of cases) admin.url = "/admin" admin.show_tile = false admin.allowed = "admins" # Assuming the "admins" group exists (cf future developments ;)) ``` ### Properties (for each perm name) - `url`: The relative URI corresponding to this permission. Typically `/` or `/something`. This property may be omitted for non-web permissions. Can also be a regex, prefixed by `re:` like `re:/api/[A-Z]*$`. - `show_tile`: (default: `true` if `url` is defined) Wether or not a tile should be displayed for that permission in the user portal - `allowed`: (default: nobody) The group initially allowed to access this perm, if `init_{perm}_permission` is not defined in the manifest questions. Note that the admin may tweak who is allowed/unallowed on that permission later on, this is only meant to **initialize** the permission. - `auth_header`: (default: `true`) Define for the URL of this permission, if SSOwat pass the authentication header to the application. Default is true - `protected`: (default: `false`) Define if this permission is protected. If it is protected the administrator won't be able to add or remove the visitors group of this permission. Defaults to 'false'. - `additional_urls`: (default: none) List of additional URL for which access will be allowed/forbidden ### Provision/Update - Delete any permissions that may exist and be related to this app yet is not declared anymore - Loop over the declared permissions and create them if needed or update them with the new values ### Deprovision - Delete all permission related to this app ### Legacy management - Legacy `is_public` setting will be deleted if it exists --- ## Ports Book port(s) to be used by the app, typically to be used to the internal reverse-proxy between nginx and the app process. Note that because multiple ports can be booked, each properties is prefixed by the name of the port. `main` is a special name and will correspond to the setting `$port`, whereas for example `xmpp_client` will correspond to the setting `$port_xmpp_client`. ### Example ```toml [resources.ports] # (empty should be fine for most apps... though you can customize stuff if absolutely needed) main.default = 12345 # if you really want to specify a prefered value .. but shouldnt matter in the majority of cases xmpp_client.default = 5222 # if you need another port, pick a name for it (here, "xmpp_client") xmpp_client.exposed = "TCP" # here, we're telling that the port needs to be publicly exposed on TCP on the firewall ``` ### Properties (for every port name) - `default`: The prefered value for the port. If this port is already being used by another process right now, or is booked in another app's setting, the code will increment the value until it finds a free port and store that value as the setting. If no value is specified, a random value between 10000 and 60000 is used. - `exposed`: (default: `false`) Wether this port should be opened on the firewall and be publicly reachable. This should be kept to `false` for the majority of apps than only need a port for internal reverse-proxying! Possible values: `false`, `true`(=`Both`), `Both`, `TCP`, `UDP`. This will result in the port being opened on the firewall, and the diagnosis checking that a program answers on that port. - `fixed`: (default: `false`) Tells that the app absolutely needs the specific value provided in `default`, typically because it's needed for a specific protocol ### Provision/Update (for every port name) - If not already booked, look for a free port, starting with the `default` value (or a random value between 10000 and 60000 if no `default` set) - If `exposed` is not `false`, open the port in the firewall accordingly - otherwise make sure it's closed. - The value of the port is stored in the `$port` setting for the `main` port, or `$port_NAME` for other `NAME`s ### Deprovision - Close the ports on the firewall if relevant - Deletes all the port settings ### Legacy management - In the past, some settings may have been named `NAME_port` instead of `port_NAME`, in which case the code will automatically rename the old setting. --- ## Ruby Installs a ruby version to be used by the app, using "rbenv" Note that ruby is compiled on the target system, and therefore requires the following dependencies to be installed : `gcc, make, libjemalloc-dev, libffi-dev, libyaml-dev, zlib1g-dev` Sourcing the helpers will then automatically tweak the `PATH` variable such that you may call `ruby` and `gem` directly. Sourcing the helpers will also automatically define: - `$path_with_ruby` to be used in the systemd config (`Environment="PATH=__PATH_WITH_RUBY__"`) - `$ruby_dir`, the directory containing the specific version of ruby, which may be used in the systemd config too (e.g. `ExecStart=__RUBY_DIR__/ruby foo bar`) ### Example ```toml [resources.ruby] version = "3.2" ``` ### Properties - `version`: The ruby version needed by the app ### Provision/Update - Fetch/update a copy of the rbenv tool as well as ruby-build, rbenv-aliases and xxenv-latest - Compute the actual "latest" version for the requested version, e.g. `3.2` may corresponds to `3.2.1` - This "actual version" is stored as `ruby_version` in the app settings - Install (compile) Ruby (may take some time) - Garbage-collect unused versions ### Deprovision - Delete the `ruby_version` setting - Garbage-collect unused versions --- ## Sources Declare what are the sources / assets used by this app. Typically, this corresponds to some tarball published by the upstream project, that needs to be downloaded and extracted in the install dir using the ynh_setup_source helper. This resource is intended both to declare the assets, which will be parsed by ynh_setup_source during the app script runtime, AND to prefetch and validate the sha256sum of those asset before actually running the script, to be able to report an error early when the asset turns out to not be available for some reason. Various options are available to accomodate the behavior according to the asset structure ### Example ```toml [resources.sources] [resources.sources.main] url = "https://github.com/foo/bar/archive/refs/tags/v1.2.3.tar.gz" sha256 = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b" autoupdate.strategy = "latest_github_tag" ``` Or more complex examples with several element, including one with asset that depends on the CPU architecture. With [packaging format v2.x](https://github.com/YunoHost/apps/blob/a5c97003e730dfd2303631a57ade2fc755f960ca/schemas/manifest.v2.schema.json#L169-L172), YunoHost currently supports `amd64`, `armhf`, `arm64` and `i386` architectures. ```toml [resources.sources] [resources.sources.main] in_subdir = false amd64.url = "https://github.com/foo/bar/archive/refs/tags/v1.2.3.amd64.tar.gz" amd64.sha256 = "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b" i386.url = "https://github.com/foo/bar/archive/refs/tags/v1.2.3.386.tar.gz" i386.sha256 = "53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3" armhf.url = "https://github.com/foo/bar/archive/refs/tags/v1.2.3.arm.tar.gz" armhf.sha256 = "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865" autoupdate.strategy = "latest_github_release" autoupdate.asset.amd64 = ".*\\.amd64.tar.gz" autoupdate.asset.i386 = ".*\\.386.tar.gz" autoupdate.asset.armhf = ".*\\.arm.tar.gz" [resources.sources.zblerg] url = "https://zblerg.com/download/zblerg" sha256 = "1121cfccd5913f0a63fec40a6ffd44ea64f9dc135c66634ba001d10bcf4302a2" format = "script" rename = "zblerg.sh" ``` ### Properties (for each source) - `prefetch` : `true` (default) or `false`, wether or not to pre-fetch this asset during the provisioning phase of the resource. If several arch-dependent url are provided, YunoHost will only prefetch the one for the current system architecture. - `url` : the asset's URL - If the asset's URL depend on the architecture, you may instead provide `amd64.url`, `i386.url`, `armhf.url` and `arm64.url` (depending on what architectures are supported), using the same `dpkg --print-architecture` nomenclature as for the supported architecture key in the manifest - `sha256` : the asset's sha256sum. This is used both as an integrity check, and as a layer of security to protect against malicious actors which could have injected malicious code inside the asset... - Same as `url` : if the asset's URL depend on the architecture, you may instead provide `amd64.sha256`, `i386.sha256`, ... - `format` : The "format" of the asset. It is typically automatically guessed from the extension of the URL (or the mention of "tarball", "zipball" in the URL), but can be set explicitly: - `tar.gz`, `tar.xz`, `tar.bz2` : will use `tar` to extract the archive - `zip` : will use `unzip` to extract the archive - `docker` : useful to extract files from an already-built docker image (instead of rebuilding them locally). Will use `docker-image-extract` - `whatever`: whatever arbitrary value, not really meaningful except to imply that the file won't be extracted (eg because it's a .deb to be manually installed with dpkg/apt, or a script, or ...) - `in_subdir`: `true` (default) or `false`, depending on if there's an intermediate subdir in the archive before accessing the actual files. Can also be `N` (an integer) to handle special cases where there's `N` level of subdir to get rid of to actually access the files - `extract` : `true` or `false`. Defaults to `true` for archives such as `zip`, `tar.gz`, `tar.bz2`, ... Or defaults to `false` when `format` is not something that should be extracted. When `extract = false`, the file will only be `mv`ed to the location, possibly renamed using the `rename` value - `rename`: some string like `whatever_your_want`, to be used for convenience when `extract` is `false` and the default name of the file is not practical - `platform`: for example `linux/amd64` (defaults to `linux/$YNH_ARCH`) to be used in conjonction with `format = "docker"` to specify which architecture to extract for #### Regarding `autoupdate` Strictly speaking, this has nothing to do with the actual app install. `autoupdate` is expected to contain metadata for automatic maintenance / update of the app sources info in the manifest. It is meant to be a simpler replacement for "autoupdate" GitHub workflow mechanism. The infos are used by [this script](https://github.com/YunoHost/apps_tools/blob/main/autoupdate_app_sources/autoupdate_app_sources.py) which is ran by the YunoHost infrastructure periodically and will create the corresponding pull request automatically. The script will rely on the code repo specified in `code` in the upstream section of the manifest. The `autoupdate.strategy` is expected to be constructed like this: `latest__` You need to replace the `` in the strategy name by either `github`, `gitlab`, `gitea` or `forgejo`, as the autoupdater supports: - GitHub - GitLab (official and self-hosted instances) - Gitea & Forgejo instances And choose one strategy in the following ones: - `latest__release` : similar to `latest__tag`, but starting from the list of releases. Note that it's the only strategy that provides the changelog link in the PR message. Pre- or draft releases are ignored. Releases may have assets attached to them, in which case you can define: - `autoupdate.asset = "some regex"` (when there's only one asset to use). The regex is used to find the appropriate asset among the list of all assets - or several `autoupdate.asset.$arch = "some_regex"` (when the asset is arch-specific). The regex is used to find the appropriate asset for the specific arch among the list of assets - `latest__tag` : look for the latest tag (by sorting tags and finding the "largest" version). Then using the corresponding tar.gz url. Tags containing `rc`, `beta`, `alpha`, `start` are ignored, and actually any tag which doesn't look like `x.y.z` or `vx.y.z` - `latest__commit` : will use the latest commit on GitHub, and the corresponding tarball. If this is used for the 'main' source, it will also assume that the version is YYYY.MM.DD corresponding to the date of the commit. It is also possible to define `autoupdate.upstream` to use a different Git repository instead of the code repository from the upstream section of the manifest. This can be useful when, for example, the app uses other assets such as plugin from a different repository. If the upstream project provides non-standard tag or release names, you can fix this, with a regex with a matching group. For example, if tags look like `release-v4.1`, put: ```toml autoupdate.version_regex = "^release-v(.*)$" ``` And the autoupdater will use the matched group (here: `4.1`) as the version. You can make sure that your autoupdate strategy is working well immediately (without waiting for the next check on the infra) by doing the following: 1. Clone the apps_tools repository: `https://github.com/YunoHost/apps_tools` 2. In `apps_tools` open a terminal to run the following commands: ```bash # Create test branch git checkout -b localtest # Create a Python virtual environment python -m venv venv source venv/bin/activate # Install dependencies (if you don't have pip already installed on your system, check https://pip.pypa.io/en/stable/installation) pip install -r requirements.txt # Run autoupdate script - replace '/path/to/myapp_ynh' with your actual local app path ./autoupdate_app_sources/autoupdate_app_sources.py '/path/to/myapp_ynh' ``` 3. If the return output includes: - `Apps udpated`, it ran successfully. Note that it will automatically make local changes in your app's `manifest.toml` (which can be discarded as they will be made automatically later online by the YNH infra); - `Apps failed`, the autoupdate stragegy is not working properly - check the debug info; - none of the above but `apps -> Autoupdater just ran, here are the results:`, it ran successfully but the app was already up to date. ### Provision/Update - For elements with `prefetch = true`, will download the asset (for the appropriate architecture) and store them in `/var/cache/yunohost/download/$app/$source_id`, to be later picked up by `ynh_setup_source`. (NB: this only happens during install and upgrade, not restore) ### Deprovision - Nothing (just cleanup the cache) --- ## System User Provision a system user to be used by the app. The username is exactly equal to the app id ### Example ```toml [resources.system_user] # (empty - defaults are usually okay) ``` ### Properties - `allow_ssh`: (default: False) Adds the user to the ssh.app group, allowing SSH connection via this user - `allow_sftp`: (default: False) Adds the user to the sftp.app group, allowing SFTP connection via this user - `allow_email`: (default: False) Enable authentication on the mail stack for the system user and send mail using `__APP__@__DOMAIN__`. A `mail_pwd` setting is automatically defined (similar to `db_pwd` for databases). You can then configure the app to use `__APP__` and `__MAIL_PWD__` as SMTP credentials (with host 127.0.0.1). You can also tweak the user-part of the domain-part of the email used by manually defining a custom setting `mail_user` or `mail_domain` - `home`: (default: `/var/www/__APP__`) Defines the home property for this user. NB: unfortunately you can't simply use `__INSTALL_DIR__` or `__DATA_DIR__` for now ### Provision/Update - will create the system user if it doesn't exists yet - will add/remove the ssh/sftp.app groups ### Deprovision - deletes the user and group ================================================ FILE: docs/dev/50.packaging/20.scripts/20.helpers_v2.0.mdx ================================================ --- title: App helpers (v2) toc_max_heading_level: 4 # custom_edit_link: 'https://github.com/YunoHost/yunohost/tree/dev/helpers/helpers.v2.d' --- Doc auto-generated by [this script](https://github.com/YunoHost/doc/blob/da78370c098ca04b590e18fb1c8924242367703e/scripts/helpers_doc_generate.py) on 09/01/2026 (YunoHost version 12.1.39) ## Sources

This is coupled to the 'sources' resource in the manifest.toml

### Sources
`ynh_setup_source`
Download, check integrity, uncompress and patch the source from app.src
**Usage**: `ynh_setup_source --dest_dir=dest_dir [--source_id=source_id] [--keep="file1 file2"] [--full_replace]` **Arguments**: - `-d`, `--dest_dir=`: Directory where to setup sources - `-s`, `--source_id=`: Name of the source, defaults to `main` (when the sources resource exists in manifest.toml) or (legacy) `app` otherwise - `-k`, `--keep=`: Space-separated list of files/folders that will be backup/restored in $dest_dir, such as a config file you don't want to overwrite. For example 'conf.json secrets.json logs' (no trailing `/` for folders) - `-r`, `--full_replace=`: Remove previous sources before installing new sources (can be 1 or 0, default to 0) **Details**: ##### New 'sources' resources (See also the resources documentation which may be more complete?) This helper will read infos from the 'sources' resources in the manifest.toml of the app and expect a structure like: ```toml [resources.sources] [resources.sources.main] url = "https://some.address.to/download/the/app/archive" sha256 = "0123456789abcdef" # The sha256 sum of the asset obtained from the URL ``` ##### Optional flags ```text format = "tar.gz"/xz/bz2 # automatically guessed from the extension of the URL, but can be set explicitly. Will use `tar` to extract "zip" # automatically guessed from the extension of the URL, but can be set explicitly. Will use `unzip` to extract "docker" # useful to extract files from an already-built docker image (instead of rebuilding them locally). Will use `docker-image-extract` to extract "whatever" # an arbitrary value, not really meaningful except to imply that the file won't be extracted in_subdir = true # default, there's an intermediate subdir in the archive before accessing the actual files false # sources are directly in the archive root n # (special cases) an integer representing a number of subdirs levels to get rid of extract = true # default if file is indeed an archive such as .zip, .tar.gz, .tar.bz2, ... = false # default if file 'format' is not set and the file is not to be extracted because it is not an archive but a script or binary or whatever asset. # in which case the file will only be `mv`ed to the location possibly renamed using the `rename` value rename = "whatever_your_want" # to be used for convenience when `extract` is false and the default name of the file is not practical platform = "linux/amd64" # (defaults to "linux/$YNH_ARCH") to be used in conjonction with `format = "docker"` to specify which architecture to extract for ``` You may also define assets url and checksum per-architectures such as: ```toml [resources.sources] [resources.sources.main] amd64.url = "https://some.address.to/download/the/app/archive/when/amd64" amd64.sha256 = "0123456789abcdef" armhf.url = "https://some.address.to/download/the/app/archive/when/armhf" armhf.sha256 = "fedcba9876543210" ``` In which case `ynh_setup_source --dest_dir="$install_dir"` will automatically pick the appropriate source depending on the arch The helper will: - Download the specific URL if there is no local archive - Check the integrity with the specific sha256 sum - Uncompress the archive to `$dest_dir`. - If `in_subdir` is true, the first level directory of the archive will be removed. - If `in_subdir` is a numeric value, the N first level directories will be removed. - Patches named `sources/patches/${src_id}-*.patch` will be applied to `$dest_dir` - Extra files in `sources/extra_files/$src_id` will be copied to dest_dir Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/sources#L85)
--- ## App Technologies

These allow to install specific version of the technology required to run some apps

## Databases

This is coupled to the 'database' resource in the manifest.toml - at least for mysql/postgresql. Mongodb/redis may have better integration in the future.

### Mysql
`ynh_mysql_connect_as`
Open a connection as a user
**Usage**: `ynh_mysql_connect_as --user=user --password=password [--database=database]` **Arguments**: - `-u`, `--user=`: the user name to connect as - `-p`, `--password=`: the user password - `-d`, `--database=`: the database to connect to **Examples**: - `ynh_mysql_connect_as --user="user" --password="pass" <<< "UPDATE ...;"` - `ynh_mysql_connect_as --user="user" --password="pass" < /path/to/file.sql` **Details**: Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mysql#L33)
`ynh_mysql_execute_as_root`
Execute a command as root user
**Usage**: `ynh_mysql_execute_as_root --sql=sql [--database=database]` **Arguments**: - `-s`, `--sql=`: the SQL command to execute - `-d`, `--database=`: the database to connect to **Details**: Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mysql#L54)
`ynh_mysql_execute_file_as_root`
Execute a command from a file as root user
**Usage**: `ynh_mysql_execute_file_as_root --file=file [--database=database]` **Arguments**: - `-f`, `--file=`: the file containing SQL commands - `-d`, `--database=`: the database to connect to **Details**: Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mysql#L78)
`ynh_mysql_dump_db`
Dump a database
**Usage**: `ynh_mysql_dump_db --database=database` **Arguments**: - `-d`, `--database=`: the database name to dump **Returns**: The mysqldump output **Example**: `ynh_mysql_dump_db --database=roundcube > ./dump.sql` **Details**: Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mysql#L146)
--- ### Postgresql
`ynh_psql_connect_as`
Open a connection as a user
**Usage**: `ynh_psql_connect_as --user=user --password=password [--database=database]` **Arguments**: - `-u`, `--user=`: the user name to connect as - `-p`, `--password=`: the user password - `-d`, `--database=`: the database to connect to **Examples**: - `ynh_psql_connect_as 'user' 'pass' <<< "UPDATE ...;"` - `ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql` **Details**: Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/postgresql#L36)
`ynh_psql_execute_as_root`
Execute a command as root user
**Usage**: `ynh_psql_execute_as_root --sql=sql [--database=database]` **Arguments**: - `-s`, `--sql=`: the SQL command to execute - `-d`, `--database=`: the database to connect to **Details**: Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/postgresql#L57)
`ynh_psql_execute_file_as_root`
Execute a command from a file as root user
**Usage**: `ynh_psql_execute_file_as_root --file=file [--database=database]` **Arguments**: - `-f`, `--file=`: the file containing SQL commands - `-d`, `--database=`: the database to connect to **Details**: Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/postgresql#L82)
`ynh_psql_dump_db`
Dump a database
**Usage**: `ynh_psql_dump_db --database=database` **Arguments**: - `-d`, `--database=`: the database name to dump **Returns**: the psqldump output **Example**: `ynh_psql_dump_db 'roundcube' > ./dump.sql` **Details**: Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/postgresql#L153)
`ynh_psql_database_exists`
Check if a psql database exists
**Usage**: `ynh_psql_database_exists --database=database | exit: Return 1 if the database doesn't exist, 0 otherwise` **Arguments**: - `-d`, `--database=`: the database for which to check existence **Details**: Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/postgresql#L210)
--- ### Mongodb
`ynh_mongo_exec`
Execute a mongo command example: ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("wekan")' example: ynh_mongo_exec --command="db.getMongo().getDBNames().indexOf(\"wekan\")"
**Usage**: `ynh_mongo_exec [--user=user] [--password=password] [--authenticationdatabase=authenticationdatabase] [--database=database] [--host=host] [--port=port] --command="command" [--eval]` **Arguments**: - `-u`, `--user=`: The user name to connect as - `-p`, `--password=`: The user password - `-d`, `--authenticationdatabase=`: The authenticationdatabase to connect to - `-d`, `--database=`: The database to connect to - `-h`, `--host=`: The host to connect to - `-P`, `--port=`: The port to connect to - `-c`, `--command=`: The command to evaluate - `-e`, `--eval`: Evaluate instead of execute the command. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mongodb#L35)
`ynh_mongo_dump_db`
Dump a database
**Usage**: `ynh_mongo_dump_db --database=database` **Arguments**: - `-d`, `--database=`: The database name to dump **Returns**: the mongodump output **Example**: `ynh_mongo_dump_db --database=wekan > ./dump.bson` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mongodb#L144)
`ynh_mongo_database_exists`
Check if a mongo database exists
**Usage**: `ynh_mongo_database_exists --database=database | exit: Return 1 if the database doesn't exist, 0 otherwise` **Arguments**: - `-d`, `--database=`: The database for which to check existence [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mongodb#L189)
`ynh_mongo_restore_db`
Restore a database
**Usage**: `ynh_mongo_restore_db --database=database` **Arguments**: - `-d`, `--database=`: The database name to restore **Example**: `ynh_mongo_restore_db --database=wekan < ./dump.bson` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mongodb#L212)
`ynh_mongo_setup_db`
Create a database, a user and its password. Then store the password in the app's config
**Usage**: `ynh_mongo_setup_db --db_user=user --db_name=name [--db_pwd=pwd]` **Arguments**: - `-u`, `--db_user=`: Owner of the database - `-n`, `--db_name=`: Name of the database - `-p`, `--db_pwd=`: Password of the database. If not provided, a password will be generated **Details**: After executing this helper, the password of the created database will be available in $db_pwd It will also be stored as "mongopwd" into the app settings. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mongodb#L255)
`ynh_mongo_remove_db`
Remove a database if it exists, and the associated user
**Usage**: `ynh_mongo_remove_db --db_user=user --db_name=name` **Arguments**: - `-u`, `--db_user=`: Owner of the database - `-n`, `--db_name=`: Name of the database [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mongodb#L283)
`ynh_install_mongo`
Install MongoDB and integrate MongoDB service in YunoHost
**Usage**: `ynh_install_mongo [--mongo_version=mongo_version]` **Arguments**: - `-m`, `--mongo_version=`: Version of MongoDB to install [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mongodb#L308)
`ynh_remove_mongo`
Remove MongoDB Only remove the MongoDB service integration in YunoHost for now if MongoDB package as been removed
**Usage**: `ynh_remove_mongo` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/mongodb#L351)
--- ### Redis
`ynh_redis_get_free_db`
get the first available redis database
**Usage**: `ynh_redis_get_free_db` **Returns**: the database number to use [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/redis#L25)
`ynh_redis_remove_db`
Create a master password and set up global settings Please always call this script in install and restore scripts
**Usage**: `ynh_redis_remove_db database` **Arguments**: - `database`: the database to erase [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/redis#L52)
--- ## Configurations / Templating ### Templating
`ynh_add_config`
Create a dedicated config file from a template
**Usage**: `ynh_add_config --template="template" --destination="destination"` **Arguments**: - `-t`, `--template=`: Template config file to use - `-d`, `--destination=`: Destination of the config file - `-j`, `--jinja`: Use jinja template instead of the simple `__MY_VAR__` templating format **Examples**: - `ynh_add_config --template=".env" --destination="$install_dir/.env" # (use the template file "conf/.env" from the app's package)` - `ynh_add_config --jinja --template="config.j2" --destination="$install_dir/config" # (use the template file "conf/config.j2" from the app's package)` **Details**: The template can be by default the name of a file in the conf directory of a YunoHost Package, a relative path or an absolute path. The helper will use the template `template` to generate a config file `destination` by replacing the following keywords with global variables that should be defined before calling this helper : ``` __PATH__ by $path_url __NAME__ by $app __NAMETOCHANGE__ by $app __USER__ by $app __FINALPATH__ by $final_path __PHPVERSION__ by $YNH_PHP_VERSION (packaging v1 only, packaging v2 uses phpversion setting implicitly set by apt resource) __YNH_NODE_LOAD_PATH__ by $ynh_node_load_PATH ``` And any dynamic variables that should be defined before calling this helper like: ``` __DOMAIN__ by $domain __APP__ by $app __VAR_1__ by $var_1 __VAR_2__ by $var_2 ``` ##### When --jinja is enabled This option is meant for advanced use-cases where the "simple" templating mode ain't enough because you need conditional blocks or loops. For a full documentation of jinja's syntax you can refer to: https://jinja.palletsprojects.com/en/3.1.x/templates/ Note that in YunoHost context, all variables are from shell variables and therefore are strings ##### Keeping track of manual changes by the admin The helper will verify the checksum and backup the destination file if it's different before applying the new template. And it will calculate and store the destination file checksum into the app settings when configuration is done. Requires YunoHost version 4.1.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/templating#L74)
`ynh_read_var_in_file`
Get a value from heterogeneous file (yaml, json, php, python...)
**Usage**: `ynh_read_var_in_file --file=PATH --key=KEY` **Arguments**: - `-f`, `--file=`: the path to the file - `-k`, `--key=`: the key to get - `-a`, `--after=`: the line just before the key (in case of multiple lines with the name of the key in the file) **Details**: This helpers match several var affectation use case in several languages We don't use jq or equivalent to keep comments and blank space in files This helpers work line by line, it is not able to work correctly if you have several identical keys in your files Example of line this helpers can managed correctly .yml title: YunoHost documentation email: 'yunohost@yunohost.org' .json "theme": "colib'ris", "port": 8102 "some_boolean": false, "user": null .ini some_boolean = On action = "Clear" port = 20 .php $user= user => 20 .py USER = 8102 user = 'https://donate.local' CUSTOM['user'] = 'YunoHost' Requires YunoHost version 4.3 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/templating#L240)
`ynh_write_var_in_file`
Set a value into heterogeneous file (yaml, json, php, python...)
**Usage**: `ynh_write_var_in_file --file=PATH --key=KEY --value=VALUE` **Arguments**: - `-f`, `--file=`: the path to the file - `-k`, `--key=`: the key to set - `-v`, `--value=`: the value to set - `-a`, `--after=`: the line just before the key (in case of multiple lines with the name of the key in the file) **Details**: Requires YunoHost version 4.3 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/templating#L318)
--- ### Nginx
`ynh_add_nginx_config`
Create a dedicated nginx config
**Usage**: `ynh_add_nginx_config` **Details**: This will use a template in `../conf/nginx.conf` See the documentation of `ynh_add_config` for a description of the template format and how placeholders are replaced with actual variables. Additionally, ynh_add_nginx_config will replace: - `#sub_path_only` by empty string if `path_url` is not `'/'` - `#root_path_only` by empty string if `path_url` *is* `'/'` This allows to enable/disable specific behaviors dependenging on the install location Requires YunoHost version 4.1.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/nginx#L37)
`ynh_remove_nginx_config`
Remove the dedicated nginx config
**Usage**: `ynh_remove_nginx_config` **Details**: Requires YunoHost version 2.7.2 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/nginx#L64)
`ynh_change_url_nginx_config`
Regen the nginx config in a change url context
**Usage**: `ynh_change_url_nginx_config` **Details**: Requires YunoHost version 11.1.9 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/nginx#L74)
--- ### Php
`ynh_add_fpm_config`
Create a dedicated PHP-FPM config
**Usage**: `ynh_add_fpm_config` **Details**: Case 1 (recommended) : your provided a snippet conf/extra_php-fpm.conf The actual PHP configuration will be automatically generated, and your extra_php-fpm.conf will be appended (typically contains PHP upload limits) The resulting configuration will be deployed to the appropriate place, /etc/php/$phpversion/fpm/pool.d/$app.conf Performance-related options in the PHP conf, such as : pm.max_children, pm.start_servers, pm.min_spare_servers pm.max_spare_servers are computed from two parameters called "usage" and "footprint" which can be set to low/medium/high. (cf details below) If you wish to tweak those, please initialize the settings `fpm_usage` and `fpm_footprint` *prior* to calling this helper. Otherwise, "low" will be used as a default for both values. Otherwise, if you want the user to have control over these, we encourage to create a config panel (which should ultimately be standardized by the core ...) Case 2 (deprecate) : you provided an entire conf/php-fpm.conf The configuration will be hydrated, replacing __FOOBAR__ placeholders with $foobar values, etc. The resulting configuration will be deployed to the appropriate place, /etc/php/$phpversion/fpm/pool.d/$app.conf ---------------------- fpm_footprint: Memory footprint of the service (low/medium/high). low - Less than 20 MB of RAM by pool. medium - Between 20 MB and 40 MB of RAM by pool. high - More than 40 MB of RAM by pool. N - Or you can specify a quantitative footprint as MB by pool (use watch -n0.5 ps -o user,cmd,%cpu,rss -u APP) fpm_usage: Expected usage of the service (low/medium/high). low - Personal usage, behind the SSO. medium - Low usage, few people or/and publicly accessible. high - High usage, frequently visited website. The footprint of the service will be used to defined the maximum footprint we can allow, which is half the maximum RAM. So it will be used to defined 'pm.max_children' A lower value for the footprint will allow more children for 'pm.max_children'. And so for 'pm.start_servers', 'pm.min_spare_servers' and 'pm.max_spare_servers' which are defined from the value of 'pm.max_children' NOTE: 'pm.max_children' can't exceed 4 times the number of processor's cores. The usage value will defined the way php will handle the children for the pool. A value set as 'low' will set the process manager to 'ondemand'. Children will start only if the service is used, otherwise no child will stay alive. This config gives the lower footprint when the service is idle. But will use more proc since it has to start a child as soon it's used. Set as 'medium', the process manager will be at dynamic. If the service is idle, a number of children equal to pm.min_spare_servers will stay alive. So the service can be quick to answer to any request. The number of children can grow if needed. The footprint can stay low if the service is idle, but not null. The impact on the proc is a little bit less than 'ondemand' as there's always a few children already available. Set as 'high', the process manager will be set at 'static'. There will be always as many children as 'pm.max_children', the footprint is important (but will be set as maximum a quarter of the maximum RAM) but the impact on the proc is lower. The service will be quick to answer as there's always many children ready to answer. Requires YunoHost version 4.1.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/php#L88)
`ynh_remove_fpm_config`
Remove the dedicated PHP-FPM config
**Usage**: `ynh_remove_fpm_config` **Details**: Requires YunoHost version 2.7.2 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/php#L223)
--- ### Systemd
`ynh_add_systemd_config`
Create a dedicated systemd config
**Usage**: `ynh_add_systemd_config [--service=service] [--template=template]` **Arguments**: - `-s`, `--service=`: Service name (optionnal, `$app` by default) - `-t`, `--template=`: Name of template file (optionnal, this is 'systemd' by default, meaning `../conf/systemd.service` will be used as template) **Details**: This will use the template `../conf/.service`. See the documentation of `ynh_add_config` for a description of the template format and how placeholders are replaced with actual variables. Requires YunoHost version 4.1.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/systemd#L33)
`ynh_remove_systemd_config`
Remove the dedicated systemd config
**Usage**: `ynh_remove_systemd_config [--service=service]` **Arguments**: - `-s`, `--service=`: Service name (optionnal, $app by default) **Details**: Requires YunoHost version 2.7.2 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/systemd#L56)
`ynh_systemd_action`
Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
**Usage**: `ynh_systemd_action [--service_name=service_name] [--action=action] [ [--line_match="line to match"] [--log_path=log_path] [--timeout=300] [--length=20] ]` **Arguments**: - `-n`, `--service_name=`: Name of the service to start. Default : `$app` - `-a`, `--action=`: Action to perform with systemctl. Default: start - `-l`, `--line_match=`: Line to match - The line to find in the log to attest the service have finished to boot. If not defined it don't wait until the service is completely started. - `-p`, `--log_path=`: Log file - Path to the log file. Default : `/var/log/$app/$app.log` - `-t`, `--timeout=`: Timeout - The maximum time to wait before ending the watching. Default : 300 seconds. - `-e`, `--length=`: Length of the error log displayed for debugging : Default : 20 **Details**: Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/systemd#L85)
--- ### Fail2ban
`ynh_add_fail2ban_config`
Create a dedicated fail2ban config (jail and filter conf files)
**Usage**: `1: ynh_add_fail2ban_config --logpath=log_file --failregex=filter [--max_retry=max_retry] [--ports=ports] 2: ynh_add_fail2ban_config --use_template` **Arguments**: - `-l`, `--logpath=`: Log file to be checked by fail2ban - `-r`, `--failregex=`: Failregex to be looked for by fail2ban - `-m`, `--max_retry=`: Maximum number of retries allowed before banning IP address - default: 3 - `-p`, `--ports=`: Ports blocked for a banned IP address - default: http,https - `-t`, `--use_template`: Use this helper in template mode **Details**: This will use a template in `../conf/f2b_jail.conf` and `../conf/f2b_filter.conf` See the documentation of `ynh_add_config` for a description of the template format and how placeholders are replaced with actual variables. Generally your template will look like that by example (for synapse): ``` f2b_jail.conf: [__APP__] enabled = true port = http,https filter = __APP__ logpath = /var/log/__APP__/logfile.log maxretry = 3 ``` ``` f2b_filter.conf: [INCLUDES] before = common.conf [Definition] # Part of regex definition (just used to make more easy to make the global regex) __synapse_start_line = .? \- synapse\..+ \- # Regex definition. failregex = ^%(__synapse_start_line)s INFO \- POST\-(\d+)\- \- \d+ \- Received request\: POST /_matrix/client/r0/login\??%(__synapse_start_line)s INFO \- POST\-\1\- Got login request with identifier: \{u'type': u'm.id.user', u'user'\: u'(.+?)'\}, medium\: None, address: None, user\: u'\5'%(__synapse_start_line)s WARNING \- \- (Attempted to login as @\5\:.+ but they do not exist|Failed password login for user @\5\:.+)$ ignoreregex = ``` ##### Note about the "failregex" option: regex to match the password failure messages in the logfile. The host must be matched by a group named "`host`". The tag "``" can be used for standard IP/hostname matching and is only an alias for `(?:::f{4,6}:)?(?P[\w\-.^_]+)` You can find some more explainations about how to make a regex here : https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters To validate your regex you can test with this command: ``` fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf ``` Requires YunoHost version 4.1.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/fail2ban#L76)
`ynh_remove_fail2ban_config`
Remove the dedicated fail2ban config (jail and filter conf files)
**Usage**: `ynh_remove_fail2ban_config` **Details**: Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/fail2ban#L148)
--- ### Logrotate
`ynh_use_logrotate`
Use logrotate to manage the logfile
**Usage**: `ynh_use_logrotate [--logfile=/log/file] [--specific_user=user/group]` **Arguments**: - `-l`, `--logfile=`: absolute path of logfile - `-u`, `--specific_user=`: run logrotate as the specified user and group. If not specified logrotate is runned as root. **Details**: If no `--logfile` is provided, `/var/log/$app` will be used as default. `logfile` can point to a directory or a file. Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logrotate#L33)
`ynh_remove_logrotate`
Remove the app's logrotate config.
**Usage**: `ynh_remove_logrotate` **Details**: Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logrotate#L113)
--- ## Misc Tools ### Utils
`ynh_local_curl`
Curl abstraction to help with POST requests to local pages (such as installation forms)
**Usage**: `ynh_local_curl "page_uri" "key1=value1" "key2=value2" ...` **Arguments**: - `page_uri`: Path (relative to `$path_url`) of the page where POST data will be sent - `key1=value1`: (Optionnal) POST key and corresponding value - `key2=value2`: (Optionnal) Another POST key and corresponding value - `...`: (Optionnal) More POST keys and values **Example**: `ynh_local_curl "/install.php?installButton" "foo=$var1" "bar=$var2"` **Details**: For multiple calls, cookies are persisted between each call for the same app `$domain` and `$path_url` should be defined externally (and correspond to the domain.tld and the /path (of the app?)) Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/utils#L106)
`ynh_secure_remove`
Remove a file or a directory securely
**Usage**: `ynh_secure_remove --file=path_to_remove` **Arguments**: - `-f`, `--file=`: File or directory to remove **Details**: Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/utils#L189)
`ynh_read_manifest`
Read the value of a key in a ynh manifest file
**Usage**: `ynh_read_manifest --manifest="manifest.json" --manifest_key="key"` **Arguments**: - `-m`, `--manifest=`: Path of the manifest to read - `-k`, `--manifest_key=`: Name of the key to find **Returns**: the value associate to that key **Details**: Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/utils#L223)
`ynh_app_upstream_version`
Read the upstream version from the manifest or `$YNH_APP_MANIFEST_VERSION`
**Usage**: `ynh_app_upstream_version [--manifest="manifest.json"]` **Arguments**: - `-m`, `--manifest=`: Path of the manifest to read **Returns**: the version number of the upstream app **Details**: If the `manifest` is not specified, the envvar `$YNH_APP_MANIFEST_VERSION` will be used. The version number in the manifest is defined by `~ynh`. For example, if the manifest contains `4.3-2~ynh3` the function will return `4.3-2` Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/utils#L263)
`ynh_check_app_version_changed`
Checks the app version to upgrade with the existing app version and returns:
**Usage**: `ynh_check_app_version_changed` **Returns**: `UPGRADE_APP` if the upstream version changed, `UPGRADE_PACKAGE` otherwise. **Details**: This helper should be used to avoid an upgrade of an app, or the upstream part of it, when it's not needed Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/utils#L315)
`ynh_compare_current_package_version`
Compare the current package version against another version given as an argument.
**Usage**: `ynh_compare_current_package_version --comparison (lt|le|eq|ne|ge|gt) --version ` **Arguments**: - `--comparison`: Comparison type. Could be : `lt` (lower than), `le` (lower or equal), `eq` (equal), `ne` (not equal), `ge` (greater or equal), `gt` (greater than) - `--version`: The version to compare. Need to be a version in the yunohost package version type (like `2.3.1~ynh4`) **Returns**: 0 if the evaluation is true, 1 if false. **Example**: `ynh_compare_current_package_version --comparison lt --version 2.3.2~ynh1` **Details**: This helper is usually used when we need to do some actions only for some old package versions. Generally you might probably use it as follow in the upgrade script : ``` if ynh_compare_current_package_version --comparison lt --version 2.3.2~ynh1 then # Do something that is needed for the package version older than 2.3.2~ynh1 fi ``` Requires YunoHost version 3.8.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/utils#L345)
`ynh_user_exists`
Check if a YunoHost user exists
**Usage**: `ynh_user_exists --username=username` **Arguments**: - `-u`, `--username=`: the username to check **Returns**: 0 if the user exists, 1 otherwise. **Example**: `ynh_user_exists 'toto' || echo "User does not exist"` **Details**: Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/utils#L422)
`ynh_user_get_info`
Retrieve a YunoHost user information
**Usage**: `ynh_user_get_info --username=username --key=key` **Arguments**: - `-u`, `--username=`: the username to retrieve info from - `-k`, `--key=`: the key to retrieve **Returns**: the value associate to that key **Example**: `mail=$(ynh_user_get_info --username="toto" --key=mail)` **Details**: Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/utils#L443)
`ynh_user_list`
Get the list of YunoHost users
**Usage**: `ynh_user_list` **Returns**: one username per line as strings **Example**: `for u in $(ynh_user_list); do ... ; done` **Details**: Requires YunoHost version 2.4.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/utils#L463)
--- ### Setting
`ynh_app_setting_get`
Get an application setting
**Usage**: `ynh_app_setting_get --app=app --key=key` **Arguments**: - `-a`, `--app=`: the application id - `-k`, `--key=`: the setting to get **Details**: Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/setting#L28)
`ynh_app_setting_set`
Set an application setting
**Usage**: `ynh_app_setting_set --app=app --key=key --value=value` **Arguments**: - `-a`, `--app=`: the application id - `-k`, `--key=`: the setting name to set - `-v`, `--value=`: the setting value to set **Details**: When choosing the setting key's name, note that including the following keywords will make the associated setting's value appear masked in the debug logs (cf. [related code](https://github.com/YunoHost/yunohost/blob/216210d5e97070b85c96ebb4548c6abf36987771/src/log.py#L571)): `pwd`, `pass`, `passwd`, `password`, `passphrase`, `secret\w*` (regex), `\w+key` (regex), `token`, `PASSPHRASE` This is meant to allow sharing the logs while preserving confidential data, but having this in mind is useful would you expect to see those values while debugging your scripts. Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/setting#L53)
`ynh_app_setting_set_default`
Set an application setting but only if the "$key" variable ain't set yet
**Usage**: `ynh_app_setting_set_default --app=app --key=key --value=value` **Arguments**: - `-a`, `--app=`: the application id - `-k`, `--key=`: the setting name to set - `-v`, `--value=`: the default setting value to set **Details**: Note that it doesn't just define the setting but ALSO define the $foobar variable Hence it's meant as a replacement for this legacy overly complex syntax: ``` if [ -z "${foo:-}" ] then foo="bar" ynh_app_setting_set --key="foo" --value="$foo" fi ``` Requires YunoHost version 11.1.16 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/setting#L88)
`ynh_app_setting_delete`
Delete an application setting
**Usage**: `ynh_app_setting_delete --app=app --key=key` **Arguments**: - `-a`, `--app=`: the application id - `-k`, `--key=`: the setting to delete **Details**: Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/setting#L113)
--- ### String
`ynh_string_random`
Generate a random string
**Usage**: `ynh_string_random [--length=string_length]` **Arguments**: - `-l`, `--length=`: the string length to generate (default: 24) - `-f`, `--filter=`: the kind of characters accepted in the output (default: 'A-Za-z0-9') **Returns**: the generated string **Example**: `pwd=$(ynh_string_random --length=8)` **Details**: Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/string#L31)
`ynh_replace_string`
Substitute/replace a string (or expression) by another in a file
**Usage**: `ynh_replace_string --match_string=match_string --replace_string=replace_string --target_file=target_file` **Arguments**: - `-m`, `--match_string=`: String to be searched and replaced in the file - `-r`, `--replace_string=`: String that will replace matches - `-f`, `--target_file=`: File in which the string will be replaced. **Details**: As this helper is based on sed command, regular expressions and references to sub-expressions can be used (see sed manual page for more information) Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/string#L56)
`ynh_replace_special_string`
Substitute/replace a special string by another in a file
**Usage**: `ynh_replace_special_string --match_string=match_string --replace_string=replace_string --target_file=target_file` **Arguments**: - `-m`, `--match_string=`: String to be searched and replaced in the file - `-r`, `--replace_string=`: String that will replace matches - `-t`, `--target_file=`: File in which the string will be replaced. **Details**: This helper will use ynh_replace_string, but as you can use special characters, you can't use some regular expressions and sub-expressions. Requires YunoHost version 2.7.7 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/string#L87)
--- ### Backup
`ynh_backup`
Add a file or a directory to the list of paths to backup
**Usage**: `ynh_backup --src_path=src_path [--dest_path=dest_path] [--is_big] [--not_mandatory]` **Arguments**: - `-s`, `--src_path=`: file or directory to bind or symlink or copy. it shouldn't be in the backup dir. - `-d`, `--dest_path=`: destination file or directory inside the backup dir - `-b`, `--is_big`: Indicate data are big (mail, video, image ...) - `-m`, `--not_mandatory`: Indicate that if the file is missing, the backup can ignore it. **Details**: This helper can be used both in a system backup hook, and in an app backup script `ynh_backup` writes `src_path` and the relative `dest_path` into a CSV file, and it creates the parent destination directory If `dest_path` is ended by a slash it complete this path with the basename of `src_path`. Example in the context of a WordPress app : ``` ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" # => This line will be added into CSV file # "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf" ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "conf/nginx.conf" # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/nginx.conf" ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "conf/" # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf" ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "conf" # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf" #Deprecated usages (maintained for retro-compatibility) ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "${backup_dir}/conf/nginx.conf" # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/nginx.conf" ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "/conf/" # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf" ``` How to use `--is_big`: `--is_big` is used to specify that this part of the backup can be quite huge. So, you don't want that your package does backup that part during ynh_backup_before_upgrade. In the same way, an user may doesn't want to backup this big part of the app for each of his backup. And so handle that part differently. As this part of your backup may not be done, your restore script has to handle it. In your restore script, use `--not_mandatory` with `ynh_restore_file` As well in your remove script, you should not remove those data ! Or an user may end up with a failed upgrade restoring an app without data anymore ! To have the benefit of `--is_big` while doing a backup, you can whether set the environement variable `BACKUP_CORE_ONLY` to 1 (`BACKUP_CORE_ONLY=1`) before the backup command. It will affect only that backup command. Or set the config `do_not_backup_data` to 1 into the `settings.yml` of the app. This will affect all backups for this app until the setting is removed. Requires YunoHost version 2.4.0 or higher. Requires YunoHost version 3.5.0 or higher for the argument `--not_mandatory` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/backup#L82)
`ynh_restore`
Restore all files that were previously backuped in a core backup script or app backup script
**Usage**: `ynh_restore` **Details**: Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/backup#L197)
`ynh_restore_file`
Restore a file or a directory
**Usage**: `ynh_restore_file --origin_path=origin_path [--dest_path=dest_path] [--not_mandatory]` **Arguments**: - `-o`, `--origin_path=`: Path where was located the file or the directory before to be backuped or relative path to $YNH_CWD where it is located in the backup archive - `-d`, `--dest_path=`: Path where restore the file or the dir. If unspecified, the destination will be `ORIGIN_PATH` or if the `ORIGIN_PATH` doesn't exist in the archive, the destination will be searched into `backup.csv` - `-m`, `--not_mandatory`: Indicate that if the file is missing, the restore process can ignore it. **Examples**: - `ynh_restore_file -o "/etc/nginx/conf.d/$domain.d/$app.conf"` - `You can also use relative paths:` - `ynh_restore_file -o "conf/nginx.conf"` **Details**: Use the registered path in backup_list by ynh_backup to restore the file at the right place. If `DEST_PATH` already exists and is lighter than 500 Mo, a backup will be made in `/var/cache/yunohost/appconfbackup/`. Otherwise, the existing file is removed. if `apps/$app/etc/nginx/conf.d/$domain.d/$app.conf` exists, restore it into `/etc/nginx/conf.d/$domain.d/$app.conf` if no, search for a match in the csv (eg: conf/nginx.conf) and restore it into `/etc/nginx/conf.d/$domain.d/$app.conf` Requires YunoHost version 2.6.4 or higher. Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/backup#L256)
`ynh_store_file_checksum`
Calculate and store a file checksum into the app settings
**Usage**: `ynh_store_file_checksum --file=file` **Arguments**: - `-f`, `--file=`: The file on which the checksum will performed, then stored. **Details**: $app should be defined when calling this helper Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/backup#L323)
`ynh_backup_if_checksum_is_different`
Verify the checksum and backup the file if it's different
**Usage**: `ynh_backup_if_checksum_is_different --file=file` **Arguments**: - `-f`, `--file=`: The file on which the checksum test will be perfomed. **Returns**: the name of a backup file, or nothing **Details**: This helper is primarily meant to allow to easily backup personalised/manually modified config files. Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/backup#L374)
`ynh_delete_file_checksum`
Delete a file checksum from the app settings
**Usage**: `ynh_delete_file_checksum --file=file` **Arguments**: - `-f`, `--file=`: The file for which the checksum will be deleted **Details**: $app should be defined when calling this helper Requires YunoHost version 3.3.1 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/backup#L413)
--- ### Logging
`ynh_die`
Print a message to stderr and exit
**Usage**: `ynh_die --message=MSG [--ret_code=RETCODE]` **Arguments**: - `-m`, `--message=`: Message to display - `-c`, `--ret_code=`: Exit code to exit with **Details**: Requires YunoHost version 2.4.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L28)
`ynh_print_info`
Display a message in the 'INFO' logging category
**Usage**: `ynh_print_info --message="Some message"` **Arguments**: - `-m`, `--message=`: Message to display **Details**: Requires YunoHost version 3.2.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L48)
`ynh_print_warn`
Print a warning on stderr
**Usage**: `ynh_print_warn --message="Text to print"` **Arguments**: - `-m`, `--message=`: The text to print **Details**: Requires YunoHost version 3.2.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L74)
`ynh_print_err`
Print an error on stderr
**Usage**: `ynh_print_err --message="Text to print"` **Arguments**: - `-m`, `--message=`: The text to print **Details**: Requires YunoHost version 3.2.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L91)
`ynh_exec_err`
Execute a command and print the result as an error
**Usage**: `ynh_exec_err your command and args` **Arguments**: - `command`: command to execute **Details**: Note that you should NOT quote the command but only prefix it with ynh_exec_err Requires YunoHost version 3.2.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L110)
`ynh_exec_warn`
Execute a command and print the result as a warning
**Usage**: `ynh_exec_warn your command and args` **Arguments**: - `command`: command to execute **Details**: Note that you should NOT quote the command but only prefix it with ynh_exec_warn Requires YunoHost version 3.2.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L130)
`ynh_exec_warn_less`
Execute a command and force the result to be printed on stdout
**Usage**: `ynh_exec_warn_less your command and args` **Arguments**: - `command`: command to execute **Details**: Note that you should NOT quote the command but only prefix it with ynh_exec_warn Requires YunoHost version 3.2.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L150)
`ynh_exec_quiet`
Execute a command and redirect stdout in /dev/null
**Usage**: `ynh_exec_quiet your command and args` **Arguments**: - `command`: command to execute **Details**: Note that you should NOT quote the command but only prefix it with ynh_exec_warn Requires YunoHost version 3.2.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L170)
`ynh_exec_fully_quiet`
Execute a command and redirect stdout and stderr in /dev/null
**Usage**: `ynh_exec_quiet your command and args` **Arguments**: - `command`: command to execute **Details**: Note that you should NOT quote the command but only prefix it with ynh_exec_quiet Requires YunoHost version 3.2.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L190)
`ynh_exec_and_print_stderr_only_if_error`
Execute a command and redirect stderr in /dev/null. Print stderr on error.
**Usage**: `ynh_exec_and_print_stderr_only_if_error your command and args` **Arguments**: - `command`: command to execute **Details**: Note that you should NOT quote the command but only prefix it with ynh_exec_and_print_stderr_only_if_error Requires YunoHost version 11.2 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L210)
`ynh_script_progression`
Print a progress bar showing the progression of an app script
**Usage**: `ynh_script_progression --message=message [--weight=weight] [--time]` **Arguments**: - `-m`, `--message=`: The text to print - `-w`, `--weight=`: The weight for this progression. This value is 1 by default. Use a bigger value for a longer part of the script. - `-t`, `--time`: Print the execution time since the last call to this helper. Especially usefull to define weights. The execution time is given for the duration since the previous call. So the weight should be applied to this previous call. - `-l`, `--last`: Use for the last call of the helper, to fill the progression bar. **Details**: Requires YunoHost version 3.5.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L270)
`ynh_return`
Return data to the YunoHost core for later processing (to be used by special hooks like app config panel and core diagnosis)
**Usage**: `ynh_return somedata` **Details**: Requires YunoHost version 3.6.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/logging#L358)
--- ### Multimedia
`ynh_multimedia_build_main_dir`
Initialize the multimedia directory system
**Usage**: `ynh_multimedia_build_main_dir` **Details**: Requires YunoHost version 4.2 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/multimedia#L29)
`ynh_multimedia_addfolder`
Add a directory in yunohost.multimedia
**Usage**: `ynh_multimedia_addfolder --source_dir="source_dir" --dest_dir="dest_dir"` **Arguments**: - `-s`, `--source_dir=`: Source directory - The real directory which contains your medias. - `-d`, `--dest_dir=`: Destination directory - The name and the place of the symbolic link, relative to "/home/yunohost.multimedia" **Details**: This "directory" will be a symbolic link to a existing directory. Requires YunoHost version 4.2 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/multimedia#L90)
`ynh_multimedia_addaccess`
Allow an user to have an write authorisation in multimedia directories
**Usage**: `ynh_multimedia_addaccess user_name` **Arguments**: - `-u`, `--user_name=`: The name of the user which gain this access. **Details**: Requires YunoHost version 4.2 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/multimedia#L119)
--- ## Deprecated Or Handled By The Core / App Resources Since V2 ### Permission
`ynh_permission_create`
Create a new permission for the app
**Usage**: `ynh_permission_create --permission="permission" [--url="url"] [--additional_urls="second-url" [ "third-url" ]] [--auth_header=true|false] [--allowed=group1 [ group2 ]] [--show_tile=true|false] [--protected=true|false]` **Arguments**: - `-p`, `--permission=`: the name for the permission (by default a permission named "main" already exist) - `-u`, `--url=`: (optional) URL for which access will be allowed/forbidden. Note that if 'show_tile' is enabled, this URL will be the URL of the tile. - `-A`, `--additional_urls=`: (optional) List of additional URL for which access will be allowed/forbidden - `-h`, `--auth_header=`: (optional) Define for the URL of this permission, if SSOwat pass the authentication header to the application. Default is true - `-a`, `--allowed=`: (optional) A list of group/user to allow for the permission - `-t`, `--show_tile=`: (optional) Define if a tile will be shown in the SSO. If yes the name of the tile will be the 'label' parameter. Defaults to false for the permission different than 'main'. - `-P`, `--protected=`: (optional) Define if this permission is protected. If it is protected the administrator won't be able to add or remove the visitors group of this permission. Defaults to 'false'. **Details**: Example 1: `ynh_permission_create --permission=admin --url=/admin --additional_urls=domain.tld/admin /superadmin --allowed=alice bob \ --show_tile=true` This example will create a new permission permission with this following effect: - A tile named "My app admin" in the SSO will be available for the users alice and bob. This tile will point to the relative url '/admin'. - Only the user alice and bob will have the access to theses following url: /admin, domain.tld/admin, /superadmin Example 2: ynh_permission_create --permission=api --url=domain.tld/api --auth_header=false --allowed=visitors \ --protected=true This example will create a new protected permission. So the admin won't be able to add/remove the visitors group of this permission. In case of an API with need to be always public it avoid that the admin break anything. With this permission all client will be allowed to access to the url 'domain.tld/api'. Note that in this case no tile will be show on the SSO. Note that the auth_header parameter is to 'false'. So no authentication header will be passed to the application. Generally the API is requested by an application and enabling the auth_header has no advantage and could bring some issues in some case. So in this case it's better to disable this option for all API. If provided, 'url' or 'additional_urls' is assumed to be relative to the app domain/path if they start with '/'. For example: / -> domain.tld/app /admin -> domain.tld/app/admin domain.tld/app/api -> domain.tld/app/api 'url' or 'additional_urls' can be treated as a PCRE (not lua) regex if it starts with "re:". For example: re:/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ re:domain.tld/app/api/[A-Z]*$ -> domain.tld/app/api/[A-Z]*$ Note that globally the parameter 'url' and 'additional_urls' are same. The only difference is: - 'url' is only one url, 'additional_urls' can be a list of urls. There are no limitation of 'additional_urls' - 'url' is used for the url of tile in the SSO (if enabled with the 'show_tile' parameter) About the authentication header (auth_header parameter). The SSO pass (by default) to the application theses following HTTP header (linked to the authenticated user) to the application: - "Auth-User": username - "Remote-User": username - "Email": user email Generally this feature is usefull to authenticate automatically the user in the application but in some case the application don't work with theses header and theses header need to be disabled to have the application to work correctly. See https://github.com/YunoHost/issues/issues/1420 for more informations Requires YunoHost version 3.7.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/permission#L83)
`ynh_permission_delete`
Remove a permission for the app (note that when the app is removed all permission is automatically removed)
**Usage**: `ynh_permission_delete --permission="permission"` **Arguments**: - `-p`, `--permission=`: the name for the permission (by default a permission named "main" is removed automatically when the app is removed) **Example**: `ynh_permission_delete --permission=editors` **Details**: Requires YunoHost version 3.7.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/permission#L161)
`ynh_permission_exists`
Check if a permission exists
**Usage**: `ynh_permission_exists --permission=permission | exit: Return 1 if the permission doesn't exist, 0 otherwise` **Arguments**: - `-p`, `--permission=`: the permission to check **Details**: Requires YunoHost version 3.7.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/permission#L178)
`ynh_permission_url`
Redefine the url associated to a permission
**Usage**: `ynh_permission_url --permission "permission" [--url="url"] [--add_url="new-url" [ "other-new-url" ]] [--remove_url="old-url" [ "other-old-url" ]] [--auth_header=true|false] [--clear_urls]` **Arguments**: - `-p`, `--permission=`: the name for the permission (by default a permission named "main" is removed automatically when the app is removed) - `-u`, `--url=`: (optional) URL for which access will be allowed/forbidden. Note that if you want to remove url you can pass an empty sting as arguments (""). - `-a`, `--add_url=`: (optional) List of additional url to add for which access will be allowed/forbidden. - `-r`, `--remove_url=`: (optional) List of additional url to remove for which access will be allowed/forbidden - `-h`, `--auth_header=`: (optional) Define for the URL of this permission, if SSOwat pass the authentication header to the application - `-c`, `--clear_urls`: (optional) Clean all urls (url and additional_urls) **Details**: Requires YunoHost version 3.7.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/permission#L201)
`ynh_permission_update`
Update a permission for the app
**Usage**: `ynh_permission_update --permission "permission" [--add="group" ["group" ...]] [--remove="group" ["group" ...]] [--show_tile=true|false] [--protected=true|false]` **Arguments**: - `-p`, `--permission=`: the name for the permission (by default a permission named "main" already exist) - `-a`, `--add=`: the list of group or users to enable add to the permission - `-r`, `--remove=`: the list of group or users to remove from the permission - `-t`, `--show_tile=`: (optional) Define if a tile will be shown in the SSO - `-P`, `--protected=`: (optional) Define if this permission is protected. If it is protected the administrator won't be able to add or remove the visitors group of this permission. **Details**: Requires YunoHost version 3.7.0 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/permission#L268)
`ynh_permission_has_user`
Check if a permission has an user
**Usage**: `ynh_permission_has_user --permission=permission --user=user | exit: Return 1 if the permission doesn't have that user or doesn't exist, 0 otherwise` **Arguments**: - `-p`, `--permission=`: the permission to check - `-u`, `--user=`: the user seek in the permission **Example**: `ynh_permission_has_user --permission=main --user=visitors` **Details**: Requires YunoHost version 3.7.1 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/permission#L331)
`ynh_legacy_permissions_exists`
Check if a legacy permissions exist
**Usage**: `ynh_legacy_permissions_exists | exit: Return 1 if the permission doesn't exist, 0 otherwise` **Details**: Requires YunoHost version 4.1.2 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/permission#L361)
`ynh_legacy_permissions_delete_all`
Remove all legacy permissions
**Usage**: `ynh_legacy_permissions_delete_all` **Example**: `if ynh_legacy_permissions_exists then ynh_legacy_permissions_delete_all # You can recreate the required permissions here with ynh_permission_create fi Requires YunoHost version 4.1.2 or higher.` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/permission#L381)
--- ### Apt
`ynh_package_is_installed`
Check either a package is installed or not
**Usage**: `ynh_package_is_installed --package=name` **Arguments**: - `-p`, `--package=`: the package name to check **Returns**: 0 if the package is installed, 1 else. **Example**: `ynh_package_is_installed --package=yunohost && echo "installed"` **Details**: Requires YunoHost version 2.2.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/apt#L71)
`ynh_install_app_dependencies`
Define and install dependencies with a equivs control file
**Usage**: `ynh_install_app_dependencies dep [dep [...]]` **Arguments**: - `dep`: the package name to install in dependence. - `"dep1|dep2|…"`: You can specify alternatives. It will require to install (dep1 or dep2, etc). **Details**: This helper can/should only be called once per app example : ynh_install_app_dependencies dep1 dep2 "dep3|dep4|dep5" Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/apt#L257)
`ynh_remove_app_dependencies`
Remove fake package and its dependencies
**Usage**: `ynh_remove_app_dependencies` **Details**: Dependencies will removed only if no other package need them. Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/apt#L386)
`ynh_install_extra_app_dependencies`
Install packages from an extra repository properly.
**Usage**: `ynh_install_extra_app_dependencies --repo="repo" --package="dep1 dep2" [--key=key_url] [--name=name]` **Arguments**: - `-r`, `--repo=`: Complete url of the extra repository. - `-p`, `--package=`: The packages to install from this extra repository - `-k`, `--key=`: url to get the public key. - `-n`, `--name=`: Name for the files for this repo, $app as default value. **Details**: Requires YunoHost version 3.8.1 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/apt#L418)
--- ### Systemuser
`ynh_system_user_create`
Create a system user
**Usage**: `ynh_system_user_create --username=user_name [--home_dir=home_dir] [--use_shell] [--groups="group1 group2"]` **Arguments**: - `-u`, `--username=`: Name of the system user that will be create - `-h`, `--home_dir=`: Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home - `-s`, `--use_shell`: Create a user using the default login shell if present. If this argument is omitted, the user will be created with /usr/sbin/nologin shell - `-g`, `--groups`: Add the user to system groups. Typically meant to add the user to the ssh.app / sftp.app group (e.g. for borgserver, my_webapp) **Details**: Create a nextcloud user with no home directory and /usr/sbin/nologin login shell (hence no login capability) : ``` ynh_system_user_create --username=nextcloud ``` Create a discourse user using /var/www/discourse as home directory and the default login shell : ``` ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell ``` Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/systemuser#L79)
`ynh_system_user_delete`
Delete a system user
**Usage**: `ynh_system_user_delete --username=user_name` **Arguments**: - `-u`, `--username=`: Name of the system user that will be create **Details**: Requires YunoHost version 2.6.4 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/systemuser#L121)
`ynh_exec_as`
Execute a command as another user
**Usage**: `ynh_exec_as $USER COMMAND [ARG ...]` **Details**: Requires YunoHost version 4.1.7 or higher. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v1.d/systemuser#L147)
--- ================================================ FILE: docs/dev/50.packaging/20.scripts/20.helpers_v2.1.mdx ================================================ --- title: App helpers (v2.1) toc_max_heading_level: 4 # custom_edit_link: 'https://github.com/YunoHost/yunohost/tree/dev/helpers/helpers.v2.1.d' --- Doc auto-generated by [this script](https://github.com/YunoHost/doc/blob/da78370c098ca04b590e18fb1c8924242367703e/scripts/helpers_doc_generate.py) on 09/01/2026 (YunoHost version 12.1.39) ## Sources

This is coupled to the 'sources' resource in the manifest.toml

### Sources
`ynh_setup_source`
Download, check integrity, uncompress and patch upstream sources
**Usage**: `ynh_setup_source --dest_dir=dest_dir [--source_id=source_id] [--keep="file1 file2"] [--full_replace]` **Arguments**: - `--dest_dir=`: Directory where to setup sources - `--source_id=`: Name of the source, defaults to `main` (when the sources resource exists in manifest.toml) or (legacy) `app` otherwise - `--keep=`: Space-separated list of files/folders that will be backup/restored in $dest_dir, such as a config file you don't want to overwrite. For example 'conf.json secrets.json logs' (no trailing `/` for folders) - `--full_replace=`: Remove previous sources before installing new sources (can be 1 or 0, default to 0) **Details**: This helper will read infos from the 'sources' resources in the `manifest.toml` of the app and expect a structure like: ```toml [resources.sources] [resources.sources.main] url = "https://some.address.to/download/the/app/archive" sha256 = "0123456789abcdef" # The sha256 sum of the asset obtained from the URL ``` (See also the resources documentation which may be more complete?) ##### Optional flags in the 'sources' resource ```text format = "tar.gz"/xz/bz2/tar # automatically guessed from the extension of the URL, but can be set explicitly. Will use `tar` to extract "zip" # automatically guessed from the extension of the URL, but can be set explicitly. Will use `unzip` to extract "docker" # useful to extract files from an already-built docker image (instead of rebuilding them locally). Will use `docker-image-extract` to extract "whatever" # an arbitrary value, not really meaningful except to imply that the file won't be extracted in_subdir = true # default, there's an intermediate subdir in the archive before accessing the actual files false # sources are directly in the archive root n # (special cases) an integer representing a number of subdirs levels to get rid of extract = true # default if file is indeed an archive such as .zip, .tar.gz, .tar.bz2, ... = false # default if file 'format' is not set and the file is not to be extracted because it is not an archive but a script or binary or whatever asset. # in which case the file will only be `mv`ed to the location possibly renamed using the `rename` value rename = "whatever_your_want" # to be used for convenience when `extract` is false and the default name of the file is not practical (the default filename being the value of `source_id` arg and not the upstream basename). platform = "linux/amd64" # (defaults to "linux/$YNH_ARCH") to be used in conjonction with `format = "docker"` to specify which architecture to extract for ``` You may also define assets url and checksum per-architectures such as: ```toml [resources.sources] [resources.sources.main] amd64.url = "https://some.address.to/download/the/app/archive/when/amd64" amd64.sha256 = "0123456789abcdef" armhf.url = "https://some.address.to/download/the/app/archive/when/armhf" armhf.sha256 = "fedcba9876543210" ``` In which case `ynh_setup_source --dest_dir="$install_dir"` will automatically pick the appropriate source depending on the arch The helper will: - Download the specific URL if there is no local archive - Check the integrity with the specific sha256 sum - Uncompress the archive to `$dest_dir`. - If `in_subdir` is true, the first level directory of the archive will be removed. - If `in_subdir` is a numeric value, the N first level directories will be removed. - Patches named `patches/${src_id}/*.patch` will be applied to `$dest_dir` - Apply sane default permissions (see _ynh_apply_default_permissions) [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/sources#L83)
--- ## Databases

This is coupled to the 'database' resource in the manifest.toml - at least for mysql/postgresql. Mongodb/redis may have better integration in the future.

### Mysql
`ynh_mysql_db_shell`
Run SQL instructions in a database ($db_name by default)
**Usage**: `ynh_mysql_db_shell [database] <<< "instructions"` **Arguments**: - `database=`: the database to connect to (by default, $db_name) **Examples**: - `ynh_mysql_db_shell $db_name <<< "UPDATE ...;"` - `ynh_mysql_db_shell < /path/to/file.sql` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/mysql#L30)
`ynh_mysql_dump_db`
Dump a database
**Usage**: `ynh_mysql_dump_db database` **Arguments**: - `database`: the database name to dump (by default, $db_name) **Returns**: The mysqldump output **Example**: `ynh_mysql_dump_db "roundcube" > ./dump.sql` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/mysql#L92)
--- ### Postgresql
`ynh_psql_db_shell`
Run SQL instructions in a database ($db_name by default)
**Usage**: `ynh_psql_db_shell database <<< "instructions"` **Arguments**: - `database`: the database to connect to (by default, $db_name) **Examples**: - `ynh_psql_db_shell $db_name <<< "UPDATE ...;"` - `ynh_psql_db_shell < /path/to/file.sql` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/postgresql#L34)
`ynh_psql_dump_db`
Dump a database
**Usage**: `ynh_psql_dump_db database` **Arguments**: - `database`: the database name to dump (by default, $db_name) **Returns**: the psqldump output **Example**: `ynh_psql_dump_db 'roundcube' > ./dump.sql` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/postgresql#L89)
--- ### Mongodb
`ynh_mongo_exec`
Execute a mongo command
**Usage**: `ynh_mongo_exec [--database=database] --command="command"` **Arguments**: - `--database=`: The database to connect to - `--command=`: The command to evaluate **Example**: `ynh_mongo_exec --command='db.getMongo().getDBNames().indexOf("wekan")' example: ynh_mongo_exec --command="db.getMongo().getDBNames().indexOf(\"wekan\")"` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/mongodb#L31)
`ynh_mongo_dump_db`
Dump a database
**Usage**: `ynh_mongo_dump_db --database=database` **Arguments**: - `--database=`: The database name to dump **Returns**: the mongodump output **Example**: `ynh_mongo_dump_db --database=wekan > ./dump.bson` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/mongodb#L81)
`ynh_mongo_database_exists`
Check if a mongo database exists
**Usage**: `ynh_mongo_database_exists --database=database | exit: Return 1 if the database doesn't exist, 0 otherwise` **Arguments**: - `--database=`: The database for which to check existence [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/mongodb#L124)
`ynh_mongo_restore_db`
Restore a database
**Usage**: `ynh_mongo_restore_db --database=database` **Arguments**: - `--database=`: The database name to restore **Example**: `ynh_mongo_restore_db --database=wekan < ./dump.bson` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/mongodb#L146)
`ynh_mongo_setup_db`
Create a database, a user and its password. Then store the password in the app's config
**Usage**: `ynh_mongo_setup_db --db_user=user --db_name=name [--db_pwd=pwd]` **Arguments**: - `--db_user=`: Owner of the database - `--db_name=`: Name of the database - `--db_pwd=`: Password of the database. If not provided, a password will be generated **Details**: After executing this helper, the password of the created database will be available in $db_pwd It will also be stored as "mongopwd" into the app settings. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/mongodb#L187)
`ynh_mongo_remove_db`
Remove a database if it exists, and the associated user
**Usage**: `ynh_mongo_remove_db --db_user=user --db_name=name` **Arguments**: - `--db_user=`: Owner of the database - `--db_name=`: Name of the database [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/mongodb#L214)
`ynh_install_mongo`
Install MongoDB and integrate MongoDB service in YunoHost
**Usage**: `ynh_install_mongo` **Details**: The installed version is defined by $mongo_version which should be defined as global prior to calling this helper [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/mongodb#L238)
`ynh_remove_mongo`
Remove MongoDB Only remove the MongoDB service integration in YunoHost for now if MongoDB package as been removed
**Usage**: `ynh_remove_mongo` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/mongodb#L279)
--- ### Redis
`ynh_redis_get_free_db`
get the first available redis database
**Usage**: `ynh_redis_get_free_db` **Returns**: the database number to use [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/redis#L25)
`ynh_redis_remove_db`
Erase a redis database so it can be reused by other apps.
**Usage**: `ynh_redis_remove_db database` **Arguments**: - `database`: the database to erase [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/redis#L51)
--- ## Configurations / Templating ### Templating
`ynh_config_add`
Create a dedicated config file from a template
**Usage**: `ynh_config_add --template="template" --destination="destination"` **Arguments**: - `--template=`: Template config file to use - `--destination=`: Destination of the config file - `--jinja`: Use jinja template instead of the simple `__MY_VAR__` templating format **Examples**: - `ynh_config_add --template=".env" --destination="$install_dir/.env" # (use the template file "conf/.env" from the app's package)` - `ynh_config_add --jinja --template="config.j2" --destination="$install_dir/config" # (use the template file "conf/config.j2" from the app's package)` **Details**: The template can be 1) the name of a file in the `conf` directory of the app, 2) a relative path or 3) an absolute path. This applies a simple templating format which covers a good 95% of cases, where patterns like `__FOO__` are replaced by the bash variable `$foo`, for example: `__DOMAIN__` by `$domain` `__PATH__` by `$path` `__APP__` by `$app` `__VAR_1__` by `$var_1` `__VAR_2__` by `$var_2` For this to work, template tags must be in uppercase and variables names must be in lowercase (for instance `__MY_var__` or `$myVar` would not be replaced as expected). Special case for `__PATH__/` which is replaced by `/` instead of `//` if `$path` is `/` ##### When --jinja is enabled This option is meant for advanced use-cases where the "simple" templating mode ain't enough because you need conditional blocks or loops. For a full documentation of jinja's syntax you can refer to [the official Jinja documentation](https://jinja.palletsprojects.com/en/3.1.x/templates/). Note that in YunoHost context, all variables are from shell variables and therefore are strings To help handling complex data Jinja engine are executed with theses additional filters: - from_json: load a string as Json and return an object - from_yaml: load a string as Yaml and return an object - from_toml: load a string as Toml and return an object - to_json: serialize to string an object to Json - to_yaml: serialize to string an object to Yaml - to_toml: serialize to string an object to Toml So by example, if you want to convert a json string `$my_json` to Toml, you can to this way: `{{ my_json | from_json | to_toml }}` Or you can iterate on a Json list `my_list='["a", "b", "c"]'` this way: ``` {% for i in my_list | from_json %} value {{ i }} {% endfor }} ``` which will result: ``` value a value b value c ``` ##### Keeping track of manual changes by the admin The helper will verify the checksum and backup the destination file if it's different before applying the new template. And it will calculate and store the destination file checksum into the app settings when configuration is done. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/templating#L86)
`ynh_read_var_in_file`
Get a value from heterogeneous file (yaml, json, php, python...)
**Usage**: `ynh_read_var_in_file --file=PATH --key=KEY` **Arguments**: - `--file=`: the path to the file - `--key=`: the key to get - `--after=`: the line just before the key (in case of multiple lines with the name of the key in the file) **Details**: This helpers match several var affectation use case in several languages We don't use jq or equivalent to keep comments and blank space in files This helpers work line by line, it is not able to work correctly if you have several identical keys in your files Example of line this helpers can managed correctly ```text .yml title: YunoHost documentation email: 'yunohost@yunohost.org' .json "theme": "colib'ris", "port": 8102 "some_boolean": false, "user": null .ini some_boolean = On action = "Clear" port = 20 .php $user= user => 20 .py USER = 8102 user = 'https://donate.local' CUSTOM['user'] = 'YunoHost' ``` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/templating#L224)
`ynh_write_var_in_file`
Set a value into heterogeneous file (yaml, json, php, python...)
**Usage**: `ynh_write_var_in_file --file=PATH --key=KEY --value=VALUE` **Arguments**: - `--file=`: the path to the file - `--key=`: the key to set - `--value=`: the value to set - `--after=`: the line just before the key (in case of multiple lines with the name of the key in the file) **Details**: This helpers replaces several var affectation use case in several languages We don't use jq or equivalent to keep comments and blank space in files This helpers works line by line, and is not made to replace a type by another. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/templating#L304)
--- ### Nginx
`ynh_config_add_nginx`
Create a dedicated nginx config
**Usage**: `ynh_config_add_nginx` **Details**: This will use a template in `../conf/nginx.conf` See the documentation of `ynh_config_add` for a description of the template format and how placeholders are replaced with actual variables. Additionally, ynh_config_add_nginx will replace: - `#sub_path_only` by empty string if `path` is not `'/'` - `#root_path_only` by empty string if `path` *is* `'/'` This allows to enable/disable specific behaviors dependenging on the install location [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/nginx#L36)
`ynh_config_remove_nginx`
Remove the dedicated nginx config
**Usage**: `ynh_config_remove_nginx` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/nginx#L61)
`ynh_config_change_url_nginx`
Regen the nginx config in a change url context
**Usage**: `ynh_config_change_url_nginx` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/nginx#L69)
--- ### Php
`ynh_config_add_phpfpm`
Create a dedicated PHP-FPM config
**Usage**: `ynh_config_add_phpfpm` **Details**: This will automatically generate an appropriate PHP-FPM configuration for this app. The resulting configuration will be deployed to the appropriate place: `/etc/php/$php_version/fpm/pool.d/$app.conf` If the app provides a `conf/extra_php-fpm.conf` template, it will be appended to the generated configuration. (In the vast majority of cases, this shouldnt be necessary) $php_version should be defined prior to calling this helper, but there should be no reason to manually set it, as it is automatically set by the apt helpers/resources when installing phpX.Y dependencies (PHP apps should at least install phpX.Y-fpm using the `apt` helper/resource) `$php_group` can be defined as a global (from `_common.sh`) if the worker processes should run with a different group than `$app` Additional "pm" and "php_admin_value" settings which are meant to be possibly configurable by admins from a future standard config panel at some point, related to performance and availability of the app, for which tweaking may be required if the app is used by "plenty" of users and other memory/CPU load considerations.... If you have good reasons to be willing to use different defaults than the one set by this helper (while still allowing admin to override it) you should use `ynh_app_setting_set_default` - `$php_upload_max_filezise`: corresponds upload_max_filesize and post_max_size. Defaults to 50M - `$php_process_management`: corresponds to "pm" (ondemand, dynamic, static). Defaults to ondemand - `$php_max_children`: by default, computed from "total RAM" divided by 40, cf `_default_php_max_children` - `$php_memory_limit`: by default, 128M (from global php.ini) Note that if $php_process_management is set to "dynamic", then these variables MUST be defined prior to calling the helper (no default value) ... Check PHP-FPM's manual for more info on what these are (: ... - `$php_start_servers` - `$php_min_spare_servers` - `$php_max_spare_servers` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/php#L68)
`ynh_config_remove_phpfpm`
Remove the dedicated PHP-FPM config
**Usage**: `ynh_config_remove_phpfpm` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/php#L144)
--- ### Systemd
`ynh_config_add_systemd`
Create a dedicated systemd config
**Usage**: `ynh_config_add_systemd [--mount=mount] [--service=service] [--template=template]` **Arguments**: - `--mount=`: Mount name (optionnal) - `--service=`: Service name (optionnal, `$app` by default) - `--template=`: Name of template file (optionnal, this is 'systemd.service' by default, meaning `../conf/systemd.service` will be used as template) **Details**: This will use the template `../conf/`. See the documentation of `ynh_config_add` for a description of the template format and how placeholders are replaced with actual variables. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/systemd#L32)
`ynh_config_remove_systemd`
Remove the dedicated systemd config
**Usage**: `ynh_config_remove_systemd service` **Arguments**: - `service`: Service name (optionnal, $app by default) [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/systemd#L58)
`ynh_systemctl`
Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
**Usage**: `ynh_systemctl [--service=service] [--action=action] [ [--wait_until="line to match"] [--log_path=log_path] [--timeout=300] [--length=20] ]` **Arguments**: - `--service=`: Name of the service to start. Default : `$app` - `--action=`: Action to perform with systemctl. Default: start - `--wait_until=`: The pattern to find in the log to attest the service is effectively fully started. - `--log_path=`: Log file - Path to the log file. Default : `/var/log/$app/$app.log`; `systemd` to listen on `journalctl --unit=$service` - `--timeout=`: Timeout - The maximum time to wait before ending the watching. Default : 60 seconds. - `--length=`: Length of the error log displayed for debugging : Default : 20 [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/systemd#L83)
--- ### Fail2ban
`ynh_config_add_fail2ban`
Create a dedicated fail2ban config (jail and filter conf files)
**Usage**: `ynh_config_add_fail2ban --logpath=log_file --failregex=filter` **Arguments**: - `--logpath=`: Log file to be checked by fail2ban - `--failregex=`: Failregex to be looked for by fail2ban **Details**: If --logpath / --failregex are provided, the helper will generate the appropriate conf using these. Otherwise, it will assume that the app provided templates, namely `../conf/f2b_jail.conf` and `../conf/f2b_filter.conf` They will typically look like (for example here for synapse): ```toml f2b_jail.conf: [__APP__] enabled = true port = http,https filter = __APP__ logpath = /var/log/__APP__/logfile.log maxretry = 5 ``` ```toml f2b_filter.conf: [INCLUDES] before = common.conf [Definition] # Part of regex definition (just used to make more easy to make the global regex) __synapse_start_line = .? \- synapse\..+ \- # Regex definition. failregex = ^%(__synapse_start_line)s INFO \- POST\-(\d+)\- \- \d+ \- Received request\: POST /_matrix/client/r0/login\??%(__synapse_start_line)s INFO \- POST\-\1\- Got login request with identifier: \{u'type': u'm.id.user', u'user'\: u'(.+?)'\}, medium\: None, address: None, user\: u'\5'%(__synapse_start_line)s WARNING \- \- (Attempted to login as @\5\:.+ but they do not exist|Failed password login for user @\5\:.+)$ ignoreregex = ``` ##### Regarding the the `failregex` option regex to match the password failure messages in the logfile. The host must be matched by a group named "`host`". The tag "``" can be used for standard IP/hostname matching and is only an alias for `(?:::f{4,6}:)?(?P[\w\-.^_]+)` You can find some more explainations about how to make a regex on [the official fail2ban documentation](https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters). To validate your regex you can test with this command: ```bash fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf ``` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/fail2ban#L72)
`ynh_config_remove_fail2ban`
Remove the dedicated fail2ban config (jail and filter conf files)
**Usage**: `ynh_config_remove_fail2ban` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/fail2ban#L134)
--- ### Logrotate
`ynh_config_add_logrotate`
Add a logrotate configuration to manage log files / log directory
**Usage**: `ynh_config_add_logrotate [/path/to/log/file/or/folder]` **Details**: If not argument is provided, `/var/log/$app/*.log` is used as default. The configuration is autogenerated by YunoHost (ie it doesnt come from a specific app template like nginx or systemd conf) [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/logrotate#L31)
`ynh_config_remove_logrotate`
Remove the app's logrotate config.
**Usage**: `` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/logrotate#L87)
--- ## Misc Tools ### Utils
`ynh_exec_as_app`
Execute a command after sudoing as $app
**Usage**: `ynh_exec_as_app COMMAND [ARG ...]` **Details**: Note that the $PATH variable is preserved (using env PATH=$PATH) [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L76)
`ynh_local_curl`
Curl abstraction to help with POST requests to local pages (such as installation forms)
**Usage**: `ynh_local_curl "page_uri" "key1=value1" "key2=value2" ...` **Arguments**: - `page_uri`: Path (relative to `$path`) of the page where POST data will be sent - `key1=value1`: (Optionnal) POST key and corresponding value - `key2=value2`: (Optionnal) Another POST key and corresponding value - `...`: (Optionnal) More POST keys and values **Example**: `ynh_local_curl "/install.php?installButton" "foo=$var1" "bar=$var2"` **Details**: For multiple calls, cookies are persisted between each call for the same app `$domain` and `$path` should be defined externally (and correspond to the domain.tld and the /path (of the app?)) [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L97)
`ynh_safe_rm`
Remove a file or a directory, checking beforehand that it's not a disastrous location to rm such as entire /var or /home
**Usage**: `ynh_safe_rm path_to_remove` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L177)
`ynh_read_manifest`
Read the value of a key in the app's manifest
**Usage**: `ynh_read_manifest "key"` **Arguments**: - `key`: Name of the key to find **Returns**: the value associate to that key [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L203)
`ynh_app_upstream_version`
Return the app upstream version, deduced from `$YNH_APP_MANIFEST_VERSION` and strippig the `~ynhX` part
**Usage**: `ynh_app_upstream_version` **Returns**: the version number of the upstream app **Details**: For example, if the manifest contains `4.3-2~ynh3` the function will return `4.3-2` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L213)
`ynh_app_upstream_version_changed`
Return 0 if the "upstream" part of the version changed, or 1 otherwise (ie only the ~ynh suffix changed)
**Usage**: `if ynh_app_upstream_version_changed; then ...` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L220)
`ynh_app_upgrading_from_version_before`
Compare the current package version is strictly lower than another version given as an argument
**Usage**: `` **Example**: `if ynh_app_upgrading_from_version_before 2.3.2~ynh1; then ...` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L228)
`ynh_app_upgrading_from_version_before_or_equal_to`
Compare the current package version is lower or equal to another version given as an argument
**Usage**: `` **Example**: `if ynh_app_upgrading_from_version_before_or_equal_to 2.3.2~ynh1; then ...` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L238)
`ynh_validate_ip`
Validate an IP address
**Usage**: `ynh_validate_ip --family=family --ip_address=ip_address` **Returns**: 0 for valid ip addresses, 1 otherwise **Example**: `ynh_validate_ip 4 111.222.333.444` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L318)
`ynh_in_ci_tests`
Check if the scripts are being run by the package_check in CI
**Usage**: `ynh_in_ci_tests` **Details**: Return 0 if in CI, 1 otherwise [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L382)
`ynh_user_get_info`
Retrieve a YunoHost user information
**Usage**: `ynh_user_get_info --username=username --key=key` **Arguments**: - `--username=`: the username to retrieve info from - `--key=`: the key to retrieve **Returns**: the value associate to that key **Example**: `mail=$(ynh_user_get_info --username="toto" --key=mail)` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L394)
`ynh_user_list`
Get the list of YunoHost users
**Usage**: `ynh_user_list` **Returns**: one username per line as strings **Example**: `for u in $(ynh_user_list); do ... ; done` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L411)
`ynh_spawn_app_shell`
Spawn a Bash shell with the app environment loaded
**Usage**: `ynh_spawn_app_shell` **Examples**: - `ynh_spawn_app_shell <<< 'echo "$USER"'` - `ynh_spawn_app_shell < /tmp/some_script.bash` **Details**: The spawned shell will have environment variables loaded and environment files sourced from the app's service configuration file (defaults to $app.service, overridable by the packager with `service` setting). If the app relies on a specific PHP version, then `php` will be aliased that version. The PHP command will also be appended with the `phpflags` settings. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L426)
`ynh_add_swap`
Add swap
**Usage**: `ynh_add_swap --size=SWAP in Mb` **Arguments**: - `-s`, `--size=`: Amount of SWAP to add in Mb. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L494)
`ynh_smart_mktemp`
Check available space before creating a temp directory.
**Usage**: `ynh_smart_mktemp --min_size="Min size"` **Arguments**: - `-s`, `--min_size=`: Minimal size needed for the temporary directory, in Mb [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/0-utils#L594)
--- ### Setting
`ynh_app_setting_get`
Get an application setting
**Usage**: `ynh_app_setting_get --key=key` **Arguments**: - `--app=`: the application id (global $app by default) - `--key=`: the setting to get [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/setting#L26)
`ynh_app_setting_set`
Set an application setting
**Usage**: `ynh_app_setting_set --key=key --value=value` **Arguments**: - `--app=`: the application id (global $app by default) - `--key=`: the setting name to set - `--value=`: the setting value to set **Details**: When choosing the setting key's name, note that including the following keywords will make the associated setting's value appear masked in the debug logs (cf. [related code](https://github.com/YunoHost/yunohost/blob/216210d5e97070b85c96ebb4548c6abf36987771/src/log.py#L571)): `pwd`, `pass`, `passwd`, `password`, `passphrase`, `secret\w*` (regex), `\w+key` (regex), `token`, `PASSPHRASE` This is meant to allow sharing the logs while preserving confidential data, but having this in mind is useful would you expect to see those values while debugging your scripts. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/setting#L48)
`ynh_app_setting_set_default`
Set an application setting but only if the "$key" variable ain't set yet
**Usage**: `ynh_app_setting_set_default --key=key --value=value` **Arguments**: - `--app=`: the application id (global $app by default) - `--key=`: the setting name to set - `--value=`: the default setting value to set **Details**: Note that it doesn't just define the setting but ALSO define the $foobar variable Hence it's meant as a replacement for this legacy overly complex syntax: ```bash if [ -z "${foo:-}" ] then foo="bar" ynh_app_setting_set --key="foo" --value="$foo" fi ``` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/setting#L80)
`ynh_app_setting_delete`
Delete an application setting
**Usage**: `ynh_app_setting_delete --key=key` **Arguments**: - `--app=`: the application id (global $app by default) - `--key=`: the setting to delete [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/setting#L102)
--- ### String
`ynh_string_random`
Generate a random string
**Usage**: `ynh_string_random [--length=string_length]` **Arguments**: - `--length=`: the string length to generate (default: 24) - `--filter=`: the kind of characters accepted in the output (default: 'A-Za-z0-9') **Returns**: the generated string **Example**: `pwd=$(ynh_string_random --length=8)` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/string#L29)
`ynh_replace`
Substitute/replace a string (or expression) by another in a file
**Usage**: `ynh_replace --match=match --replace=replace --file=file` **Arguments**: - `--match=`: String to be searched and replaced in the file - `--replace=`: String that will replace matches - `--file=`: File in which the string will be replaced. **Details**: As this helper is based on sed command, regular expressions and references to sub-expressions can be used (see sed manual page for more information). In particular for back-references, as in sed without specific options, you will need to escape the parentheses of the capture group. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/string#L53)
`ynh_replace_regex`
Substitute/replace a regex in a file
**Usage**: `ynh_replace_regex --match=match --replace=replace --file=file` **Arguments**: - `--match=`: String to be searched and replaced in the file - `--replace=`: String that will replace matches - `--file=`: File in which the string will be replaced. **Details**: This helper will use ynh_replace, but as you can use special characters, you can't use some regular expressions and sub-expressions. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/string#L81)
`ynh_normalize_url_path`
Normalize the url path syntax
**Usage**: `ynh_normalize_url_path path_to_normalize` **Examples**: - `url_path=$(ynh_normalize_url_path $url_path)` - `ynh_normalize_url_path example # -> /example` - `ynh_normalize_url_path /example # -> /example` - `ynh_normalize_url_path /example/ # -> /example` - `ynh_normalize_url_path / # -> /` **Details**: Handle the slash at the beginning of path and its absence at ending Return a normalized url path [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/string#L136)
--- ### Backup
`ynh_backup`
Add a file or a directory to the list of paths to backup
**Usage**: `ynh_backup /path/to/stuff` **Details**: NB : note that this helper does *NOT* perform any copy in itself, it only declares stuff to be backuped via a CSV which is later picked up by the core NB 2 : there is a specific behavior for $data_dir (or childs of $data_dir) and /var/log/$app which are *NOT* backedup during safety-backup-before-upgrade, OR if the setting "do_not_backup_data" is equals 1 for that app The rationale is that these directories are usually too heavy to be integrated in every backup (think for example about Nextcloud with quite a lot of data, or an app with a lot of media files...) This is coupled to the fact that $data_dir and the log dir won't be (and should NOT) be deleted during remove, unless --purge is used. Hence, if the upgrade fails and the script is removed prior to restoring the backup, the data/logs are not destroyed. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/backup#L42)
`ynh_restore`
Restore a file or a directory from the backup archive
**Usage**: `ynh_restore /path/to/stuff` **Examples**: - `ynh_restore "/etc/nginx/conf.d/$domain.d/$app.conf"` **Details**: If the file or dir to be restored already exists on the system and is lighter than 500 Mo, it is backed up in `/var/cache/yunohost/appconfbackup/`. Otherwise, the existing file or dir is removed. if `apps/$app/etc/nginx/conf.d/$domain.d/$app.conf` exists, restore it into `/etc/nginx/conf.d/$domain.d/$app.conf` otheriwse, search for a match in the csv (eg: conf/nginx.conf) and restore it into `/etc/nginx/conf.d/$domain.d/$app.conf` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/backup#L147)
`ynh_restore_everything`
Restore all files that were previously backuped in an app backup script
**Usage**: `ynh_restore_everything` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/backup#L204)
`ynh_store_file_checksum`
Calculate and store a file checksum into the app settings
**Usage**: `ynh_store_file_checksum /path/to/file` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/backup#L226)
`ynh_backup_if_checksum_is_different`
Verify the checksum and backup the file if it's different
**Usage**: `ynh_backup_if_checksum_is_different /path/to/file` **Details**: This helper is primarily meant to allow to easily backup personalised/manually modified config files. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/backup#L257)
`ynh_delete_file_checksum`
Delete a file checksum from the app settings
**Usage**: `ynh_delete_file_checksum /path/to/file` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/backup#L287)
--- ### Logging
`ynh_die`
Print a message to stderr and terminate the current script
**Usage**: `ynh_die "Some message"` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/logging#L24)
`ynh_print_info`
Print an "INFO" message
**Usage**: `ynh_print_info "Some message"` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/logging#L38)
`ynh_print_warn`
Print a warning on stderr
**Usage**: `ynh_print_warn "Some message"` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/logging#L45)
`ynh_hide_warnings`
Execute a command and redirect stderr to stdout
**Usage**: `ynh_hide_warnings your command and args` **Arguments**: - `command`: command to execute [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/logging#L54)
`ynh_exec_and_print_stderr_only_if_error`
Execute a command and redirect stderr in /dev/null. Print stderr on error.
**Usage**: `ynh_exec_and_print_stderr_only_if_error your command and args` **Arguments**: - `command`: command to execute **Details**: Note that you should NOT quote the command but only prefix it with ynh_exec_and_print_stderr_only_if_error [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/logging#L65)
`ynh_return`
Return data to the YunoHost core for later processing (to be used by special hooks like app config panel and core diagnosis)
**Usage**: `ynh_return somedata` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/logging#L80)
`ynh_script_progression`
Print a progress bar showing the progression of an app script
**Usage**: `ynh_script_progression "Some message"` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/logging#L98)
--- ### Multimedia
`ynh_multimedia_build_main_dir`
Initialize the multimedia directory system
**Usage**: `ynh_multimedia_build_main_dir` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/multimedia#L27)
`ynh_multimedia_addfolder`
Add a directory in `yunohost.multimedia`
**Usage**: `ynh_multimedia_addfolder --source_dir="source_dir" --dest_dir="dest_dir"` **Arguments**: - `--source_dir=`: Source directory - The real directory which contains your medias. - `--dest_dir=`: Destination directory - The name and the place of the symbolic link, relative to `/home/yunohost.multimedia` **Details**: This "directory" will be a symbolic link to a existing directory. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/multimedia#L86)
`ynh_multimedia_addaccess`
Add an user to the multimedia group, in turn having write permission in multimedia directories
**Usage**: `ynh_multimedia_addaccess user_name` **Arguments**: - `user_name`: The name of the user which gain this access. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/multimedia#L112)
--- ## Deprecated Or Handled By The Core / App Resources Since V2 ### Permission
`ynh_permission_delete`
Remove a permission for the app (note that when the app is removed all permission is automatically removed)
**Usage**: `ynh_permission_delete --permission="permission"` **Arguments**: - `--permission=`: the name for the permission (by default a permission named "main" is removed automatically when the app is removed) **Example**: `ynh_permission_delete --permission=editors` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/permission#L158)
`ynh_permission_exists`
Check if a permission exists
**Usage**: `ynh_permission_exists --permission=permission | exit: Return 1 if the permission doesn't exist, 0 otherwise` **Arguments**: - `--permission=`: the permission to check [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/permission#L173)
`ynh_permission_url`
Redefine the url associated to a permission
**Usage**: `ynh_permission_url --permission "permission" [--url="url"] [--add_url="new-url" [ "other-new-url" ]] [--remove_url="old-url" [ "other-old-url" ]] [--auth_header=true|false] [--clear_urls]` **Arguments**: - `--permission=`: the name for the permission (by default a permission named "main" is removed automatically when the app is removed) - `--url=`: (optional) URL for which access will be allowed/forbidden. Note that if you want to remove url you can pass an empty sting as arguments (""). - `--add_url=`: (optional) List of additional url to add for which access will be allowed/forbidden. - `--remove_url=`: (optional) List of additional url to remove for which access will be allowed/forbidden - `--auth_header=`: (optional) Define for the URL of this permission, if SSOwat pass the authentication header to the application - `--clear_urls`: (optional) Clean all urls (url and additional_urls) [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/permission#L194)
`ynh_permission_update`
Update a permission for the app
**Usage**: `ynh_permission_update --permission "permission" [--add="group" ["group" ...]] [--remove="group" ["group" ...]]` **Arguments**: - `--permission=`: the name for the permission (by default a permission named "main" already exist) - `--add=`: the list of group or users to enable add to the permission - `--remove=`: the list of group or users to remove from the permission [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/permission#L257)
`ynh_permission_has_user`
Check if a permission has an user
**Usage**: `ynh_permission_has_user --permission=permission --user=user | exit: Return 1 if the permission doesn't have that user or doesn't exist, 0 otherwise` **Arguments**: - `--permission=`: the permission to check - `--user=`: the user seek in the permission **Example**: `ynh_permission_has_user --permission=main --user=visitors` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/permission#L298)
--- ### Apt
`ynh_apt_install_dependencies`
Define and install dependencies with a equivs control file
**Usage**: `ynh_apt_install_dependencies dep [dep [...]]` **Arguments**: - `dep`: the package name to install in dependence. - `"dep1|dep2|…"`: You can specify alternatives. It will require to install (dep1 or dep2, etc). **Details**: example : ynh_apt_install_dependencies dep1 dep2 "dep3|dep4|dep5" [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/apt#L31)
`ynh_apt_remove_dependencies`
Remove fake package and its dependencies
**Usage**: `ynh_apt_remove_dependencies` **Details**: Dependencies will removed only if no other package need them. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/apt#L177)
`ynh_apt_install_dependencies_from_extra_repository`
Install packages from an extra repository properly.
**Usage**: `ynh_apt_install_dependencies_from_extra_repository --repo="repo" --package="dep1 dep2" --key=key_url` **Arguments**: - `--repo=`: Complete url of the extra repository. - `--package=`: The packages to install from this extra repository - `--key=`: url to get the public key. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/apt#L207)
--- ### Systemuser
`ynh_system_user_exists`
Check if a user exists on the system
**Usage**: `ynh_system_user_exists --username=username` **Arguments**: - `--username=`: the username to check **Returns**: 0 if the user exists, 1 otherwise. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/systemuser#L26)
`ynh_system_group_exists`
Check if a group exists on the system
**Usage**: `ynh_system_group_exists --group=group` **Arguments**: - `--group=`: the group to check **Returns**: 0 if the group exists, 1 otherwise. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/systemuser#L41)
`ynh_system_user_create`
Create a system user
**Usage**: `ynh_system_user_create --username=user_name [--home_dir=home_dir] [--use_shell] [--groups="group1 group2"]` **Arguments**: - `--username=`: Name of the system user that will be create - `--home_dir=`: Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home - `--use_shell`: Create a user using the default login shell if present. If this argument is omitted, the user will be created with /usr/sbin/nologin shell - `--groups`: Add the user to system groups. Typically meant to add the user to the ssh.app / sftp.app group (e.g. for borgserver, my_webapp) **Details**: Create a nextcloud user with no home directory and /usr/sbin/nologin login shell (hence no login capability) : ```bash ynh_system_user_create --username=nextcloud ``` Create a discourse user using /var/www/discourse as home directory and the default login shell : ```bash ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell ``` [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/systemuser#L70)
`ynh_system_user_delete`
Delete a system user
**Usage**: `ynh_system_user_delete --username=user_name` **Arguments**: - `--username=`: Name of the system user that will be create [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/systemuser#L108)
--- ### Nodejs
`ynh_nodejs_install`
Install a specific version of nodejs, using 'n'
**Usage**: `ynh_nodejs_install` **Details**: The installed version is defined by `$nodejs_version` which should be defined as global prior to calling this helper `n` (Node version management) uses the `PATH` variable to store the path of the version of node it is going to use. That's how it changes the version The helper adds the appropriate, specific version of nodejs to the `$PATH` variable (which is preserved when calling ynh_exec_as_app). Also defines: - `$path_with_nodejs` to be used in the systemd config (`Environment="PATH=__PATH_WITH_NODEJS__"`) - `$nodejs_dir`, the directory containing the specific version of nodejs, which may be used in the systemd config too (e.g. `ExecStart=__NODEJS_DIR__/node foo bar`) [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/nodejs#L73)
`ynh_nodejs_remove`
Remove the version of node used by the app.
**Usage**: `ynh_nodejs_remove` **Details**: This helper will check if another app uses the same version of node. - If not, this version of node will be removed. - If no other app uses node, n will be also removed. [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/nodejs#L107)
--- ### Ruby
`ynh_ruby_install`
Install a specific version of Ruby using rbenv
**Usage**: `ynh_ruby_install` **Details**: The installed version is defined by `$ruby_version` which should be defined as global prior to calling this helper The helper adds the appropriate, specific version of ruby to the `$PATH` variable (which is preserved when calling ynh_exec_as_app). Also defines: - `$path_with_ruby` to be used in the systemd config (`Environment="PATH=__PATH_WITH_RUBY__"`) - `$ruby_dir`, the directory containing the specific version of ruby, which may be used in the systemd config too (e.g. `ExecStart=__RUBY_DIR__/ruby foo bar`) [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/ruby#L68)
`ynh_ruby_remove`
Remove the version of Ruby used by the app.
**Usage**: `ynh_ruby_remove` **Details**: This helper will also cleanup unused Ruby versions [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/ruby#L110)
--- ### Go
`ynh_go_install`
Install a specific version of Go using goenv
**Usage**: `ynh_go_install` **Details**: The installed version is defined by `$go_version` which should be defined as global prior to calling this helper The helper adds the appropriate, specific version of go to the `$PATH` variable (which is preserved when calling `ynh_exec_as_app`). Also defines: - `$path_with_go` (the value of the modified `$PATH`, but you dont really need it?) - `$go_dir` (the directory containing the specific go version) [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/go#L68)
`ynh_go_remove`
Remove the version of Go used by the app.
**Usage**: `ynh_go_remove` **Details**: This helper will also cleanup Go versions [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/go#L99)
--- ### Composer
`ynh_composer_install`
Install and initialize Composer in the given directory
**Usage**: `ynh_composer_install` **Details**: The installed version is defined by `$composer_version` which should be defined as global prior to calling this helper. Will use `$install_dir` as workdir unless `$composer_workdir` exists (but that shouldnt be necessary) [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/composer#L29)
`ynh_composer_exec`
Execute a command with Composer
**Usage**: `ynh_composer_exec commands` **Details**: Will use `$install_dir` as workdir unless `$composer_workdir` exists (but that shouldnt be necessary) You may also define `composer_user=root` prior to call this helper if you absolutely need composer to run as root, but this is discouraged... [Dude, show me the code!](https://github.com/YunoHost/yunohost/blob/3572fc9dff10b9f4f4ab30efe88a9b145867c241/helpers/helpers.v2.1.d/composer#L55)
--- ================================================ FILE: docs/dev/50.packaging/20.scripts/_category_.yaml ================================================ collapsed: false ================================================ FILE: docs/dev/50.packaging/20.scripts/index.mdx ================================================ --- title: App scripts --- App scripts are the essential logic defining what happens when an app is `install`ed, `remove`d, `upgrade`d, `backup`ed, or `restore`d. They are written in [Bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)) which is the same stuff you type in interactive mode in a terminal, though we added a bunch of custom YunoHost functions that we call `helpers` to standardize many common operations - for example adding the nginx configuration. Note that starting from packaging v2, the logic or what happens when an app is installed, etc. is also contained partially in the resource configuration in the `manifest.toml`. In the `scripts` folder of an app, you can expect to find: ```text manifest.toml scripts ├── _common.sh # Some "common" definition, typically custom helpers │ # or global variables used across all scripts ├── install # The install procedure ├── remove # The remove procedure ├── backup # The backup procedure - in fact it only "declares" what should be backed up. │ # No actual real backup happens at this point except dumping SQL databases ├── restore # The restore procedure ├── change_url # Some apps do also provide a change url script, which corresponds to changing │ # the URL endpoint of the app, which may be as simple as changing │ # the nginx conf, or may involve significant changes in the app DB └── upgrade # The upgrade procedure ``` Here is an example of the simple install script for the `helloworld` app: ```bash #!/bin/bash # This is where we load the official YunoHost helpers source /usr/share/yunohost/helpers #================================================= # DOWNLOAD, CHECK AND UNPACK SOURCE # This is where we would usually fetch the .tar.gz archive # from the upstream and extract it into our local install dir #================================================= # At the beginning of each major operation, we call this helper # that creates a progress bar ynh_script_progression --message="Setting up source files..." --weight=1 echo "Hello world!" > $install_dir/index.html chown -R www-data: "$install_dir" #================================================= # NGINX CONFIGURATION # This is where the nginx conf snippet for the app is created using the # configuration template provided in conf/nginx.conf # and added to /etc/nginx/conf.d/$domain.d/$app.conf #================================================= ynh_script_progression --message="Configuring nginx web server..." --weight=1 ynh_add_nginx_config ``` Note that the scripts are run with the `set -eu` options (except for the remove script), which means that any failing command or use of non-existing variable will trigger an error and stop the script execution. ## Variables available in a script context Special variables are automatically defined in the context of a script: - `$app` is the app ID. It will typically be the ID from the app's manifest.toml, for example `helloworld`, but will be `helloworld__2`, `__3` etc for multi-instance installs. - During install, answers to install questions are automatically available as bash variables. Typically, `$domain` and `$path` will contain the answers to the default install questions assuming they are defined in the `manifest.toml`. Answer values associated to any custom install questions will be available the same way, e.g. `$prefered_pet` for the custom question `[install.prefered_pet]` that would be defined in the manifest. Note that - apart from special questions such as `init_main_permission` or user-provided passwords - they are also automatically saved as settings (cf. next section). - During other scripts, all app settings are also loaded and automatically available. - Note that some settings are automatically created/updated by app ressources. For example, the `install_dir` setting will automatically be available too and corresponds to typically `/var/www/$app` - In the `change_url` context, variables called `new_domain`, `new_path`, `old_domain`, `old_path` will be available, as well as `change_domain` and `change_path` equal to `0` (false) or `1` (true) depending if the domain / path changed ## Setting system Application often need to store long term information in between scripts triggered by the admin. For this, YunoHost has a key-value store for each application called "setting" and is stored in `/etc/yunohost/apps/$app/settings.yml`. Apps can interact with this key value store in this way: ```bash # Retrieve a setting into variable "db_name" db_name=$(ynh_app_setting_get --app=$app --key=db_name) # Update a setting ynh_app_setting_set --app=$app --key=db_name --value=$db_name ``` ## Helper system We call helpers a set of custom bash functions created by the YunoHost project to standardize common operations across all apps. They are all prefixed with `ynh_`. The full list and documentation of these helpers is available on [this page](/dev/packaging/scripts/helpers_v2.1). Some of these helpers are now partially obsolete as they are now handled by the core via app resources. Here is the list of the major ones: - `ynh_app_setting_get` / `ynh_app_setting_set` - `ynh_script_progression` - `ynh_setup_source` - nginx: `ynh_add_nginx_config` / `ynh_remove_nginx_config` - php: `ynh_add_fpm_config` / `ynh_remove_fpm_config` - systemd: `ynh_add_systemd_config` / `ynh_remove_systemd_config` - fail2ban: `ynh_add_fail2ban_config` / `ynh_remove_fail2ban_config` - custom: `ynh_add_config` - nodejs: `ynh_install_nodejs` / `ynh_use_nodejs` - `ynh_exec_warn_less` - `ynh_local_curl` - `ynh_secure_remove` - `ynh_backup` / `ynh_restore_file` ## Configuration/template system App scripts will often need to create a bunch of configuration files. Configuration templates are canonically stored provided in the `conf/` folder of the app, such as `nginx.conf`, `extra_php-fpm.conf`, `systemd.conf`, or `some-custom-app-conf.env` ... In these templates, you can use the syntax `__FOOBAR__` which will automatically be replaced by the variable `$foobar` during runtime, when the conf is installed via the `ynh_add_*_config` helpers. For example, an app's NGINX conf snippet may look like: ```text # The next line starting with '#sub_path_only' is automatically uncommented only when $path is not / #sub_path_only rewrite ^__PATH__$ __PATH__/ permanent; location __PATH__/ { alias __INSTALL_DIR__/; # Some headers and tweaks } ``` ## App sources App sources were historically defined in `conf/app.src` files containing the URL + checksum of assets to download. This is now integrated in `manifest.toml` using the `sources` resource, which pre-download the assets prior to entering the install or upgrade scripts. The sources can then be effectively deployed using `ynh_setup_source`. For example, for YesWiki, the sources are defined in `manifest.toml` using: ```toml [resources.sources.main] url = "https://github.com/YesWiki/yeswiki/archive/refs/tags/v4.4.0.tar.gz" sha256 = "5ceb12d225c20de2ba3cb4ce483348ed1a8ad5b1789d4f4f8f89dc4871524007" ``` More infos on the `source` resource in [the resource system documentation](/dev/packaging/resources). ## Common operations :::caution TODO / FIXME : this part should be completed... ::: - installing/upgrading app sources - adding configurations - adding a systemd service - curl / automatizing install forms - classic stuff for nodejs apps - classic stuff for php apps - classic stuff for python apps - classic stuff for ??? apps ================================================ FILE: docs/dev/50.packaging/30.doc.mdx ================================================ --- title: Documenting apps --- Properly documenting your app is important for user experience ;). YunoHost provides several mechanism to display information to users. ## Extensive description : `doc/DESCRIPTION.md` and `doc/screenshots/` You are encouraged to add a `doc/DESCRIPTION.md` which should contain a more extensive description than the short description contained in `manifest.toml`. This usually corresponds to listing the key features of the app. You are also encouraged to add a `.png` or `.jpg` screenshot of what the app looks like in `doc/screenshots/`. The filename is arbitrary but must not start with a dot. Also the file weight should be kept below 512kb. This description and screenshot will be shown when the admin open the catalog page for this app and the app info page in the webadmin after the admin installs this app. You can add subfolders such as `doc/screenshots/subfolder` to add pictures in your documentation without showing them on the app info page. You can also add translated versions of the `.md` file in, for example, `doc/DESCRIPTION_fr.md`, `_es.md`, `_it.md`, etc. If your app repository is part of the YunoHost-Apps org, the provided description will be used to auto-regenerate the README.md of your GitHub repo via `yunohost-bot`. ## Specific notes for admins : `doc/ADMIN.md`, `doc/.md` Sometimes, you may want to ship YunoHost-specific notes regarding the administration of this app. For example, integrating OnlyOffice inside Nextcloud. You can do so by adding a `doc/ADMIN.md` file or even a `doc/.md` page for each specific topic - and similarly add `_` suffix for translations. Note that you can even use the `__FOOBAR__` syntax which will automatically be replaced with the `foobar` setting. These notes will be available in the app info page in the webadmin after the app installation. ## Pre/post-install notes, pre/post-upgrade notes Sometimes, you may want to display important information to the admin at key points in the app's life cycle. You can do so by providing special markdown files: - `doc/PRE_INSTALL.md`: displayed right before the installation (for example to warn that « This app install is expected to take around 30 minutes, be patient! » or « This app will automatically add 1GB swap to your system »). - NB: try to not overlap with the anti-feature tags from the catalog (cf. Publishing your app in the catalog) which can be used to warn that the app's upstream is alpha-stage or deprecated among other things. - `doc/POST_INSTALL.md`: displayed in a popup after the installation AND a dismissable note in the webadmin app info view. - `doc/PRE_UPGRADE.md`: displayed right before any upgrade of this app. - NB: the pre-upgrade note from the NEW version will be used, not the one from the installed version. - `doc/POST_UPGRADE.md`: displayed in a popup after the upgrade AND a dismissable note in the webadmin app info view. In these files you can use the `__FOOBAR__` syntax which will automatically be replaced with the `foobar` setting. These notes are displayed both in WebUI and CLI contexts. In the CLI context, admin is prompted to press a key to dismiss the note and continue the install/upgrade process. ### Display notes only for a specific version To display such note only for a specific version, you can create a markdown file named after the version inside a folder named after the targeted hook as such: `doc/{hook}.d/{version}.md`, where: - `{hook}` corresponds to `PRE_UPGRADE` or `POST_UPGRADE` - `{version}` corresponds to the version defined in the manifest. Example: `doc/PRE_UPGRADE.d/1.2.1~ynh1.md`. With the above example, the user will be notified with the content of this markdown file when they upgrade from a lower version of `1.2.1~ynh1` to this latter version or higher. :::tip You can easily increase the package version directly from a comment in a Pull Request on Github by posting `!bump`. The YunoHost bot will automatically add 1 to the package version (`~ynh1` to `~ynh2`, for instance). ::: :::tip You can add a PRE_UPGRADE message directly from a comment in a Pull Request on Github by posting `!changelog `, `!pre_upgrade `, or `!preupgrade `. The YunoHost bot will automatically create the appropriate file with the `` you wrote. ::: ### Localization All notes' markdown file can optionally be localized using via a filename suffix with the following format: `doc/{hook}_{locale}.md` or `doc/{hook}.d/{version}_{locale}.md`. Without locale suffix, a file will be considered to be the English locale (i.e. `doc/PRE_UPGRADE.md` is equivalent to `doc/PRE_UPGRADE_en.md`). Examples: - `doc/POST_INSTALL_fr.md` will be displayed after each install of the given app where the Yunohost instance's language is set to French. - `doc/POST_UPGRADE.d/2025.04.02~ynh1_es.md` will be displayed after upgrading to version `2025.04.02~ynh1` or newer of the given app where the Yunohost instance's language is set to Spanish. ================================================ FILE: docs/dev/50.packaging/40.test.mdx ================================================ --- title: Testing your app --- Once you're done writing you app package, you'll want to check that everything works correctly. At first, you can manually try to install your app on some test server of your own : `sudo yunohost app install ./path/to/mycustomapp_ynh` Note that `./path/to/mycustomapp_ynh` can be a local path or an external git repository https URL (basically anything compatible with `git clone`). You may also be interested in specifying the following parameters for `yunohost app install` command: - `--debug` : prints detailed log information - `--no-remove-on-failure` : won't remove the app if the install fails - therefore you can analyze and manually run/debug stuff, typically in `/var/www/$app` - `--force` : so that you are not asked confirmation if the app is not safe to use (low quality, experimental or 3rd party), or when the app displays a post-install notification. - `-a "&domain=sub.domain.tld&path=/my_app&init_main_permission=all_users"` : can be used to preconfigure the answers to the install questions that are asked otherwise after entering the command. i.e. - `domain=sub.domain.tld` : the domain/subdomain on which to install the app - `path=/my_app` : the path to which the app will be accessible, e.g. https://(sub.)domain.tld/my_app - `init_main_permission=all_users` : permission group associated to the app (can be `all_users`, `visitors`, etc.) Testing everything manually often becomes tedious ;). The YunoHost project maintains several tools to automatically and somewhat "objectively" analyze and tests our 400+ apps catalog. ## Package linter The [package linter](https://github.com/YunoHost/package_linter) performs a static analysis of your app to check a bunch of recommended practice. It is pretty straightforward to run considering that you should only need Python installed. ## Package check [Package check](https://github.com/YunoHost/package_check) is a more elaborate software that will tests many scenarios for you app such as: - installing, removing and reinstalling your app + validating that the app can indeed be accessed on its URL endpoint (with no 404/502 error) - when installing on a root domain (`domain.tld/`) - when installing in a domain subpatch (`domain.tld/foobar`) - installing in private mode - installing multiple instances - upgrading from the same version - upgrading from older versions - backup/restore - ... Package check will then summarize the results and compute a quality level ranging from 0 to 8. To run its tests, package check uses a LXC container to manipulate the package in a clean environment without any previous installations. Installing LXC/LXD is unfortunately not that straighforward (it kinda depends on your OS/distribution), though we documented how to do so [in the README](https://github.com/YunoHost/package_check#deploying-package_check). ### Package check's `tests.toml` Package check interfaces with your app's `tests.toml` which allows you to control a few things about which tests are run - though it is usually pretty empty as many things can be deduced from the app's manifest. More info about the syntax here are also available [in the README](https://github.com/YunoHost/package_check#teststoml-syntax) ### Application quality levels Package check will compute a quality level ranging from 0 to 8. Apps with level equal or lower than 4 are considered "bad quality" and YunoHost will discourage people from installing such apps. While this definition may vary with time, the current definition as of February 2023 is roughly: - level 0 (« Broken ») : the application doesn't work at all or doesn't pass level 1 criterias - level 1 (« Installable in at least one scenario ») : At least one install succeeded, and there's no critical issue reported in the linter - level 2 (« Installable in all scenarios ») : All install scenarios tested (typically install on full domain, domain+subpath, multi-instance, private/public) succeeded - level 3 (« Can be upgraded ») : All upgrades tests from the current commit succeeded - level 4 (« Can be backuped/restored ») : All backup/restore tests succeeded - level 5 (« No linter error ») : No red errors reported by the linter - level 6 (« App is in a community-operated git org ») : The app is hosted on YunoHost-Apps organization. (From a maintenance / security point of view, we want to avoid the catalog being filled with apps that are privately-hosted and that the initial maintainer will ultimately abandon and that can't be maintained easily by the community) - level 7 (« All tests succeeded + No linter warning ») : Pass all test (including for example upgrade from past commits) and no warning reported by the linter - level 8 (« Maintained and long-term good quality ») : The app is not flagged as not-maintained / alpha / deprecated / obsolete in the catalog, and has been at least level 5 during the past ~year ## Continous integration (CI) The YunoHost project also developed an interface called [`yunorunner`](https://github.com/YunoHost/yunorunner) which interfaces with `package_check`, handles a job queue, and automatically add jobs to the queue using some triggers. The two major ones are: - [The "official" CI](https://ci-apps.yunohost.org/ci): This where the "official" quality level of each app comes from. Jobs are triggered after each commit on the repo's master branch. - [The "dev" CI](https://ci-apps-dev.yunohost.org/ci/): This is where people validate their pull request which is often more convenient than running `package_check` yourself, and has the advantage of the results being automatically public, which facilitates collective debugging. Members of the YunoHost-Apps organization can trigger jobs on the dev CI directly from a pull request simply by commenting something like `!testme` (cf for example [here](https://github.com/YunoHost-Apps/nextcloud_ynh/pull/532#issuecomment-1402751409)). A .png summary of the tests will be automatically displayed once the job completes (and you can click the link to see the entire job execution and debug it). ### Why create `package_check` + `yunorunner` rather than using well-known solutions like Gitlab-CI ? Constrain 1 : Gitlab-CI or other similar solutions are mostly based around Docker, while we use LXC. In particular, we do want to reuse LXC snapshots of successful install during other tests (upgrade, backup/restore, ..) rather than reinstalling the app from scratch everytime, which drastically reduces the test time. We could do so using Gitlab artifacts, but such artifacts are automatically made public which is not convenient because they contain a full filesystem and their only use it to speed up the test process. Moreover, in the Gitlab-CI paradigm, jobs are not running on the same machine and they would need to download the snapshot which can be lengthy. The other mechanism, caching, is explicitly advertised as not reliable in Gitlab's-CI doc. What would be helpful would be some non-public artifact system (see similar discussion [here](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/336)) Constrain 2 : Our test workflow is somewhat complex and we have 400+ apps to maintain. It's not acceptable to have to duplicate/maintain the CI logic in app each repository, so we need some sort of repo that handles the CI logic, while still being to supersed some behavior from the app repo itself. Gitlab-CI has some syntax which can allow this, but this remains quite laborious. Constrain 3 : Having a common job queue/dashboard UI across all apps. In the Gitlab-CI paradigm, each repository has its own job queue/dashboard UI, but this is not really convenient. ================================================ FILE: docs/dev/50.packaging/50.publish.mdx ================================================ --- title: Publishing your app on the catalog --- The official YunoHost's app catalog is maintained [in this repository](https://github.com/YunoHost/apps/), in particular [the `apps.toml` file](https://github.com/YunoHost/apps/blob/master/apps.toml). For your app to be made available to everybody, you should make a pull request that adds your app inside the `apps.toml` (see the [detailed instructions in the README](https://github.com/YunoHost/apps/#how-to-add-your-app-to-the-application-catalog)). Before doing so, please make sure to check that your app is compatible with [the official app catalog policy](/dev/packaging/policy). Note that the "real" catalog used by YunoHost servers is [https://app.yunohost.org/default/v3/apps.json](https://app.yunohost.org/default/v3/apps.json) which is rebuilt every 4 hours. NB: The `level` key is not to be set manually by maintainers. The `yunohost-bot` will [automatically create a pull request](https://github.com/YunoHost/apps/blob/master/tools/update_app_levels/update_app_levels.py) every Friday evening with results from the official CI, which are then to be manually reviewed and merged by the community. ================================================ FILE: docs/dev/50.packaging/60.advanced/20.config_panels.mdx ================================================ --- title: Config Panels description: ' ' --- From a practical point of view, one of the main purpose of config panel is to "expose" settings from the app's configuration files to YunoHost's admins which are therefore able to manipulate them from a nice web ui. This is especially relevant for apps which do not provide any sort of admin UI and expect admins to manually edit the configuration files. Technically speaking, config panels are used both for apps packaging and also core features (domain configuration, global settings) :::warning Please: Keep in mind the YunoHost spirit, and try to build your panels in such a way as to expose only really useful, "high-level" parameters, and if there are many of them, to relegate those corresponding to rarer use cases to "Advanced" sub-sections. Keep it simple, focus on common needs, don't expect the admins to have 3 PhDs in computer science. ::: ## Community examples - [Check the example_ynh app toml](https://github.com/YunoHost/example_ynh/blob/master/config_panel.toml.example) and the [basic `scripts/config` example](https://github.com/YunoHost/example_ynh/blob/master/scripts/config) - [Check config panels of other apps](https://grep.app/search?q=version&filter[repo.pattern][0]=YunoHost-Apps&filter[lang][0]=TOML) - [Check `scripts/config` of other apps](https://grep.app/search?q=ynh_app_config_apply&filter[repo.pattern][0]=YunoHost-Apps&filter[lang][0]=Shell) ## Overview From an app packager perspective, config panels are defined in `config_panel.toml` at the root of the app repository. It is coupled to the `scripts/config` script, which may be used to define custom getters/setters/validations/actions. However, most use cases should be covered automagically by the core, thus it may not be necessary to define such a `config` script at all! The `config_panel.toml` describes one or several panels, containing sections, each containing questions generally binded to a params in the app's actual configuration files. Let's imagine that the upstream app is configured using this simple `config.yml` file stored in the app's install directory (typically `/var/www/$app/config.yml`): ```yaml title: 'My dummy app' theme: 'white' max_rate: 10 max_age: 365 ``` A simple configuration panel can be created with this syntax: ```toml version = "1.0" [main] [main.main] [main.main.title] ask.en = "Title" type = "string" bind = ":__INSTALL_DIR__/config.yml" [main.main.theme] ask.en = "Theme" type = "select" choices = ["white", "dark"] bind = ":__INSTALL_DIR__/config.yml" [main.limits] [main.limits.max_rate] ask.en = "Maximum display rate" type = "number" bind = ":__INSTALL_DIR__/config.yml" [main.limits.max_age] ask.en = "Duration of a dummy" type = "number" bind = ":__INSTALL_DIR__/config.yml" ``` Here, a `main` panel is created, containing the `main` and `limits` sections, containing questions corresponding to app options in `config.yml` file. Thanks to the `bind` property, all those questions are read/written to their values in the actual `config.yml` file. ## Supported questions types and properties You can learn more about the full list of option types and their properties in [their dedicated page](/dev/core/forms). ## The "`bind`" statement Without any `bind` statement attached to a config panel property, values are only read/written from/to the app's settings file (`/etc/yunohost/$app/settings.yml`). This is usually not very useful in practice. Using `bind = ":/some/config/file"`, one declares that the actual truth used by the app lives in `/some/config/file`. The config panel will read/write the value from/to this file. YunoHost will automagically adapt to classic formats such as YAML, TOML, JSON, INI, PHP, `.env`-like and `.py`. (At least, assuming we're dealing with simple key\<-\>value mappings) A simple real-life example looks like: ```toml [main.main.theme] type = "string" bind = ":__INSTALL_DIR__/config.yml" ``` In which case, YunoHost will look for something like a key/value, with the key being `theme` inside the app's `config.yml`. If the question id in the config panel (here, `theme`) differs from the key in the actual conf file (let's say it's not `theme` but `css_theme`), then the syntax becomes: ```toml [main.main.theme] type = "string" bind = "css_theme:__FINALPATH__/config.yml" ``` You may also encounter situations such as: ```json { "foo": { "max": 123 }, "bar": { "max": 456 } } ``` In which case if we want to interface with foo's `max` value, let's write: ```toml bind = "foo>max:__INSTALL_DIR__/conf.json" ``` ### "Binding" to an entire file Useful when using a question `file` or `text` for which you want to save the raw content directly as a file on the system. For example to be able to manipulate an image: ```toml [panel.section.logo] type = "file" bind = "__INSTALL_DIR__/assets/logo.png" ``` Or an entire text file: ```toml [panel.section.config_content] type = "text" bind = "__INSTALL_DIR__/config.ini" default = "This is the default content" ``` ### Custom getters/setters/validators (a.k.a `bind=null`) More complex use-case may appear, such as: - you want to expose some "dynamic" information in the config panel, such as computed health status, computed disk usage, dynamic list of options, ... - password handling, where the data may be written but can't be read - the config file format is not supported (e.g. xml, csv, ...) - ... You can create specific getter/setters functions inside the `config` script of the app to customize how the information is read/written. The basic structure of the script is: ```bash #!/bin/bash source /usr/share/yunohost/helpers ynh_abort_if_errors # Put your getter, setter, validator or action here # Keep this last line ynh_app_config_run $1 ``` #### Custom getters A question's getter is the function used to read the current value/state. Custom getters are defined using bash functions called `getter__QUESTION_SHORT_KEY()` which returns data through stdout. Stdout can be generated into one of those formats: 1. either just the raw value, 2. or a YAML message, containing the value and other metadata and properties (for example the `style` of an `alert`, the list of available `choices` of a `select`, etc.) Note that in the first case, if the raw value contains any yaml-sensitive character (e.g. `#` which is interpreted as a comment in yaml), make sure it is returned between escaped quotes (cf. dedicated example below) as it will be [converted to yaml](https://github.com/YunoHost/issues/issues/2501) by YunoHost core in the end.
Basic example with raw stdout: get the timezone on the system `config_panel.toml` ```toml [main.main.timezone] ask = "Timezone" type = "string" ``` `scripts/config` ```bash get__timezone() { echo "$(cat /etc/timezone)" } ```
Basic example with raw stdout containing a yaml-sensitive character: return a HTML color code matched in a file `config_panel.toml` ```toml [main.default_colors.background] ask = "Default background color" type = "color" default = "#cccccc" ``` `scripts/config` ```bash get__background() { current_color=$(grep 'id="backgroundColorPicker' "$install_dir/index.html" | grep -oP 'value="\K[^"]*') # e.g. #2B748B # explicitely add escaped quotes to protect YAML-sensitive comment char ('#') echo "\"$current_color\"" } ```
Basic example with yaml-formated stdout : Display a list of available plugins `config_panel.toml` ```toml [main.plugins.plugins] ask = "Plugin to activate" type = "tags" choices = [] ``` `scripts/config` ```bash get__plugins() { echo "choices: [$(ls $install_dir/plugins/ | tr '\n' ',')]" } ```
Advanced example with yaml-formated stdout : Display the status of a VPN `config_panel.toml` ```toml [main.cube.status] ask = "Custom getter alert" type = "alert" style = "info" bind = "null" # no behaviour on ``` `scripts/config` ```bash get__status() { if [ -f "/sys/class/net/tun0/operstate" ] && [ "$(cat /sys/class/net/tun0/operstate)" == "up" ] then cat << EOF style: success ask: en: Your VPN is running :) EOF else cat << EOF style: danger ask: en: Your VPN is down EOF fi } ```
#### Custom setters A question's setter is the function used to set new value/state. Custom setters are defined using bash functions called `setter__QUESTION_SHORT_KEY()`. In the context of the setter function, variables named with the various quetion's short keys are avaible ... for example the user-specified date for question `[main.main.theme]` is available as `$theme`. When doing non-trivial operations to set a value, you may want to use `ynh_print_info` to inform the admin about what's going on.
Basic example : Set the system timezone `config_panel.toml` ```toml [main.main.timezone] ask = "Timezone" type = "string" ``` `scripts/config` ```bash set__timezone() { echo "$timezone" > /etc/timezone ynh_print_info "The timezone has been changed to $timezone" } ```
## User input validations You will sometimes need to validate data provided by the user before saving it. Simple validation can be achieved using a regex pattern: ```toml pattern.regexp = '^.+@.+$' pattern.error = 'An email is required for this field' ``` You can also restrict the accepted values using a choices list. ```toml choices.foo = "Foo (some explanation)" choices.bar = "Bar (moar explanation)" choices.loremipsum = "Lorem Ipsum Dolor Sit Amet" ``` Some other type specific argument exist like | type | validation arguments | | ----- | --------------------------- | | `number`, `range` | `min`, `max`, `step` | | `file` | `accept` | | `boolean` | `yes` `no` | See also : custom validators ### Custom validators In addition to the "simple" validation mechanism (see the 'option' doc), custom validators can be defined in a similar fashion as custom getters/setters: ```bash validate__login_user() { if [[ "${#login_user}" -lt 4 ]] then echo 'User login is too short, should be at least 4 chars' fi } ``` ## `visible` & `enabled` expression evaluation Sometimes we may want to conditionaly display a message or prompt for a value, for this we have the `visible` prop. And we may want to allow a user to trigger an action only if some condition are met, for this we have the `enabled` prop. Expressions are evaluated against a context containing previous values of the current section's options. This quite limited current design exists because on the web-admin or on the CLI we cannot guarantee that a value will be present in the form if the user queried only a single panel/section/option. In the case of an action, the user will be shown or asked for each of the options of the section in which the button is present. The expression has to be written in javascript (this has been designed for the web-admin first and is converted to python on the fly on the cli). Available operators are: `==`, `!=`, `>`, `>=`, `<`, `<=`, `!`, `&&`, `||`, `+`, `-`, `*`, `/`, `%` and `match()`. ### Examples ```toml # simple "my_option_id" is thruthy/falsy visible = "my_option_id" visible = "!my_option_id" # misc visible = "my_value >= 10" visible = "-(my_value + 1) < 0" visible = "!!my_value || my_other_value" ``` For a more complete set of examples, [check the tests at the end of the file](https://github.com/YunoHost/yunohost/blob/dev/src/tests/test_questions.py). ### match() For more complex evaluation we can use regex matching. ```toml [my_string] default = "Lorem ipsum dolor et si qua met!" [my_boolean] type = "boolean" visible = "my_string && match(my_string, '^Lorem [ia]psumE?')" ``` Match the content of a file. ```toml [my_file] type = "file" accept = ".txt" bind = "/etc/random/lorem.txt" [my_boolean] type = "boolean" visible = "my_file && match(my_file, '^Lorem [ia]psumE?')" ``` with a file with content like: ```text Lorem ipsum dolor et si qua met! ``` ## Actions "Actions" correspond to config panel buttons triggering specific pieces of code. For example, one could implement an action to trigger a scan of Nextcloud files, or install a plugin inside an app that does not already provide an interface to do so. In core config panels, buttons are for example used to trigger certificate renewal. The most basic example looks like this, using `type = 'button'`: ```toml [panel.section.my_action] type = "button" ask = "Run action" # (NB: no need to set `bind` to "null") ``` And then defining the controller, prefixed by `run__` inside the app's `config` script: ```bash run__my_action() { ynh_print_info "Running 'my_action'..." } ``` You may build more complex actions, where the actions uses other form inputs: ```toml [panel.my_action_section] name = "Action section" [panel.my_action_section.my_repo] type = "url" bind = "null" # this value won't be saved as a setting, it's ephemeral and only relevant for the action ask = "gimme a repo link" [panel.my_action_section.my_repo_name] type = "string" bind = "null" # this value won't be saved as a setting, it's ephemeral and only relevant for the action ask = "gimme a custom folder name" [panel.my_action_section.my_action] type = "button" ask = "Clone the repo" # the button is clickable only once the previous values are provided enabled = "my_repo && my_repo_name" ``` ```bash run__my_action() { ynh_print_info "Cloning '$my_repo'..." cd /tmp git clone "$my_repo" "$my_repo_name" } ``` ## Overwrite config panel mechanism All main configuration helpers are overwritable, example: ```bash ynh_app_config_apply() { # Stop vpn client touch /tmp/.ynh-vpnclient-stopped systemctl stop ynh-vpnclient _ynh_app_config_apply # Start vpn client systemctl start ynh-vpnclient rm -f /tmp/.ynh-vpnclient-stopped } ``` List of main configuration helpers: - `ynh_app_config_get` - `ynh_app_config_show` - `ynh_app_config_validate` - `ynh_app_config_apply` - `ynh_app_config_run` More info on this can be found by reading [vpnclient_ynh config script](https://github.com/YunoHost-Apps/vpnclient_ynh/blob/master/scripts/config) ## Important technical notes ### Options short keys have to be unique For performance reasons, questions short keys have to be unique in all the `config_panel.toml` file, not just inside its panel or its section. Hence it's not possible to have: ```toml [manual.vpn.server_ip] [advanced.dns.server_ip] ``` In which two questions have "real variable name" `is server_ip` and therefore conflict with each other. :::warning Some short keys are forbidden cause it can interfer with config scripts (`old`, `file_hash`, `types`, `binds`, `formats`, `changed`) and you probably should avoid to use common settings name to avoid to bind your question to this settings (e.g. `id`, `install_time`, `mysql_pwd`, `path`, `domain`, `port`, `db_name`, `current_revision`, `admin`) ::: ### `bind` versus app settings :::warning IMPORTANT: with the exception of `bind = "null"` options, options ids should almost **always** correspond to an app setting initialized/reused during install/upgrade. ::: Not doing so may result in inconsistencies between the config panel mechanism and the use of ynh_add_config. See also [the relevant issue](https://github.com/YunoHost/issues/issues/1973). ================================================ FILE: docs/dev/50.packaging/60.advanced/30.sso_ldap_integration.mdx ================================================ --- title: SSO/LDAP integration description: ' ' --- One powerful aspect of YunoHost is that apps are meant to be integrated with the SSO/LDAP stack, such that users logged in on YunoHost's user portal can be directly logged in each app without having to create an account in each of them nor having to re-log in each app every time. It should be stressed that there are two different aspects here: - the LDAP integration, meaning that the user accounts in the app are directly mapped to YunoHost user accounts - the SSO integration, meaning that a user logged in on the YunoHost user portal is automatically logged in on the app as well. Sometimes, LDAP integration is possible, but not SSO integration (though the opposite would be really weird as LDAP integration is somewhat required for the SSO to work) The SSO system is handled by [SSOwat](https://github.com/YunoHost/ssowat) and also handles the "permission" system which defines wether or not a user (or anonymous visitor) can access the app. ## LDAP integration LDAP is a de-facto standard when it comes to sharing a common user account database between multiple applications, hence its use in the context of YunoHost. However, each app does implement LDAP support in its own specific way (or doesn't), and needs to be provided with parameters to actually talk to YunoHost's LDAP database, usually via its config file. It is advise to look for real-life example of apps implementing these (such as Nextcloud, Wekan...) but you will usually need to provide: - LDAP host: `localhost` / `127.0.0.1` - LDAP port: `389` - Base DN : `dc=yunohost,dc=org` - User DN : `ou=users,dc=yunohost,dc=org` - Search filter: `(&(|(objectclass=posixAccount))(uid=%uid)(permission=cn=__APP__.main,ou=permission,dc=yunohost,dc=org))` (this makes sure that only people with the appropriate YunoHost/SSowat permission can access the app) - Username attribute: `uid` - Display name attribute: `displayname` - Email attribute: `mail` TODO/FIXME: moar explanations? What is missing? ## SSO integration This documentation apply to YunoHost\>=12. On YunoHost \<12 the header was a bit different but the idea was the same. Internally, SSOwat will on-the-fly inject theses different headers: |Name|Description|Protected over header injection from clients (a client try with a request to override the header and be logged in with a different user)|Header name for app which provide HTTP server and nginx transfert the request|How to get with php App| |----|----|----|----|----| |The username|the username of the authenticated user|Yes|`YNH_USER`|with `getallheaders()["Ynh-User"]` or `$_SERVER["HTTP_YNH_USER"]`| |User email|the email of the authenticated user. Could be usefull for some app which require an email for the username. Can be also used by some apps which populate all user infomration from the HTTP header instead of LDAP.|Yes|`YNH_USER_EMAIL`|with `getallheaders()["Ynh-User-Email"]` or `$_SERVER["HTTP_YNH_USER_EMAIL"]`| |User full name|The full name of the user. The full name of the user. Which is mostly used by some apps which populate all user infomration from the HTTP header instead of LDAP.|Yes|`YNH_USER_FULLNAME`|with `getallheaders()["Ynh-User-Fullname"]` or `$_SERVER["HTTP_YNH_USER_FULLNAME"]`| |The [HTTP Basic Auth Headers](https://en.wikipedia.org/wiki/Basic_access_authentication)|Like `Authorization: Basic `. If used we should be sure that the app check the credential (user and password) before to validate the authentication. It's mainly used by apps which need the credential to authenticate to a internal service. By example most of webmail need the credential to pass the correct credential to the mail server.|No. A client can send a header and will be passed to the application. It's why the application must check the credential to be sure that the passed passord are correct.|`Authorization`|with `getallheaders()["Authorization"]` or `$_SERVER["HTTP_AUTHORIZATION"]`| ### Usage For many application, like django, you will need configure the `YNH_USER` header, as the header to trust, to authenticate the user. For php apps it will be most of case the header `Ynh-User`. And for some app which need the auth basic header, you generally don't need to set the header name as the `Authorization` header name is normalized. ### Specific case #### App which reuse the auth basic header to authenticate to an internal service Currently you don't need any specific setup on YunoHost side. Since YunoHost provide the header needed, the application should be able to use it correclty. Depending of the application, some configuration could be needed. #### Application which provide an API Some app, like Nextcloud or SOGo provide an service like Caldav, Cardav or Webdav, the client will need to send the basic authentication and the nginx must transmit this authentication header to the serivice which will validate the authentication. Currently to make it working correctly you need to set a following app settings this way: ```bash ynh_app_setting_set --key=protect_against_basic_auth_spoofing --value=false ``` This will say to YunoHost that for this app we can safely transmit auth basic header from the client to the application. If you need to change this behavior after the application installation, you can set the option with: ```bash sudo yunohost app setting protect_against_basic_auth_spoofing -v false ``` Then you must regenerate the SSOwat configuration with: ```bash sudo yunohost app ssowatconf ``` And, finally, you need to reload NGINX configuration with: ```bash sudo systemctl reload nginx.service ``` ## Configuring SSOwat permissions for the app SSOwat permissions are configured using the 'permission' resource in your app's manifest.toml If relevant, you can create "sub" permissions for your app, for instance to only allow a specific group of people to access the admin UI of the app. For example: ```toml [resources.permissions] # This configures the main permission, i.e. general access to `https://domain.tld/$app/` # Initial access is defined using the `init_main_permission` install question. main.url = "/" # This configures an additional "admin" permission regarding access to `https://domain.tld/$app/admin` admin.url = "/admin" admin.show_tile = false # This means that this permission won't correspond to a tile in YunoHost's user portal admin.allowed = "admins" # Initialize the access for the "admins" group ... You can also use an install question called `init_admin_permission` to let the server admin choose this. ``` See the page about app resources for the full description of behavior and properties. ## Logging out on the app vs. Logging out of YunoHost A common [known issue](https://github.com/YunoHost/issues/issues/501) is that sometimes, logging out of YunoHost apps will not log people out of every app. This is for example the case for [Nextcloud](https://github.com/YunoHost-Apps/nextcloud_ynh/issues/19), because it uses its own authentication cookies which are not cleared when people log out of YunoHost. This is not trivial to fix. Similarly, logging out of the app doesn't necessarily log people from YunoHost entirely (which is more acceptable that clicking Log out and... not being logged out at all because you're still logged-in on the SSO, hence logged in on the app). Some YunoHost app do integrate custom patches such that the logout process of the app does automatically redirects to `https://domain.tld/yunohost/sso/?action=logout` which logs them out. ================================================ FILE: docs/dev/50.packaging/60.advanced/50.hooks.mdx ================================================ --- title: Hooks description: ' ' --- YunoHost includes a hook mechanism triggered on a lot of operation changing the system. You can use this mechanism in order to extend the behaviour of a YunoHost command. The most obvious case is adding a user. If you had a `post_user_create` hook, this hook will be triggered as soon as a user is added. ## How to add a custom hook on a specific instance :::tip Below we imagine we want to run a command after each user creation to add the user to samba user. ::: You should create a directory with the name of the hooks into `/etc/yunohost/hooks.d/`: ```bash mkdir -p /etc/yunohost/hooks.d/post_user_create ``` Next create a bash script inside this directory prefixed by 2 numbers and a dash: ```bash nano /etc/yunohost/hooks.d/post_user_create/05-add-user-to-samba ``` By default, the directory must be readable and traversable by root, but if you notice your hook is not run at all by YunoHost, you can check permissions with `ls -l /etc/yunohost/hooks.d/` and apply these commands if needed: ```bash chown root:root /etc/yunohost/hooks.d/post_user_create chmod u+rx /etc/yunohost/hooks.d/post_user_create ``` ## How to add a hook in an app package If you are packaging an app, you should not set by yourself the hook into `/etc/yunohost/hooks.d` instead you should create a hooks dir at the root of your package. ```text . ├── conf ├── hooks ├── scripts ``` In the hooks dir, create a bash script called with the type of hook you want to create for example `post_create_user`. ## Hooks referencies ### User and permissions #### post_user_create
Triggered after user creation This hook is run at the end of the command `yunohost user create` or equivalent action in webadmin. ##### Environment variables - YNH_USER_USERNAME: The username of the created user - YNH_USER_MAIL: The mail of the created user - YNH_USER_PASSWORD: The **clear** password of the created user - YNH_USER_FIRSTNAME: The firstname of the created user ([should be removed in future](https://github.com/YunoHost/issues/issues/296)) - YNH_USER_LASTNAME: The lastname of the created user ([should be removed in future](https://github.com/YunoHost/issues/issues/296)) ##### Positionnal arguments (deprecated) - $1: The username of the created user - $2: The mail of the created user ##### No waited return ##### Examples ###### Send automatically a mail to new user ```bash #!/bin/bash domain=$(cat /etc/hostname) message="Hello $YNH_USER_FIRSTNAME, Welcome on $domain ! Feel free to change your password. Let me know if you have a problem, The admin of $domain " echo $message | mail -s "Welcome on $domain !" $YNH_USER_MAIL ```
#### post_user_delete
Triggered at the end of user deletion This hook is run at the end of the command `yunohost user delete` or equivalent action in webadmin. ##### No environment variables ##### Positionnal arguments - $1: The username of the user deleted - $2: True if --purge option is used ##### No waited return ##### Examples ###### ```bash #!/bin/bash ```
### post_user_update
Triggered at the end of the user update This hook is run at the end of the command `yunohost user update` or equivalent action in webadmin. #### Environment variables :::warning Only arguments given to the cli/api are given as environment variable. ::: - YNH_USER_USERNAME: The username of the updated user - YNH_USER_FIRSTNAME: The firstname of the updated user ([should be removed in future](https://github.com/YunoHost/issues/issues/296)) - YNH_USER_LASTNAME: The lastname of the updated user ([should be removed in future](https://github.com/YunoHost/issues/issues/296)) - YNH_USER_PASSWORD: The new password of the updated user - YNH_USER_MAILS: The mail and mail aliases of the updated user seperated by comma - YNH_USER_MAILFORWARDS: The list of forward mails of the updated user separated by comma - YNH_USER_MAILQUOTA: The quota of the updated user (could be 0 or a number following by one of this unit: b, k, M, G or T) #### No positionnal arguments #### No waited return #### Examples ##### Send a mail on password changing ```bash #!/bin/bash " domain=$(cat /etc/hostname) message="Hello, Your password has been successfully changed on $domain. If you have not asked for changing your password, you probably should contact the admin of $domain. " echo $message | mail -s "Your password has been changed on $domain !" $YNH_USER_USERNAME ```
### post_app_addaccess
Triggered after adding a permission to users or groups This hook is run at the end of the command `yunohost user permission add` or equivalent action in webadmin. #### No environment variables #### Positionnal arguments (deprecated) - $1: The app name - $2: The list of users added separated by comma - $3: The name of the sub permission (`main`, `admin`, etc.) - $4: The list of groups added separated by comma #### No waited return #### Examples
### post_app_removeaccess
Triggered after removing a pemission to users or groups This hook is run at the end of the command `yunohost user permission remove` or equivalent action in webadmin. #### No environment variables #### Positionnal arguments (deprecated) - $1: The app name - $2: The list of users removed from the permission separated by comma - $3: The name of the sub permission (`main`, `admin`, etc.) - $4: The list of groups removed from the permission separated by comma #### No waited return #### Examples
## Domain, certificates and DNS ### post_domain_add
Triggered at the end of the domain add operation This hook is run at the end of the command `yunohost domain add` or equivalent action in webadmin. #### No environment variable #### Positionnal arguments (deprecated) - $1: The domain added #### No waited return #### Examples ##### ```bash ```
### post_domain_remove
Triggered after removing the domain This hook is run at the end of the command `yunohost domain remove` or equivalent action in webadmin. #### No environment variable #### Positionnal arguments (deprecated) - $1: The domain removed #### No waited return #### Examples
### post_cert_update
Triggered after Let's encrypt certificate update This hook is run at the end of the command `yunohost domain cert update` or equivalent action in webadmin. #### No environment variable #### Positionnal arguments - $1: The domain for which we have updated the certificate #### No waited return #### Examples ##### Restart a service after cert renewal ```bash #!/bin/bash systemctl restart gemserv ```
### custom_dns_rules
Customized your DNS rules for your domains This hook is run at the end of the command `yunohost domain dns suggest` or equivalent action in webadmin. Thanks to This hook you can customize #### Environment variables - `base_domain`: the top-level part of the domain - `suffix`: the subdomain part of the domain #### Positionnal arguments - $1: The base domain for which we want to build a DNS suggestion #### Waited return The script should return a JSON array with dictionnary in this format: ```json [ { 'type': 'SRV', 'name': 'stuff.foo.bar', 'value': 'yoloswag', 'ttl': 3600 } ] ``` #### Examples ##### Validate Let's Encrypt DNS challenge with a YunoHost DynDNS domain ```bash #!/bin/bash if [[ "$1" == "XXXX.nohost.me" ]] ; then echo "[ { 'type': 'TXT', 'name': '_acme-challenge', 'value': 'LETSENCRYPT_VALUE', 'ttl': 3600 } ]" fi ```
## Apps ### post_app_change_url
Triggered after an app has changed of URL This hook is run at the end of the command `yunohost app change-url` or equivalent action in webadmin. #### Environment variables - YNH_APP_OLD_DOMAIN: The old domain of the app - YNH_APP_OLD_PATH: The old path of the app - YNH_APP_NEW_DOMAIN: The new domain of the app - YNH_APP_NEW_PATH: The new path of the app #### No positionnal arguments #### No waited return #### Examples
### post_app_upgrade
Triggered on app upgrade This hook is run at the end of the command `yunohost app upgrade` or equivalent action in webadmin. #### Environment variables - YNH_APP_ID: The app id (for example nextcloud) - YNH_APP_INSTANCE_NAME: The app instance name (for example nextcloud__2) - YNH_APP_INSTANCE_NUMBER: The app instance number (for example 2) - YNH_APP_MANIFEST_VERSION: The app manifest version (for example 1 or ?) - YNH_ARCH: The arch as returned by `dpkg --print-architecture` - YNH_APP_UPGRADE_TYPE: The type of upgrade (UPGRADE_PACKAGE, UPGRADE_APP, UPGRADE_FULL) - YNH_APP_MANIFEST_VERSION: The version number - YNH_APP_CURRENT_VERSION: The version number of the app (in the YunoHost format) - NO_BACKUP_UPGRADE: 1 if we don't want to backup else 0 #### No positionnal arguments #### No waited return #### Examples ##### Change a settings in an app config file (unmanaged by config panel) ```bash #!/bin/bash source /usr/share/yunohost/helpers app=$YNH_APP_INSTANCE_NAME if [[ "$app" == "etherpad_mypads" ]]; then ynh_write_var_in_file --file=/var/www/etherpad_mypads/settings.json --key=max --value=100 --after=importExportRateLimiting systemctl restart etherpad_mypads fi ```
### post_app_install
Triggered at the end of an app installation This hook is run at the end of the command `yunohost app install` or equivalent action in webadmin. #### Environment variables - YNH_APP_ID: The app id (for example nextcloud) - YNH_APP_INSTANCE_NAME: The app instance name (for example nextcloud__2) - YNH_APP_INSTANCE_NUMBER: The app instance number (for example 2) - YNH_APP_MANIFEST_VERSION: The app manifest version (for example 1 or ?) - YNH_ARCH: The arch as returned by `dpkg --print-architecture` - YNH_APP_ARG_XXXXXXX: The argument of the manifest #### No positionnal arguments #### No waited return #### Examples
### post_app_remove
Triggered after removing an app This hook is run at the end of the command `yunohost app remove` or equivalent action in webadmin. #### Environment variables - YNH_APP_ID: The app id (for example nextcloud) - YNH_APP_INSTANCE_NAME: The app instance name (for example nextcloud__2) - YNH_APP_INSTANCE_NUMBER: The app instance number (for example 2) - YNH_APP_MANIFEST_VERSION: The app manifest version (for example 1 or ?) - YNH_ARCH: The arch as returned by `dpkg --print-architecture` - YNH_APP_PURGE: 1 if the --purge option has been activated #### No positionnal arguments #### No waited return #### Examples
## Backup / Restore ### backup
Add some files to backup This hook is run at the end of the command `yunohost backup create` or equivalent action in webadmin. #### Environment variables - YNH_BACKUP_DIR: The work dir in which we can store temporary data to backup like database dump - YNH_BACKUP_CSV: The CSV in which we add the things to backup. Don't use this directly and use ynh_backup helper instead. - YNH_APP_BACKUP_DIR: To document #### Positionnal arguments - $1: The work dir in which we can store temporary data to backup like database dump #### No waited return #### Examples ##### Backup some files in more (for example your custom hooks) ```bash #!/bin/bash # Source YNH helpers source /usr/share/yunohost/helpers ynh_backup_dest (){ YNH_CWD="${YNH_BACKUP_DIR%/}/$1" mkdir -p $YNH_CWD cd "$YNH_CWD" } # Exit hook on subcommand error or unset variable ynh_abort_if_errors # MISC ynh_backup_dest "conf/custom/misc" ynh_backup "/etc/sysctl.d/noipv6.conf" ynh_backup "/usr/local/bin/" ynh_backup "/etc/yunohost/hooks.d/backup/99-conf_custom" ynh_backup "/etc/yunohost/hooks.d/restore/99-conf_custom" ```
### restore
Restore some files This hook is run at the end of the command `yunohost backup restore` or equivalent action in webadmin. #### Environment variables - YNH_BACKUP_DIR: The work dir in which we can store temporary data to backup like database dump - YNH_BACKUP_CSV: The CSV in which we add the things to backup. Don't use this directly and use ynh_backup helper instead. #### Positionnal arguments - $1: The work dir in which we can store temporary data to backup like database dump #### No waited return #### Examples ##### restore custom files ```bash #!/bin/bash # Source YNH helpers source /usr/share/yunohost/helpers ynh_restore_dest (){ YNH_CWD="${YNH_BACKUP_DIR%/}/$1" cd "$YNH_CWD" } # Exit hook on subcommand error or unset variable ynh_abort_if_errors # MISC ynh_restore_dest "conf/custom/misc" ynh_restore_file "/etc/sysctl.d/noipv6.conf" ynh_restore_file "/usr/local/bin/" ynh_restore_file "/etc/yunohost/hooks.d/backup/99-conf_custom" ynh_restore_file "/etc/yunohost/hooks.d/restore/99-conf_custom" ```
### backup_method
Define a new way to backup and restore files This hook is run during the command `yunohost backup create` or equivalent action in webadmin. This hook is called several times with different action keywords. #### No environment variables #### Positionnal arguments - $1: The action ("need_mount", "backup", "mount") - $2: The work dir - $3: The name of the backup - $4: The repository in which the backup should be done - $5: An estimation size of the files to backup - $6: A description of the archive #### No waited return #### Examples ##### A very simple backup on rotationnal disks ```bash #!/bin/bash set -euo pipefail work_dir="$2" name="$3" repo="$4" size="$5" description="$6" case "$1" in need_mount) # Set false if your method can itself put files in good place in your archive true ;; backup) mount /dev/sda1 /mnt/hdd if [[ "$(df /mnt/hdd | tail -n1 | cut -d" " -f1)" != "/dev/sda1" ]] then exit 1 fi pushd "$work_dir" current_date=$(date +"%Y-%m-%d_%H:%M") cp -a "${work_dir}" "/mnt/hdd/${current_date}_$name" popd umount /mnt/hdd ;; *) echo "hook called with unknown argument \`$1'" >&2 exit 1 ;; esac exit 0 ```
## Configuration and firewall ### post_iptable_rules
Triggered after reloaded the firewall rules This hook is run at the end of the command `yunohost firewall reload` or equivalent action in webadmin. #### No environment variables #### Positionnal arguments - $1: True if upnp has succeeded - $2: True if ipv6 is available #### No waited return #### Examples ##### Forbid completely the outgoing 25 port except for postfix user ```bash #!/bin/bash iptables -A OUTPUT -p tcp --dport 25 -m owner --uid-owner postfix -j ACCEPT iptables -A OUTPUT -p tcp --dport 25 -m tcp -j REJECT --reject-with icmp-port-unreachable ```
### conf_regen
Change configuration suggested as default config in regen-conf mechanism This hook is run during the command `yunohost tools regen-conf` or equivalent action in webadmin. This hook is called several times with different actions keywords (pre and post operations). In order to be taken into account, the conf_regen hooks must: 1. be present in the folder `/etc/yunohost/hooks.d/conf_regen` 2. follow the naming convention `dd-sss_xxx`. `dd` are 2 digits and should be higher than the ones from the default hook (present in `/usr/share/yunohost/hooks/conf_regen`). `sss` is a string that defines the kind of hook (eg. `ssh` or `postfix`). `xxx` is a free field to help remind what is inside that hook. #### Environment variables - YNH_DOMAINS: The list of domains managed by YunoHost separated by comma - YNH_MAIN_DOMAINS: The list of main domains separated by comma #### Positionnal arguments - $1: The pre or post action - $2: Empty string due to legacy - $3: Empty string due to legacy - $4: In post mode the list of file which should be modified. In pre mode the dir in which we store pending configuration #### No waited return #### Examples ##### Fix the warning about postfix compatibility mode in postfix logs ```bash #!/bin/bash action=$1 pending_dir=$4 postfix_conf=$pending_dir/../postfix/etc/postfix/main.cf [[ "$action" == "pre" ]] || exit 0 [[ -e $postfix_conf ]] || exit 0 echo ' compatibility_level = 2' >> $postfix_conf ```
================================================ FILE: docs/dev/50.packaging/60.advanced/60.advanced_packagers.mdx ================================================ --- title: Advanced packagers description: ' ' --- Here comes the time: - you masterise [apps packaging](/dev/packaging/), [package_check](https://github.com/YunoHost/package_check), [example_ynh](https://github.com/YunoHost/example_ynh) and [experimental helpers](https://github.com/YunoHost-Apps/Experimental_helpers) - you have integrated the [YunoHost Apps Group](/community/yunohost_project_organization) - you know what means `¯\_(ツ)_/¯` - you use to say `Don't ask to ask, just ask` in the [YunoHost support room](/community/help) Here are few ideas that could help you to improve YunoHost apps packaging. Usually, there are things that slow you down: - Installing your freshly done package because of dependencies installation or npm/rust/elixir/composer builds - Waiting a package_check to see the level of your package - etc... The idea is to use YunoHost stuffs to help you improve this lost time. ## Building your infrastructure First idea is to build several VMs, LXCs or VirtualBoxs with YunoHost to let you parallelize actions, like having the first one installing an app, the second installing another app, the third one debugging an app upgrade, etc... After first installation of those VMs/LXCs, each one has to be reacheable with its domain name, like for example: - ynh1.mydomain.org - ynh2.mydomain.org - ynh3.mydomain.org For that you will need a public IP for each one or reverse proxy... If your are lucky enough to have IPV6 and a /64 IPV6 scope, it won't be a problem to assign a public IPV6 to each YunoHost. Another way the DNS stuff is to simply use an hosts file. In addition, it's helpfull to have several domains names for each YunoHost, for example: - ynh1.mydomain.org - test11.mydomain.org - test12.mydomain.org - test13.mydomain.org - ynh2.mydomain.org - test21.mydomain.org - test22.mydomain.org - test23.mydomain.org - ynh3.mydomain.org - test31.mydomain.org - test32.mydomain.org - test33.mydomain.org With that you will be able to install two apps on the same YunoHost first one at `https://test11.mydomain.org` and a second app at `https://test12.mydomain.org` (let say the first app is nextcloud_ynh the second one is collabora_ynh or onlyoffice_ynh) When your infrastructure is up and ready, you will have to do snapshots of each VMs/LXCs. Doing that, you will be able to revert back to an happy and healthy YunoHost after doing install/backup/restore/upgrade of and app... Don't forget to regularly upgrade your YunoHosts VMs/LXCs to the last release doing: revert back to last happy/healthy YunoHost snapshot and doing `yunohost domain cert renew --no-check && yunohost tools update && yunohost tools upgrade --apps && yunohost tools upgrade --system && apt autoremove`. Take a snapshot after that successfull full upgrade. And after some testings or one week later, remove old snapshot. PS: that can be automated... Example of a script to upgrade a master VirtualBox VM ```bash #!/bin/bash # printers normal="\e[0m" bold="\e[1m" white="\e[97m" blue="\e[34m" echo_info() { echo -e "[${bold}${blue}INFO${normal}] ${bold}${white}$1${normal}" } echo_info "### Update host" sudo apt update sudo apt dist-upgrade sudo yunohost settings set security.password.user.strength -v -1 sudo yunohost settings set security.password.admin.strength -v -1 echo_info "### Update package_check" ( cd package_check; git pull) echo_info "### Update LXC container" package_check/sub_scripts/lxc_upgrade.sh echo_info "### Clean hosts" sudo apt autoclean sudo apt autoremove echo_info "### Fill free space with zero" cat /dev/zero > zeros ; sync ; rm zeros echo_info "### Run 'VBoxManage modifyhd --compact file.vdi' to reduce the size of this VM" ``` Example of a script to customize a cloned VM ```bash #!/bin/bash master_domain=domain1.fr domainX=domain2.fr master_ip=70 ipX=68 sudo yunohost --admin-password admin domain add $domainX sudo yunohost --admin-password admin domain add sous.$domainX sudo yunohost --admin-password admin tools maindomain -n $domainX sudo yunohost --admin-password admin domain remove $master_domain sudo yunohost --admin-password admin domain remove sous.$master_domain sudo sed -i "s/address 192.168.1.$master_ip/address 192.168.1.${ipX}/" /etc/network/interfaces sudo reboot ``` Doing that you will have all the time a full/ready to go YunoHosts infrastructure for advanced packagers. And if require, you can have some VMs/LXCs runnning the YunoHost testing or YunoHost next Debian main version. ## Having your packages/commits available in each VMs/LXCs There are several ways to have your freshly created package available from each VMs/LXCs 1- Do an ssh from the YunoHost VM/LXC to a central repository on your computer 2- Having a shared directory available from each VMs, LXCs VirtualBoxs 3- Rsync you central repository to each VM/LXC 4- Use [syncthing](https://github.com/YunoHost-Apps/syncthing_ynh) to syncrhonise you main repository on each VM/LXC Example of a script to mount as shared directory a packaging directory into a VirtualBox VM ```bash #!/bin/bash shared_folder=my_directory # printers normal="\e[0m" bold="\e[1m" white="\e[97m" blue="\e[34m" echo_info() { echo -e "[${bold}${blue}INFO${normal}] ${bold}${white}$1${normal}" } # Create the main directory for the mount sudo mkdir -p "./$shared_folder" # Mount ynh-dev directory from the host echo_info "Mount shared directory $shared_folder" sudo mount -o defaults -t vboxsf $shared_folder "./$shared_folder" ``` ## Shortcuts Use and abuse of `yunohost app install` `--args` argument You can do ugly thing considering mynewapp is the name/REPLACEBYYOURAPP of your app To install your mynewapp app: ```bash YNHAPP=mynewapp yunohost app install /mycentralrepo/${YNHAPP}_ynh/ --debug --force --args domain=test11.mydomain.org&path=/myapp&admin=alice&is_public=true&language=en&password=awesomepassword ``` To remove your mynewapp app and reinstall it ```bash YNHAPP=mynewapp yunohost app remove ${YNHAPP} --debug && yunohost app install /mycentralrepo/${YNHAPP}_ynh/ --debug --force --args domain=test11.mydomain.org&path=/myapp&admin=alice&is_public=true&language=en&password=awesomepassword ``` To backup your mynewapp app ```bash YNHAPP=mynewapp yunohost backup create --apps ${YNHAPP} --debug ``` To restore your mynewapp app from the backup just made ```bash YNHAPP=mynewapp yunohost backup restore XXXXXXXX-XXXXXX --apps ${YNHAPP} --debug ``` To upgrade your mynewapp ```bash YNHAPP=mynewapp yunohost app upgrade ${YNHAPP} -f /mycentralrepo/${YNHAPP}_ynh/ --debug ``` With that, you will be able to launch different actions on differents YunoHost VMs/LXCs ## Package_check With advanced packaging comes [CI_package_check](https://github.com/YunoHost/CI_package_check), it lets you serialize and automate package_check. ## Managing all the parallel packaging you are working on When you do several things at the same time, sometimes you don't remember what is the next step for this or that app. A good tool to keep your TODO list organized is to use a kaban like apps: - [Kanboard](https://github.com/YunoHost-Apps/kanboard_ynh) - [Wekan](https://github.com/YunoHost-Apps/wekan_ynh) ================================================ FILE: docs/dev/50.packaging/60.advanced/70.packaging_v2.mdx ================================================ --- title: Packaging v2 description: ' ' --- Packaging v2 is a major improvement for the packaging introduced in YunoHost 11.1 ### Motivation The motivations for this new format is: - to get rid of some boring or unnecessarily complex or duplicated stuff such as saving/loading settings, creating a system user, etc. during the install/upgrade/restore script, which are common things across many apps. - to get rid of funky historical, not-super-semantic stuff such as `__FINALPATH__` being replaced by `$final_path` (with underscore), or `__PATH__` being replaced by `$path_url`, etc. - formalize some aspects such as the existence of the install dir, data dir, apt dependencies, database, etc. which in turn unlock possible future developments such as computing the space used by an app at one given moment, auto-upgrading apt dependencies during Debian major migration, etc. - formalize some meta-info such as LDAP/SSO support, architectures supports, and other pre-install / post-install, pre-upgrade / post-upgrade notifications (replacing the infamous `ynh_send_readme_to_admin`) for better UI/UX during the install and upgrade process. However, this "v2" is not the end of the story and should be seen as an intermediate stage before a "v3" packaging. In particular this "v3" packaging should also formalize the handling of the system and app configurations files and ultimately rework the entire paradigm of the install/remove/upgrade/backup/restore scripts. ### Adapting a v1 app to v2 A script is available in [the apps_tools repository](https://github.com/YunoHost/apps_tools/tree/main/packaging_v2) and will attempt to convert what it can from the v1 format to the v2 format, in particular: - initializing a `manifest.toml` and prefilling it with info scrapped from the various scripts - comment out now-unecessary lines in the various scripts Usage: `python3 convert_app_to_packaging_v2.py /path/yo/your/app` This will edit the file in place and you should then carefully review and iterate over what the script did for you. ### Highlights of the new format The [example repo](https://github.com/YunoHost/example_ynh) illustrates the below. - **The manifest is now written as toml (`manifest.toml`)** instead of json (`manifest.json`). The structure of the manifest itself has been reworked and now include: - The `upstream` section (now mandatory) - An `integration` section meant to formalize what minimum YunoHost version is required, the list of supported architectures, declare if SSO/LDAP is supported, typical resource usage. This is meant to be displayed both in the catalog (similar to app stores) and on the app info page after installing the app - though this is still work in progress. - A `resource` section (detailed below) - **Install questions are now automatically saved as settings** (except user-provided password and other specific infos) - **All settings are now automatically loaded in app script environments** (so e.g. directly define `$domain`, etc.) - **Auto-enable `set -eu`** a.k.a. `ynh_abort_if_errors` in appropriate scripts - **The safety-backup-before-upgrade is now automatically handled by the core** - **Simplify writing change-url scripts**: old the `new`/`old`/`change` `domain`/`path` are now automatically available in the context and a new helper `ynh_change_url_nginx_config` takes care of tweaking the nginx conf. Your script should essentially just call that helper and possibly tweak the app's conf and possibly restart the app's service - **Introduce a new `resource` mechanism** - Resources are declared in the `manifest.toml`. - They are meant to formalize recurring app needs that are to be provisioned/deprovisioned by the core. - They include for example: system user, apt dependencies, install dir, data dir, port, permissions, SQL database... - Each resource is to be provisioned *before* running the install script, deprovisioned *after* the remove script, and automatically upgraded if needed before running the upgrade script (or provisionned if introduced in the new app version, or deprovisioned if removed w.r.t. the previous app version) - More infos about resources and their options and behavior are available in the dedicated doc page - **Permissions are automatically initialized using the answer to the `init_main_permission` install question** (replacing the `is_public` question). No need to write a boring `if $is_public ...` in the install script to add visitors anymore ! There is a similar mechanism to init other permissions, eg `init_admin_permission` (cf also the doc about the `permission` resource) - **The content of the `doc/` folder is now meant to be integrated in the webadmin** (though this is still WIP as of writing this). In particular: - `DESCRIPTION.md` and the `screenshots/` folder are expected to be displayed prior to the app install form (similar to app stores on mobile) - `ADMIN.md` is expected to be made available somewhere in the info page and should contain technical admin notes. Other pages can be defined (just name it `WHATEVER.md`). Lang codes are also supported following the existing scheme for the README, eg `README_fr.md` is the French version, hence you can create `ADMIN_fr.md`, etc. - Note that the `ADMIN.md` page supports the `__FOOBAR__` notation that will be automatically replaced with the app's `foobar` setting - **Special files called 'notifications' are meant to replace the `ynh_send_readme_to_admin` mechanics**. They are also to be added to the `doc` folder: - `doc/PRE_INSTALL.md`: a note to be displayed prior to the app install. Typically to warn of something unusual, such as "the app install will automatically add 1GB swap to the system". - `doc/POST_INSTALL.md`: a note to be displayed after the app install. Typically to explain post-install operations to be performed manually by the admin and that cannot be automated. - `doc/PRE_UPGRADE.md`: a note to be displayed prior to any upgrade of this app. - `doc/PRE_UPGRADE.d/{version}.md`: a note to be displayed prior to a specific version upgrade. - `doc/POST_UPGRADE.md`: a note to be displayed after the app upgrade. For example in the context of Nextcloud, the fact that you may need to re-enable custom modules manually? - Note that the notifications, like `ADMIN.md`, supports the `__FOOBAR__` notation that will be automatically replaced with the app's `foobar` setting - **Replace some historical names with more sensible ones**, or homogenize some practices: - `final_path` is now `install_dir` (this migration should be automatically handled by the core and the `convert_app_to_packaging_v2.py` script) - `datadir` is now `data_dir` to be consistent with `install_dir` (this migration should be automatically handled by the core and the `convert_app_to_packaging_v2.py` script) - `path` is now always loaded as `$path`, no funky `$path_url`-but-it-is-saved-as-`path` anymore (this migration should be automatically handled by the core and the `convert_app_to_packaging_v2.py` script) - `mysqldbpwd` and `psqlpwd` or whatever are now always saved as `db_pwd` (cf the `database` resource) (this migration should be automatically handled by the core and the `convert_app_to_packaging_v2.py` script) - ports settings are now always named either `$port` or `$port_foo_bar` instead of `$foo_bar_port` (cf the `port` resource) (this migration should be automatically handled by the core and the `convert_app_to_packaging_v2.py` script) - the install dir is to be set to `/var/www/$app` by default for web apps (or can be changed to `/opt/????` for non-webapps). Note that YunoHost will **automatically move** the old install dir to the new `install_dir` during the corresponding upgrade. ================================================ FILE: docs/dev/50.packaging/60.advanced/_category_.yaml ================================================ label: Advanced link: type: generated-index title: Advanced slug: /packaging/advanced ================================================ FILE: docs/dev/50.packaging/80.misc/_category_.yaml ================================================ label: Misc resources link: type: generated-index title: Misc resources ================================================ FILE: docs/dev/50.packaging/80.misc/packaging_apps_git.mdx ================================================ --- title: Use Git to package apps --- Git... Our dear beloved Git, which can be described also as "Goddamn Idiotic Truckload of sh\*t", according to Linus. Be sure if you don't know Git yet that you will soon agree with that description. YunoHost and all our apps are on the Git forge GitHub. Which means that if you want to work on an app, sooner or later you're going to have to deal with Git. So let's see how to work with Git to be able to contribute in the context of YunoHost. ## Working with GitHub Let's go first for the easy part, GitHub comes with an "easy" web interface to deal with. *First things first, unfortunately there's no way around, you need an account on GitHub.* ### Branches Then, probably one of the most important thing, **do not work directly on the master branch**. Sorry, it has to be said ! Branches are, as GitHub explains, "*a parallel version of a repository. It is contained within the repository, but does not affect the other branches. Allowing you to work freely without disrupting the "live" version.*" The master branch is the branch that contains the version of the app users will actually install and use. The usual thing to do is to work from the testing branch, and when everything is settled and tested, you can merge the testing branch in master, so users will enjoy the new release of your package. To see and change the current branch, use this button: ![](/img/github_branch.png) ### Edit a file Now that you're on the right branch, let's see how to edit a file on GitHub. You can edit any file by using the small pencil icon: ![](/img/github_edit.png) If you don't have the permission to write on the repository, you will see (as on the picture) that you're going to create a fork (we'll see below what a fork is). If you have the permission to write, you will just edit the file, without forking. ### Commit your changes When you're done with your modification on the file, you can commit your changes. Behind that word, the idea is quite simple, you're just going to save your changes... ![](/img/github_commit.png) The first field is the name of your commit, a very short sentence to explain why you did this modification. The second field is a large one for a more complete explanation, if you need it. Finally, if you're editing a repository on which you have permission to write, you can either commit directly to the current branch or create a new branch. It's usually better to create a new branch, that way you keep your modifications on a *parallel* version of the repository. Your modifications will be discussed in a pull request (explained below) then finally merged into the original branch. ### To fork or not to fork A fork is a copy of a repository into your own account. We have seen before that if you don't have permission to write into a repository, editing a file will automatically create a fork. Because the fork is on your account, you always have the permission to write on it. But even if a fork is not the real repository, but just a copy, a fork is always linked to its parent. We'll see later that to create a fork is really useful when opening a pull request. When you create a new package, it's common to use the [example app](https://github.com/YunoHost/example_ynh) as a base. But, because you don't want to keep that link to the example app, you should not fork the example app. You will rather clone the app. Unfortunately, to clone an app is a little bit trickier on GitHub. We will see later how to clone to a local repository instead. We have seen how to edit a file, and how this could fork the app. But, when you want to edit multiple files, the GitHub interface isn't really the best way. In such situation, you would rather clone the repository and work on a local repository. You may still need to fork on your own account to be able to save your modifications if you don't have the permission on the distant repository. ### Pull request After you have committed your changes, whether on a branch or a fork, you want to propose your modifications to be integrated into the main repository, or the original branch. To do so, you're going to *create a pull request*. GitHub usually ask you directly if you want to do so. Otherwise, you'll find the button to create a pull request just here: ![](/img/github_pull_request.png) When creating a pull request from a fork, to ease the work of the reviewers, **do never** uncheck the checkbox *Allow edits from maintainers*. That option simply allow the maintainers of the original repository to edit directly your work. ### YunoHost-Apps organization Following the [guide for packaging application within YunoHost](/dev/packaging/), your app has to be into the YunoHost-Apps organization, but if you have never contributed to an app before or never had any app into this organization you may not have the permission. First, you need the permission to write into the organization, to do so, ask to the Apps group on the Apps XMPP room. To transfer your app to the YunoHost-Apps organization, go to your repository and to *Settings* tab. At the bottom of the page, you will find *Transfer ownership*. Into the field *New owner’s GitHub username or organization name*, type *YunoHost-Apps*. Your repo will be moved into the organization, you don't have to remove the original repository. ## Working with Git locally As we have seen, you can do a lot of things directly on GitHub. But when you need to edit multiple files, or when you need to work on your code on your own, it's better to work directly on your computer. Before going to the hellish part of Git, let's see two different ways to start working with Git. ### First case: Creating a new package You have shockingly discovered that the wonderful app you love to use everyday does not yet have its YunoHost package. And because you're nice, you decided to create yourself the package, so everyone will enjoy that app the way you do. What a good idea! The best is to start from the [example app](https://github.com/YunoHost/example_ynh). But as we have explained before, you don't want to fork, because if you do so, you're going to keep that link to the example app and it's really annoying. So, you're going to do it differently. You're going to clone! #### git clone To clone, you're going to do: ```bash git clone https://github.com/YunoHost/example_ynh ``` `git clone` will download a copy of the repository. You will have the complete repository, with its branches, commits, and everything (into that apparently little `.git` directory). To git clone is usually the starting point of any local work with Git. *A side note though, if you expect to send your modifications back to the distant repository on GitHub, be sure to have the permission to write on this repository. Otherwise, fork before and clone your fork, on which you do have the permission.* #### My brand new package, continued In the context of a new package, you will also need to create a repository on GitHub to nest your package. Which is as simple as a big green *New* button. Don't bother with README, .gitignore or license. Just create the repository itself. you can now git clone that new repository. ![](/img/github_create_new_repo.png) You now have 2 repositories cloned on your computer. Copy all the files from the example_ynh app, **except the .git directory** (You just want the files themselves) to your new package. *If you want, you can remove the example_ynh app. We don't need it anymore.* You're ready to work on your new package ! ### Second case: Working locally on a repository You already have a repository, but what you want is just to work locally, so you can modify multiple files. Simply clone the repository, the .git directory is the link to the distant repository. Nothing else to do than a `git clone`. ### Branches You do have your local copy of the repository, but because you have read carefully this documentation until then, you know that you should be sure to be on the testing branch before starting to work. To see the branches, and to know on which you actually are, while into the directory of your repository, type `git branch`. The current branch is highlighted and preceded by a `*`. ### `git checkout` If it appears that you're not on the branch you wanted to be, or you're actually on master (which is bad !), you can move to another branch with `git checkout` ```bash git checkout testing ``` *Read carefully what Git says when you validate a command, do never forget that Git is sneaky...* ### `git pull` before anything else You're finally on the right branch, and ready to work. **Wait ! A nasty trap is waiting for you...** Before ending up in an inextricable situation. Start with a `git pull` to update your branch to the latest change from the distant repository. *Sometimes, you will encounter an impossible situation where Git is saying that you can't pull because you have local changes. But you don't care of those local modifications, you just want to get the last version of the distant branch. But Git don't care about what YOU want...* *I have to admit that my only solution is as highly efficient as dirty... A good old `rm -r` of the repository and a `git clone`* ### Let's work Eventually, you can work on your code. When you are finally ok with what you have done, it's time to validate your work. The first step is to inform Git about which file(s) to validate. To do so, we'll use `git add` ```bash git add my_file git add my_other_file and_also_this_one ``` If you want to validate all your work, you can also simply do ```bash git add --all ``` To check the current status of your validation, you can use `git status`. It will show you which files will be included into your commit, and which files are modified, but not yet included. `git status -v` will show also which part of the files are modified. A good way to be sure that you didn't make a mistake before committing. ### `git checkout -b` Before committing, or after, or before starting to work. Whenever you feel like it ! You should consider adding your work to a separate branch, that way, it will be easy to create a pull request to merge into the testing branch and discuss with the other packagers what you suggest to change. To create a new branch and move to this branch, you can use `git checkout -b my_new_branch`. ### `git commit` To commit is simply to validate your work in Git. As you can do in GitHub. To have the same fields that you had on GitHub, with the name of the commit, and a longer explanation. You can simply use `git commit`. The first line, before the comments, is for the name of the commit. After all the comments, you can add an explanation if you want to. If you want to commit with only a name for your commit, you can use a simple command: ```bash git commit -m "My commit name" ``` ### Push to the distant repository Your changes are validated, but only on your local clone of the repository. Now, you have to send those modifications back to the distant repository on GitHub. In order to do that, you need to know what is your current branch. (If you don't know, `git branch` will give you that info). Then you can git push ```bash git push -u origin BRANCH_NAME ``` ================================================ FILE: docs/dev/50.packaging/80.misc/packaging_apps_virtualbox.mdx ================================================ --- title: Create a development environment with VirtualBox --- This documentation page aims at explaining how to setup a YunoHost virtual server, using VirtualBox, to work on application packaging. ## Why use VirtualBox rather than an actual YunoHost production server to package an application? There are mostly two reasons why one should prefer a virtual server rather than their own server: - You can freely torture a virtual server without any risk of breaking it, since you can always restore it to a former working state. It would really be a pity to break your own real server! - In a typical workflow, a virtual server state would be restored from a known snapshot before starting any work on it, so as to always keep a clean system, without any residues of a former installation. This allows you to always be as close as possible to a user's first installation. We will discuss VirtualBox in this guide, as it comes with an easy to use GUI. If you prefer a pure commandline approach to handling your virtual machine, you should use [ynh-dev](/dev/core/) instead. ## Installing VirtualBox From a GNU/Linux system, simply install the `virtualbox-qt` package. From a Windows or macOS machine, you'd have to refer to the [VirtualBox download page](https://www.virtualbox.org/wiki/Downloads) to fetch the appropriate installation package. The virtualbox package is deprecated since Debian 9, a `.deb` installation package is available on the abovementioned referenced page. Whatever your system, there should be no need to install the extension pack or the guest addons. ## Installing YunoHost on VirtualBox Simply follow the appropriate documentation for [installing on VirtualBox](/dev/packaging/misc/packaging_apps_virtualbox) then the [post-installation](/category/after-installation) guide. During post-install, there is no need to use an actual domain name in `.nohost.me` or `.noho.st`, as your virtual server won't be reachable from outside your local network. We prefer using a fake domain name which will remain associated with your local network, for instance `yunohost.packaging`. This domain name, not being registered with any DNS server, will be stored in the `hosts` file of the computer which will need to access it. Please refer to the documentation about [using a local DNS](/admin/tutorials/domains/dns_local_network) for more information. Your virtual server is now installed. Before starting to use it, we'll see how to create a first snapshot and how to use that feature. ## Using snapshots VirtualBox becomes even more interesting with its snapshotting feature, which allow to store the virtualized machine state and restore it quickly. We'll also see how to use multiple snapshot branches to work on different apps on the same machine. ### Now, let's create a first snapshot Before starting to play with the virtual machine, now is a good time to take a first snapshot, so that we don't have to redo the full install process every time. First, stop the virtual machine. Managing snapshots is done in the 'Snapshots' tab ![](/img/softwares/virtualbox_packaging1-en.png) Here, we're creating a first snapshot ![](/img/softwares/virtualbox_packaging2-en.png) We can now start to work on the virtual machine and create as many snapshots as desired for each milestone of our modifications. ![](/img/softwares/virtualbox_packaging3-en.png) In this example, after having validated our particular package removal works fine, we can easily get back in time by restoring the virtual machine to its previous state with the package still installed. Once the package will be fully functional, it will just be a matter of deleting the snaphots associated with this package work to get the virtual machine back to its initial state. For our next test, we will then be back to a freshly installed YunoHost serveur, without any trace of package installation. ### Using multiple snapshot branches In addition to successive snapshots, it is also possible to create a new machine state and additional snapshots from an older machine snapshot/state. ![](/img/softwares/virtualbox_packaging4-en.png) In this example, I have created two branches since my successful package installation, so as to independently test just the application removal, upgrade and backup/restore steps. I eventually got back to the virtual machine base state to start a new test on another package, without dropping my former test whatsoever. At any time, it is possible to get back to a previous snapshot simply by restoring it. The machine always start on the "Current state" state. ![](/img/softwares/virtualbox_packaging5-en.png) > It is always possible to create a new snapshot, whether the machine is stopped or not. To restore a snapshot however, the machine cannot be running. ## How do we connect to the virtual machine? Virtual machine connection is similar to any YunoHost server connection, that is by using SSH. ```bash ssh admin@my.domain ``` Or, if the domain has not been added to the `hosts` file, via its IP address. ```bash ssh admin@11.22.33.44 ``` We can now work on the virtual machine using the commandline. To easily copy the package files or use a graphical text editor, one can also connect via SFTP using a file explorer. It's a simple matter of using the `sftp://admin@my.domain/` address. ![](/img/softwares/virtualbox_packaging6.jpg) > Note: on Windows or macOS, the file explorer does not natively support the SFTP protocol... ================================================ FILE: docs/dev/50.packaging/80.misc/shell_variables_scope.mdx ================================================ --- title: General scope of variables template: docs taxonomy: category: docs routes: default: '/shell_variables_scope' --- Variables exists for the current shell and its children only. Another script executed from the script is not a child, it's another shell which herited only the environment variables from its caller script, not its globals or locals variables. When a script is called, it isn't started in the current shell, but in a new instance of bash which herite environment variables from its parent. ```bash var1=value1 export var2=value2 echo "$var1" echo "$var2" # var1 and var2 exist echo "-" echo " echo \"\$var1\" echo \"\$var2\"" > other_script.sh chmod +x other_script.sh ./other_script.sh # Here, var1 doesn't exist, only var2 still exists. # Because it's an environment variable. ``` In your current shell, where you launch this script, try ```bash echo $var1 - $var2 ``` None of this 2 variables exists, because their scope is limited to the script itself. Never its parent. ### Functions inside a script Use a function would not change the scope of variables. ```bash var1=value1 export var2=value2 set_variable () { var3=value3 export var4=value4 echo "$var1" echo "$var2" echo "$var3" echo "$var4" # All variables exists here # Because the function inherite its variables from the script. } set_variable echo "$var1" echo "$var2" echo "$var3" echo "$var4" # var1 var2, var3 and var4 exist # var3 exist because the function is executed in the same shell than the script itself. echo "-" echo " echo \"\$var1\" echo \"\$var2\" echo \"\$var3\" echo \"\$var4\"" > other_script.sh chmod +x other_script.sh ./other_script.sh # Here, var1 and var3 don't exist, only var2 and var4 still exist. # Because they're environment variables. ``` ### The usage of locales variables Locales variables are limited to the function and its children. ```bash var1=value1 export var2=value2 set_variable () { var3=value3 export var4=value4 local var5=value5 echo "$var1" echo "$var2" echo "$var3" echo "$var4" echo "$var5" # All variables exists here # Because the function inherite its variables from the script. } set_variable echo "-" echo "$var1" echo "$var2" echo "$var3" echo "$var4" echo "$var5" # var1 var2, var3 and var4 exist # var3 exist because the function is executed in the same shell than the script itself. # var5 doesn't exist, because its scope is limited to the function which declare it. echo "-" echo " echo \"\$var1\" echo \"\$var2\" echo \"\$var3\" echo \"\$var4\" echo \"\$var5\"" > other_script.sh chmod +x other_script.sh ./other_script.sh # Here, var1, var3 and var5 don't exist, only var2 and var4 still exist. # Because they're environment variables. ``` Using a local variable is usefull for limit it scope to the function only. And not bother the script in its globality with useless variables. But there's also another advantage with local variable, do not modify the content of a global variable. ```bash var1=value1 var2=value2 var3=value3 set_variable () { echo "$var1" echo "$var2" echo "$var3" echo "-" var2=new_value2 local var3=new_value3 echo "$var1" echo "$var2" echo "$var3" # Values of var2 and var3 are modified in the function. } set_variable echo "-" echo "$var1" echo "$var2" echo "$var3" # var3 retake is original value, # because in the function, var3 was declared as a new locale variable. # But var2 was directly modified, so its value still changed. # Because, var2 in the function is still a global variable. ``` As seen previously, modified or created variables in a function can affect the main script because the function is executed in the same shell. But, the things are different if the function is executed in a sub shell, the function become a child which only inherite from its parent. ```bash var1=value1 var2=value2 var3=value3 fonction2 () { echo "-" echo "var1=$var1" echo "var2=$var2" echo "var3=$var3" echo "var4=$var4" echo "var5=$var5" # Even var3, which is local, is inherited from the parent function. } set_variable () { echo "var1=$var1" echo "var2=$var2" echo "var3=$var3" # Variables are inherited from the parent. echo "-" var2=new_value2 local var3=new_value3 var4=new_value4 export var5=new_value5 echo "var1=$var1" echo "var2=$var2" echo "var3=$var3" echo "var4=$var4" echo "var5=$var5" # Values of var2 and var3 are modified in the function. (fonction2) } (set_variable) # Start the function in a sub shell. echo "-" echo "var1=$var1" echo "var2=$var2" echo "var3=$var3" echo "var4=$var4" echo "var5=$var5" # var2 and var3 retake their original values. # Because the function is in a child shell which never affect its parent. # Likewise, var4 and var5 don't exist, because they're been declared in child shell. # The parent never inherite from its children shell. ``` ### Conclusion - The scope of a variable is always the current shell and its children, never its parent shell. - An environment variable may be exported to a new shell, detached from the first one. If the last one executed the second one. But, it can't affect the parents. - A locale variable in a function, executed in the current shell, can't affect the environment outside of the function. End allow also to not affect a global variable with the same name. - A function executed in a sub shell will never affect its parent, with global or local variables. - A parent can NEVER be affected by variables defined or modified in its children shell. ================================================ FILE: docs/dev/50.packaging/90.policy.mdx ================================================ --- sidebar_label: Catalog policy title: YunoHost's policy regarding the apps included in the official catalog --- ### License The rule of thumb is that we only include software licensed under a free-software license in the official app catalog. As YunoHost grew, some gray area cases appeared with software that would be relevant for [YunoHost's goal](/community/faq#whats-yunohost-goal) and match its spirit, while not being strictly-speaking free-software. These applications may be: - promoting the use of centralized services, though precisely to avoid their direct usage ; - relying on non-free dependencies or assets ; - released under "new" post-open-source or ethical-yet-not-free licenses such as the [ACSL](https://anticapitalist.software/), the [HL3](https://firstdonoharm.dev/) or the [CoopCycle License](https://github.com/coopcycle/coopcycle-web/blob/master/LICENSE) ; - released under "open-core" models, trademark clauses, or business-related license clauses (such as the BSL) which are meant to ensure the project's sustainability while remaining ethical. While we believe free software principles are an essential footstep towards [YunoHost's goal](/community/faq#whats-yunohost-goal), we believe they are a means and not an end. We reject the purist vision according to which software is either free or proprietary, and the flawed premise that technology is fundamentally neutral. We believe that ethical software and technology can and should exist beyond the definition of free software layed 40 years ago (see also: [Freedom isn't Free](https://logicmag.io/failure/freedom-isnt-free/) and [Post-Open Source](https://www.boringcactus.com/2020/08/13/post-open-source.html)). The project therefore allows the inclusion inside the official app catalog, ***on a case-by-case basis***, of apps which does not qualify as "free software", yet considered to be ethical and worthy of interest for [YunoHost's goal](/community/faq#whats-yunohost-goal). Such apps are tagged in the catalog, such that an explicit message displayed before their installation. If you notice an app is missing such a tag/disclaimer, feel free to open a discussion or pull requet on [the app catalog](https://github.com/YunoHost/apps/). If you run YunoHost for your business, you are responsible for doing your due diligence by checking the licenses of the software you want to install on your server. ### Nature of the app In addition, the YunoHost team decided to not include apps in the official catalog if they: - are overly complex to deploy or resource-hungry compared to their features ; - only apply to super niche use cases ; - promote cryptocurrencies ; - promote AI for purposes deemed futile compared to the ecological and sociological costs involved behind the scenes ; - promote shady activities such as tracking/stalking people. The team may make exceptions to these criteria on a case-by-case basis, on its own volition. The team may also amend this list with other criteria in the future. ### What to do if you're not happy with these criterias These editorial choices do not mean that apps infringing them cannot be created, merely that they won't be included in the official catalog. You are free to: - [Develop your own application packages](/dev/packaging/) (though support may be limited due to aforementioned criteria) - Manually install any application by using `yunohost app install ` - Create and add a custom catalog source within `/etc/yunohost/apps_catalog.yml` ================================================ FILE: docs/dev/50.packaging/index.mdx ================================================ --- title: 📦 Application packaging --- YunoHost relies on applications, and so, on their packagers. This documentation is here to help you package and maintain apps. ## Packaging philosophy The simplicity of using apps is a key feature of YunoHost. As a packager, you should remember these principles: - **The admin should not have a PhD in computer science to be able to install, configure and use your application**: try to assume that the admin doesn't know about advanced computer concepts; - **Less is more**, **Keep it simple**: don't overcrowd the admin with a dozens technical questions; - **Things should work out of the box**: for example, the admin should not have to manually finish the installation process by manually filling in database credentials; - YunoHost app packaging is **not just about installing** sources and dependencies: it's also about maintenance (upgrade, backup...) and integrating the app in the YunoHost ecosystem (NGINX, SSO/LDAP, Fail2Ban, application catalog, UI/UX...) ## Prerequisites Before diving in, this documentation assumes that: 1. You already are a YunoHost admin yourself and already know what the install workflow looks like;) 2. You are somewhat familiar with (or are willing to learn) system administration and bash programming; 3. You are somewhat familiar with (or are willing to learn) Git; 4. You are comfortable with tinkering and debugging computer stuff in general. :::warning[NOTE ABOUT GENERATIVE AI] It might be tempting to use generative AI, LLMs, to generate app packages. Such "contributions" have systematically brought too verbose code and comments, helpers hallucinations, non-standard directory architectures and files. Reviewing such packages is tiresome for the contributors. It has been decided to reject generated packages that do not follow the `example_ynh` template app. If you still decide to use AI, we highly recommend you to be transparent and responsible about it, and "own" it: you must be able to understand and explain every piece of your code as if you wrote it yourself, you must be able to explain what it does and why you chose to implement it this way. You can't just throw something you don't even understand yourself at other people, and expect them to maintain it for you. ::: Whether or not it is your first contribution, you are encouraged to join the [app packaging chatroom](/community/chat_rooms) to introduce yourself and the app you want to package. Do not hesitate to ask any questions you may have! At some point, you will also want to have a dev/test environment, either using [VirtualBox](/dev/packaging/misc/packaging_apps_virtualbox) or [LXC/ynh-dev](https://github.com/yunohost/ynh-dev) which is meant for the core but can totally be used for developping apps. You can also setup a dev/test VPS on your favourite hosting provider, or even develop on your prod if you like to live dangerously;). ## Notes about the history of YunoHost's app packaging Many things in YunoHost, and YunoHost app packaging format, are historical or were designed in an organic fashion. Thus some aspects may legitimately feel old. The **"v0" of app packaging** consisted in writing raw bash scripts with no real standardization/constrain. Over time, recurrent steps (such as installing dependencies with apt, or setting up the NGINX config) where formalized into standardized bash functions, aka "helpers". This pretty much marked **the beginning of the "v1" packaging era**. Various tools were implemented to test the app and standardize their behavior. After a while, a set of common practices and conventions emerged and is somewhat reflected and maintained in the [`example_ynh`](https://github.com/YunoHost/example_ynh) template application. While it is tempting for dev-oriented folks to change variable naming schemes or refactorize the structure of scripts, it turns out that it is even more important to stick to the common set of practices (even though arbitrary and not elegant) to ease the maintenance of all apps by any member of the packaging community across all repos! Nevertheless, even though helpers existed, the inherent structure of apps was hard and boring to maintain with too many redundant pieces of code or filled with funky historical conventions. **A new v2 format** [has been designed and added to YunoHost 11.1 in early 2023](https://github.com/YunoHost/yunohost/pull/1289) in the hope to modernize and simplify app packaging and improve the UI/UX of YunoHost. However, [**a future v3 format** has yet to come](https://github.com/YunoHost/issues/issues/2136) to further simplify app packaging (such as taking care of NGINX/systemd/... configurations, removing the need to manually write remove/backup/restore scripts, etc.) ================================================ FILE: docs/dev/80.core/05.architecture.mdx ================================================ --- title: YunoHost architecture --- The core of YunoHost is built in Python around the `yunohost` server, but is composed of four main components: ## [Moulinette](https://github.com/YunoHost/moulinette) It is a small "homemade" framework. [Its major role](https://moulinette.readthedocs.io/en/latest/actionsmap.html) is to allow us to build both a web API and a command-line API from the same Python code thanks to a YAML schema which we call [the actionmap](https://github.com/YunoHost/yunohost/blob/dev/share/actionsmap.yml). It handles other mechanisms like authentication, internationalization and small technical utilitary functions (e.g. reading/writing JSON). Moulinette has its own documentation available [here](https://moulinette.readthedocs.io/en/latest/). ## [YunoHost](https://github.com/YunoHost/yunohost) This piece is the very core of YunoHost. It contains: - [The Python code](https://github.com/YunoHost/yunohost/tree/dev/src) that manages users, domains, apps, services and other things - [Bash helpers](https://github.com/YunoHost/yunohost/tree/dev/helpers) mainly used by application packagers to package applications - [Hooks](https://github.com/YunoHost/yunohost/tree/dev/hooks) and [templates](https://github.com/YunoHost/yunohost/tree/dev/conf) that are used to configure the various pieces of the ecosystem such as NGINX, Postfix... - [Internationalized strings](https://github.com/YunoHost/yunohost/tree/dev/locales) - [Tests](https://github.com/YunoHost/yunohost/tree/dev/tests) ## [SSOwat](https://github.com/YunoHost/ssowat) This is the single sign-on backend of YunoHost. It is based on Lua scripts that are directly interfaced with NGINX and handle all the "technical" aspects of authentication and route accesses. SSOwat is configured through `/etc/ssowat/conf.json` which is generated by YunoHost. ## [YunoHost-portal](https://github.com/YunoHost/yunohost-portal) This is the web user portal used to log in and browse installed apps. ## [YunoHost-admin](https://github.com/YunoHost/yunohost-admin) It is an *optional* dependency of YunoHost and corresponds to an interface for the web API created by YunoHost and Moulinette (c.f. the `yunohost-api` service). It essentially contains: - [View templates](https://github.com/YunoHost/yunohost-admin/tree/dev/app/src/views) - Corresponding [JavaScript controllers](https://github.com/YunoHost/yunohost-admin/tree/dev/src/js/yunohost/controllers) that interact with the YunoHost API - [Internationalized strings](https://github.com/YunoHost/yunohost-admin/tree/dev/app/src/i18n/locales) ================================================ FILE: docs/dev/80.core/10.devenv.mdx ================================================ --- title: Development environment --- The recommended development tool is `ynh-dev`, and is based on Incus. This page gives an introduction to both tools. ## Incus The recommended testing and development environment is based on [Incus](https://linuxcontainers.org/incus/), a system container manager. Its usage is very similar to Docker and Podman, but its main difference is its ability to run full operating systems, with their own network interfaces and `init` system. There is no virtualization here. The YunoHost project provides Incus images on [the Incus repository](https://repo.yunohost.org/incus/). For each Debian release and for each branch (`stable`, `testing`, `unstable`) are provided multiple images: * `before-install`: tools and dependencies are installed but *not* Yunohost * `dev`: YunoHost is installed but the post-install step was not run * `appci`: YunoHost is installed, post-install was run and you can install apps * `core-tests`: YunoHost is installed and post-installed, and development and testing tools are installed. The `appci` and `core-tests` images are used by the project's testing infrastructure. The Incus images are built by our [incus_builder](https://github.com/YunoHost/incus_builder/) tool, but **not automatically**, so please feel free to ask us to regenerate images. ### Install and configure Incus Incus can be installed on Debian with: ``` apt install incus ``` Then you need to add users to the `incus-admin` group: ``` sudo usermod -a -G incus-admin $(whoami) newgrp incus-admin ``` and initialize Incus: ``` incus admin init ``` You will want to add the YunoHost repository (do NOT run this as root but as your user): ``` incus remote add yunohost https://repo.yunohost.org/incus --protocol simplestreams --public ``` and to download an image: ``` incus image copy yunohost:yunohost/bookworm-stable/dev local: --copy-aliases --auto-update ``` ## Install a custom YunoHost version When testing an unreleased YunoHost version, or installation script, you might want to run the installation script from [its Git repository](https://github.com/YunoHost/install_script) on a freshly installed Debian. For example to install the unreleased Debian 13 Trixie version: ``` curl https://raw.githubusercontent.com/YunoHost/install_script/main/trixie | bash ``` You might also want to pass arguments to the script: ``` curl https://raw.githubusercontent.com/YunoHost/install_script/main/trixie | bash -s -- -d unstable ``` ## `ynh-dev` [`ynh-dev`](https://github.com/YunoHost/ynh-dev) is the *recommended tool* that automates: * downloading Incus images * download YunoHost's projects source code * Install and symlink YunoHost stuff inside the container That way, you will be able to edit files, test your changes in real time, commit and push/pull your changes directly from your development environment. Please see [the `ynh-dev` README](https://github.com/YunoHost/ynh-dev/?tab=readme-ov-file) for installation and usage instructions. ================================================ FILE: docs/dev/80.core/20.ynh_core.mdx ================================================ --- title: Working on the API and CLI --- When using `ynh-dev`, run in the container: ``` ./ynh-dev use-git yunohost ``` If you work on Moulinette too: ``` ./ynh-dev use-git moulinette ``` ## The actionsmap The actionsmap file (`data/actionsmap/yunohost.yml`) defines the command line *and* the API structure. It is structured as "categories", "actions", and "arguments". For example for the command line `yunohost domain add some.domain.tld`, the category is `domain`, the action is `add`, and `some.domain.tld` is an argument. Moulinette will automatically map commands in the actionsmap to Python functions (and their arguments) located in `src/yunohost/`. For example, typing `yunohost domain add some.domain.tld` will call the function `domain_add(domainName)` in `domain.py`, with the argument `domainName` equal to `"some.domain.tld"`. :::warning Each time you edit the actionsmap or the Python code, you should restart the YunoHost api with: ``` systemctl restart yunohost-api ``` You'll need to retype your admin and password in the web interface. ::: ## Coding style Please follow the standard PEP8 rules, add [Python typing](https://docs.python.org/3/library/typing.html), and run the usual linting tools for Python and Bash. Github Actions will run the linting tools and report errors. ### YunoHost specific rules - To handle exceptions, you should raise some `YunohostError()` - To help with internationalizing the messages, use `m18n.n('some-message-id')` and put your string in `locales/en.json`. You can also put arguments and use them in the string with `{{some-argument:s}}`. Don't edit other locales files, this will be done using [weblate](https://translate.yunohost.org/) ! - Name of "private" functions should start with a `_` ================================================ FILE: docs/dev/80.core/25.ynh_admin.mdx ================================================ --- title: Working on the YunoHost web admin --- When using `ynh-dev`, run in the container: ``` ./ynh-dev use-git yunohost-admin ``` :::danger[FIXME] The rest of this section is completely outdated and should be rewritten from scratch... ::: It launches gulp, such as each time you modify sources, it recompiles the code and you can use it by refreshing (Ctrl+F5) your web administration. To stop the command, just do Ctrl+C. :::warning You might need to force-clear the cache of your browser sometimes to refresh the JavaScript and/or HTML (so each time you edit something in `js` or `views`). ::: The web interface uses the API to interact with YunoHost. The API commands/requests are also defined via the actionsmap. For instance, accessing the page `https://domain.tld/yunohost/api/users` corresponds to a `GET /users` requests on the YunoHost API. It is mapped to the function `user_list()`. Accessing the URL should display the JSON returned by this function. 'GET' requests are typically meant to ask information to the server. 'POST' requests are meant to ask the server to edit/change some information, or to execute some actions. - `js/yunohost/controllers` contains the JavaScript parts, and define which requests to make to the API when loading a specific page of the interface, and how to process the data to generate the page, using templates. - `views` contains the various templates for the pages of the interface. In the template, data coming from the JavaScript part can be used with the syntax `{{some-variable}}`, which will be replaced when building/accessing the page. It is also possible to have conditions using the [handlebars.js](http://handlebarsjs.com) syntax: `{{#if some-variable}}

Some conditional HTML code here !

{{/if}}` - For internationalized strings, use `y18n.t('some-string-code')` in the JavaScript, or `{{t 'some-string-code'}}` in the HTML template, and put your string in `locales/en.json`. Don't edit other locales files, this will be done using [Weblate](https://translate.yunohost.org/)! ================================================ FILE: docs/dev/80.core/forms.mdx ================================================ --- title: Technical details for config panel structure and form option types --- Doc auto-generated by [this script](https://github.com/YunoHost/doc/blob/da78370c098ca04b590e18fb1c8924242367703e/scripts/forms_doc_generate.py) on 09/01/2026 (YunoHost version 12.1.39) ## Glossary You may encounter some named types which are used for simplicity. - `Translation`: a translated property - used for properties: `ask`, `help` and `Pattern.error` - a `dict` with locales as keys and translations as values: ```toml ask.en = "The text in english" ask.fr = "Le texte en français" ``` It is not currently possible for translators to translate those string in weblate. - a single `str` for a single english default string ```toml help = "The text in english" ``` - `JSExpression`: a `str` JS expression to be evaluated to `true` or `false`: - used for properties: `visible` and `enabled` - operators availables: `==`, `!=`, `>`, `>=`, `<`, `<=`, `!`, `&&`, `||`, `+`, `-`, `*`, `/`, `%` and `match()` - `Binding`: bind a value to a file/property/variable/getter/setter/validator - save the value in `settings.yaml` when not defined - nothing at all with `"null"` - a custom getter/setter/validator with `"null"` + a function starting with `get__`, `set__`, `validate__` in `scripts/config` - a variable/property in a file with `:__FINALPATH__/my_file.php` - a whole file with `__FINALPATH__/my_file.php` - `Pattern`: a `dict` with a regex to match the value against and an error message ```toml pattern.regexp = '^[A-F]\d\d$' pattern.error = "Provide a room number such as F12: one uppercase and 2 numbers" # or with translated error pattern.error.en = "Provide a room number such as F12: one uppercase and 2 numbers" pattern.error.fr = "Entrez un numéro de salle comme F12: une lettre majuscule et deux chiffres." ``` - IMPORTANT: your `pattern.regexp` should be between simple quote, not double. ## Configuration panel structure ### ConfigPanel This is the 'root' level of the config panel toml file #### Examples ```toml version = 1.0 [config] # …refer to Panels doc ``` #### Properties - `version`: `float` (default: `1.0`), version that the config panel supports in terms of features. - `i18n` (optional): `str`, an i18n property that let you internationalize options text. - However this feature is only available in core configuration panel (like `yunohost domain config`), prefer the use `Translation` in `name`, `help`, etc. --- ### Panel Panels are, basically, sections grouped together. Panels are `dict`s defined inside a ConfigPanel file and require a unique id (in the below example, the id is `main`). Keep in mind that this id will be used in CLI to refer to the panel, so choose something short and meaningfull. #### Examples ```toml [main] name.en = "Main configuration" name.fr = "Configuration principale" help = "" services = ["__APP__", "nginx"] [main.customization] # …refer to Sections doc ``` #### Properties - `name`: `Translation` or `str`, displayed as the panel title - `help` (optional): `Translation` or `str`, text to display before the first section - `services` (optional): `list` of services names to `reload-or-restart` when any option's value contained in the panel changes - `"__APP__` will refer to the app instance name - `actions`: FIXME not sure what this does --- ### Section Sections are, basically, options grouped together. Sections are `dict`s defined inside a Panel and require a unique id (in the below example, the id is `customization` prepended by the panel's id `main`). Keep in mind that this combined id will be used in CLI to refer to the section, so choose something short and meaningfull. Also make sure to not make a typo in the panel id, which would implicitly create an other entire panel. If at least one `button` is present it then become an action section. Options in action sections are not considered settings and therefor are not saved, they are more like parameters that exists only during the execution of an action. FIXME i'm not sure we have this in code. #### Examples ```toml [main] [main.customization] name.en = "Advanced configuration" name.fr = "Configuration avancée" help = "Every form items in this section are not saved." services = ["__APP__", "nginx"] [main.customization.option_id] type = "string" # …refer to Options doc ``` #### Properties - `name` (optional): `Translation` or `str`, displayed as the section's title if any - `help`: `Translation` or `str`, text to display before the first option - `services` (optional): `list` of services names to `reload-or-restart` when any option's value contained in the section changes - `"__APP__` will refer to the app instance name - `optional`: `bool` (default: `true`), set the default `optional` prop of all Options in the section - `visible`: `bool` or `JSExpression` (default: `true`), allow to conditionally display a section depending on user's answers to previous questions. - Be careful that the `visible` property should only refer to **previous** options's value. Hence, it should not make sense to have a `visible` property on the very first section. --- ## List of all option types ### Common properties Options are fields declaration that renders as form items, button, alert or text in the web-admin and printed or prompted in CLI. They are used in app manifests to declare the before installation form and in config panels. [Have a look at the app config panel doc](/dev/packaging/advanced/config_panels) for details about Panels and Sections. ! IMPORTANT: as for Panels and Sections you have to choose an id, but this one should be unique in all this document, even if the question is in an other panel. #### Example ```toml [section.my_option_id] type = "string" # ask as `str` ask = "The text in english" # ask as `dict` ask.en = "The text in english" ask.fr = "Le texte en français" # advanced props visible = "my_other_option_id != 'success'" readonly = true # much advanced: config panel only? bind = "null" ``` #### Properties - `type`: the actual type of the option, such as 'markdown', 'password', 'number', 'email', ... - `ask`: `Translation` (default to the option's `id` if not defined): - text to display as the option's label for inputs or text to display for readonly options - in config panels, questions are displayed on the left side and therefore have not much space to be rendered. Therefore, it is better to use a short question, and use the `help` property to provide additional details if necessary. - `visible` (optional): `bool` or `JSExpression` (default: `true`) - define if the option is diplayed/asked - if `false` and used alongside `readonly = true`, you get a context only value that can still be used in `JSExpression`s - `readonly` (optional): `bool` (default: `false`, forced to `true` for readonly types): - If `true` for input types: forbid mutation of its value - `bind` (optional): `Binding`, config panels only! A powerful feature that let you configure how and where the setting will be read, validated and written - if not specified, the value will be read/written in the app `settings.yml` - if `"null"`: - the value will not be stored at all (can still be used in context evaluations) - if in `scripts/config` there's a function named: - `get__my_option_id`: the value will be gathered from this custom getter - `set__my_option_id`: the value will be passed to this custom setter where you can do whatever you want with the value - `validate__my_option_id`: the value will be passed to this custom validator before any custom setter - if `bind` is a file path: - if the path starts with `:`, the value be saved as its id's variable/property counterpart - this only works for first level variables/properties and simple types (no array) - else the value will be stored as the whole content of the file - you can use `__FINALPATH__` or `__INSTALL_DIR__` in your path to point to dynamic install paths - FIXME are other global variables accessible? - [refer to `bind` doc for explaination and examples](/dev/packaging/advanced/config_panels#the-bind-statement) --- ### Common inputs properties Rest of the option types available are considered `inputs`. #### Example ```toml [section.my_option_id] type = "string" # …any common props… + optional = false redact = false default = "some default string" help = "You can enter almost anything!" example = "an example string" placeholder = "write something…" ``` #### Properties - [common properties](#common-properties) - `optional`: `bool` (default: `false`, but `true` in config panels) - `redact`: `bool` (default: `false`), to redact the value in the logs when the value contain private information - `default`: depends on `type`, the default value to assign to the option - in case of readonly values, you can use this `default` to assign a value (or return a dynamic `default` from a custom getter) - `help` (optional): `Translation`, to display a short help message in cli and web-admin - `example` (optional): `str`, to display an example value in web-admin only - `placeholder` (optional): `str`, shown in the web-admin fields only --- ### `markdown` (readonly) Display markdown multi-line content. Markdown is currently only rendered in the web-admin #### Example ```toml [section.my_option_id] type = "display_text" ask = "Text **rendered** in markdown." ``` #### Properties - [common properties](#common-properties) --- ### `alert` (readonly) Alerts displays a important message with a level of severity. You can use markdown in `ask` but will only be rendered in the web-admin. #### Example ```toml [section.my_option_id] type = "alert" ask = "The configuration seems to be manually modified..." style = "warning" icon = "warning" ``` #### Properties - [common properties](#common-properties) - `style`: any of `"success|info|warning|danger"` (default: `"info"`) - `icon` (optional): any icon name from [Fork Awesome](https://forkaweso.me/Fork-Awesome/icons/) - Currently only displayed in the web-admin --- ### `button` (readonly) Triggers actions. Available only in config panels. Renders as a `button` in the web-admin and can be called with `yunohost [app|domain|settings] action run ` in CLI. Every options defined in an action section (a config panel section with at least one `button`) is guaranted to be shown/asked to the user and available in `scripts/config`'s scope. [check examples in advanced use cases](/dev/packaging/advanced/config_panels#actions). #### Example ```toml [section.my_option_id] type = "button" ask = "Break the system" style = "danger" icon = "bug" # enabled only if another option's value (a `boolean` for example) is positive enabled = "aknowledged" ``` To be able to trigger an action we have to add a bash function starting with `run__` in your `scripts/config` ```bash run__my_action_id() { ynh_print_info "Running 'my_action_id' action" } ``` #### Properties - [common properties](#common-properties) - `bind`: forced to `"null"` - `style`: any of `"success|info|warning|danger"` (default: `"success"`) - `enabled`: `JSExpression` or `bool` (default: `true`) - when used with `JSExpression` you can enable/disable the button depending on context - `icon` (optional): any icon name from [Fork Awesome](https://forkaweso.me/Fork-Awesome/icons/) - Currently only displayed in the web-admin --- ### `string` (string) Ask for a simple string. #### Example ```toml [section.my_option_id] type = "string" default = "E10" pattern.regexp = '^[A-F]\d\d$' pattern.error = "Provide a room like F12 : one uppercase and 2 numbers" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: `""` - `pattern` (optional): `Pattern`, a regex to match the value against --- ### `text` (string) Ask for a multiline string. Renders as a `textarea` in the web-admin and by opening a text editor on the CLI. #### Example ```toml [section.my_option_id] type = "text" default = "multi\nline\ncontent" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: `""` - `pattern` (optional): `Pattern`, a regex to match the value against --- ### `password` (input) Ask for a password. The password is tested as a regular user password (at least 8 chars) #### Example ```toml [section.my_option_id] type = "password" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: forced to `""` - `redact`: forced to `true` - `example`: forbidden --- ### `color` (input) Ask for a color represented as a hex value (with possibly an alpha channel). Renders as color picker in the web-admin and as a prompt that accept named color like `yellow` in CLI. #### Example ```toml [section.my_option_id] type = "color" default = "#ff0" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: `""` --- ### `number` (input) Ask for a number (an integer). #### Example ```toml [section.my_option_id] type = "number" default = 100 min = 50 max = 200 step = 5 ``` #### Properties - [common inputs properties](#common-inputs-properties) - `type`: `number` or `range` (input or slider in the web-admin) - `min` (optional): minimal int value inclusive - `max` (optional): maximal int value inclusive - `step` (optional): currently only used in the webadmin as the `` step jump --- ### `boolean` (input) Ask for a boolean. Renders as a switch in the web-admin and a yes/no prompt in CLI. #### Example ```toml [section.my_option_id] type = "boolean" default = 1 yes = "agree" no = "disagree" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: `0` - `yes` (optional): (default: `1`) define as what the thruthy value should output - can be `true`, `True`, `"yes"`, etc. - `no` (optional): (default: `0`) define as what the thruthy value should output - can be `0`, `"false"`, `"n"`, etc. --- ### `date` (input) Ask for a date in the form `"2025-06-14"`. Renders as a date-picker in the web-admin and a regular prompt in CLI. Can also take a timestamp as value that will output as an ISO date string. #### Example ```toml [section.my_option_id] type = "date" default = "2070-12-31" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: `""` --- ### `time` (input) Ask for an hour in the form `"22:35"`. Renders as a date-picker in the web-admin and a regular prompt in CLI. #### Example ```toml [section.my_option_id] type = "time" default = "12:26" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: `""` --- ### `email` (input) Ask for an email. Validation made with [python-email-validator](https://github.com/JoshData/python-email-validator) #### Example ```toml [section.my_option_id] type = "email" default = "Abc.123@test-example.com" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: `""` --- ### `path` (string) Ask for an web path (the part of an url after the domain). Used by default in app install to define from where the app will be accessible. #### Example ```toml [section.my_option_id] type = "path" default = "/" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: `""` - `pattern` (optional): `Pattern`, a regex to match the value against --- ### `url` (string) Ask for any url. #### Example ```toml [section.my_option_id] type = "url" default = "https://example.xn--zfr164b/@handle/" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: `""` - `pattern` (optional): `Pattern`, a regex to match the value against --- ### `file` (input) Ask for file. Renders a file prompt in the web-admin and ask for a path in CLI. #### Example ```toml [section.my_option_id] type = "file" accept = ".json" # bind the file to a location to save the file there bind = "/tmp/my_file.json" ``` #### Properties - [common inputs properties](#common-inputs-properties) - `default`: `""` - `accept`: a comma separated list of extension to accept like `".conf, .ini` - /!\ currently only work on the web-admin --- ### `select` (choices) Ask for value from a limited set of values. Renders as a regular `