diff --git a/roles/syncthing/README.md b/roles/syncthing/README.md new file mode 100644 index 0000000..b85b7ed --- /dev/null +++ b/roles/syncthing/README.md @@ -0,0 +1,48 @@ +# syncthing + +Installs and configures [Syncthing](https://syncthing.net/) as a system service. +Runs as a dedicated `syncthing` system user via `syncthing@syncthing.service`. + +Supports Arch Linux and Debian-based distributions. + +## Required variables + +Set these in `inventory/host_vars/.yml`: + +```yaml +syncthing_gui_user: admin +syncthing_gui_password: "{{ vault_syncthing_gui_password }}" +``` + +`syncthing_gui_password` must be at least 12 characters. Set the actual value +in your vault file and reference it via `vault_syncthing_gui_password`. +Syncthing will bcrypt-hash the password on first start. + +## Optional variables + +See `defaults/main.yml` for the full list. Key options: + +| Variable | Default | Description | +|-----------------------------|--------------------------------|------------------------------------| +| `syncthing_user` | `syncthing` | OS user to run syncthing as | +| `syncthing_home` | `/var/lib/syncthing` | Home directory for the system user | +| `syncthing_config_dir` | `{{ syncthing_home }}/.config/syncthing` | Config directory | +| `syncthing_gui_bind` | `0.0.0.0` | GUI listen address | +| `syncthing_gui_port` | `8384` | GUI listen port | +| `syncthing_port` | `22000` | Sync protocol port (TCP) | +| `syncthing_allowed_networks` | `[]` | UFW rules for GUI and sync ports | + +## Notes + +- `config.xml` is written only on first run — the task is skipped on subsequent + runs if the file already exists. Syncthing manages the file after that (device + ID, folder config, hashed password). Re-running the playbook is safe. +- Folder and device pairing must be done via the Syncthing web UI or REST API + after the service is running. +- The GUI binds to `0.0.0.0` by default — use `syncthing_allowed_networks` to + restrict access via UFW to specific LAN/VPN ranges. + +## Debian notes + +The `syncthing` package in some Debian versions may be outdated. Consider adding +the [official APT repository](https://apt.syncthing.net/) before applying this role. diff --git a/roles/syncthing/defaults/main.yml b/roles/syncthing/defaults/main.yml new file mode 100644 index 0000000..24da534 --- /dev/null +++ b/roles/syncthing/defaults/main.yml @@ -0,0 +1,27 @@ +--- +# System user to run syncthing as +syncthing_user: syncthing +syncthing_group: syncthing +syncthing_home: /var/lib/syncthing + +# Config directory (syncthing reads and writes this at runtime) +syncthing_config_dir: "{{ syncthing_home }}/.config/syncthing" + +# GUI credentials (REQUIRED - must be set explicitly) +# syncthing_gui_user: "" # Intentionally undefined - role will fail if not set +# syncthing_gui_password: "" # Intentionally undefined - role will fail if not set + +# GUI listen address and port +syncthing_gui_bind: "0.0.0.0" +syncthing_gui_port: 8384 + +# Sync protocol port (TCP) +syncthing_port: 22000 + +# Package and service names +syncthing_package: syncthing +syncthing_service: "syncthing@{{ syncthing_user }}" + +# Firewall rules - list of allowed source ranges for GUI and sync ports +syncthing_allowed_networks: + - { src: "127.0.0.1/8", comment: "Localhost" } diff --git a/roles/syncthing/handlers/main.yml b/roles/syncthing/handlers/main.yml new file mode 100644 index 0000000..004e168 --- /dev/null +++ b/roles/syncthing/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Restart syncthing + ansible.builtin.systemd: + name: "{{ syncthing_service }}" + state: restarted diff --git a/roles/syncthing/tasks/main.yml b/roles/syncthing/tasks/main.yml new file mode 100644 index 0000000..1274bcf --- /dev/null +++ b/roles/syncthing/tasks/main.yml @@ -0,0 +1,81 @@ +--- +- name: Validate required variables are set + ansible.builtin.assert: + that: + - syncthing_gui_user is defined + - syncthing_gui_user | length >= 1 + - syncthing_gui_password is defined + - syncthing_gui_password | length >= 12 + fail_msg: | + syncthing_gui_user and syncthing_gui_password are required. + syncthing_gui_password must be at least 12 characters. + See roles/syncthing/defaults/main.yml for configuration instructions. + +- name: Install syncthing + ansible.builtin.package: + name: "{{ syncthing_package }}" + state: present + +- name: Create syncthing system group + ansible.builtin.group: + name: "{{ syncthing_group }}" + system: true + state: present + +- name: Create syncthing system user + ansible.builtin.user: + name: "{{ syncthing_user }}" + group: "{{ syncthing_group }}" + home: "{{ syncthing_home }}" + shell: /sbin/nologin + system: true + create_home: true + state: present + +- name: Create syncthing config directory + ansible.builtin.file: + path: "{{ syncthing_config_dir }}" + state: directory + owner: "{{ syncthing_user }}" + group: "{{ syncthing_group }}" + mode: "0700" + +- name: Check if syncthing config already exists + ansible.builtin.stat: + path: "{{ syncthing_config_dir }}/config.xml" + register: syncthing_config_stat + +- name: Deploy initial syncthing config (skipped if already exists) + ansible.builtin.template: + src: config.xml.j2 + dest: "{{ syncthing_config_dir }}/config.xml" + owner: "{{ syncthing_user }}" + group: "{{ syncthing_group }}" + mode: "0600" + when: not syncthing_config_stat.stat.exists + notify: Restart syncthing + +- name: Allow syncthing GUI and sync traffic through firewall + community.general.ufw: + rule: allow + port: "{{ item.1.port }}" + proto: tcp + from: "{{ item.0.src }}" + direction: in + comment: "{{ item.0.comment }}" + loop: "{{ syncthing_allowed_networks | product(syncthing_ufw_ports) | list }}" + vars: + syncthing_ufw_ports: + - { port: "{{ syncthing_gui_port }}" } + - { port: "{{ syncthing_port }}" } + when: syncthing_allowed_networks | length > 0 + retries: 5 + delay: 2 + register: ufw_result + until: ufw_result is succeeded + +- name: Enable and start syncthing service + ansible.builtin.systemd: + name: "{{ syncthing_service }}" + enabled: true + state: started diff --git a/roles/syncthing/templates/config.xml.j2 b/roles/syncthing/templates/config.xml.j2 new file mode 100644 index 0000000..1611dfa --- /dev/null +++ b/roles/syncthing/templates/config.xml.j2 @@ -0,0 +1,21 @@ + + + + + +
{{ syncthing_gui_bind }}:{{ syncthing_gui_port }}
+ {{ syncthing_gui_user }} + + {{ syncthing_gui_password }} + default + false +
+ + false + false + + -1 + + 0 + +