-->
ラベル alfresco の投稿を表示しています。 すべての投稿を表示
ラベル alfresco の投稿を表示しています。 すべての投稿を表示

2026年6月11日木曜日

alfresco community 7.4→alfresco26.xへの移行(ansibleインストール)

⛔ 移行元:Ubuntu 22 + Alfresco 7.4 ✅ 移行先:Ubuntu 24 + Alfresco 26.x
🔄
本記事について
従来の移行手順(Samba共有フォルダ経由)をrsync over SSHに置き換えています。 WindowsホストでLinuxパーティションを読む際の日本語ファイル名の文字化けを回避し、VM間で直接転送します。

1 概要・注意事項

項目移行元VM移行先VM
OSUbuntu 22.04 ServerUbuntu 24.04 Server
AlfrescoCommunity 7.4Community 26.x
インストール方法Alfresco公式Ansibleロール
仮想化基盤Hyper-V / Windows Server 2016
データベースPostgreSQL
検索サービスSolr(Community版)
⚠️
ACS 7.4 はサポート終了(End-of-Life)
2026年6月、Alfresco公式Ansibleロールリポジトリにて ACS 7.4 のサポートが正式に削除されました (PR #1407 "Remove ACS 7.4 support and test coverage")。 移行元として 7.4 を使用している場合は、早期に新バージョンへの移行を検討してください。
⚠️
Windows経由のファイルコピーは避ける
WindowsホストでLinux(ext4)パーティションを読むと日本語ファイル名が文字化けします。必ずLinux同士(rsync/SSH)で転送してください。

2 移行先VMにAlfresco 26.x をインストール

Ubuntu 24.04 ServerにAlfresco公式Ansibleロールで新規インストールします。

リポジトリ取得・Python環境構築

移行先VM
# 公式Ansibleロールをクローン
git clone https://github.com/Alfresco/alfresco-ansible-deployment.git
cd alfresco-ansible-deployment

# Python仮想環境を構築
sudo apt install pipenv python3-venv
python3.12 -m venv venv
source venv/bin/activate

# Ansibleの依存関係をインストール
pip3 install pipenv
python3.12 -m pipenv install --deploy
python3.12 -m pipenv run ansible-galaxy install -r requirements.yml

アクセスURLの設定

アクセスする可能性のあるURLを全て指定します。誤るとファイル操作等ができなくなります。

移行先VM
sudo vi playbooks/group_vars/all.yml
playbooks/group_vars/all.yml
acs_play_known_urls: [
  http://サーバーのIPアドレス:8080/share,
  https://サーバーのIPアドレス:8080/share,
  https://ドメイン名/share
]
acs_play_major_version: 26

Community版向けに検索サービスを設定

初期設定はEnterprise版の検索サービスが選択されているため、Solrに切り替えます。

移行先VM
sudo vi inventory_local.yml
inventory_local.yml(変更箇所)
# Solrを有効化(コメントを解除)
search:
  children:
    repository:        # ← コメント解除

# Enterprise Searchを無効化(コメントアウト)
search_enterprise:
  children:
    # repository:      # ← コメントアウト
elasticsearch:
  children:
    # repository:      # ← コメントアウト

Vaultパスワード生成・インストール実行

移行先VM
# Vaultパスワードを生成
openssl rand -base64 21 > ~/.vault_pass.txt
export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass.txt

# シークレットを自動生成
pipenv run ansible-playbook \
  -e vault_init=encrypted_file playbooks/secrets-init.yml

# インストール実行(Community版として指定)
pipenv run ansible-playbook playbooks/acs.yml \
  -i inventory_local.yml \
  -e "acs_play_repository_acs_edition=Community"

3 データ転送の事前準備

🔄
従来手順との変更点
従来のSamba共有フォルダ(/mnt/smb)経由の転送をrsync over SSHに変更しています。Sambaのセットアップが不要になり、日本語ファイル名の文字化けも回避できます。

移行先VM:SSH サーバーの確認

移行先VM
sudo systemctl status ssh
# 起動していない場合
sudo apt install openssh-server
sudo systemctl enable --now ssh

移行先VM:一時受け取りディレクトリの作成

Alfrescoの管理ディレクトリに直接転送すると権限エラーが発生しやすいため、ホームディレクトリ配下の一時ディレクトリに受け取ります。

移行先VM
mkdir -p ~/alfresco_restore/content
mkdir -p ~/alfresco_restore/search-services
mkdir -p ~/alfresco_restore/search-services-config
mkdir -p ~/alfresco_restore/extension
mkdir -p ~/alfresco_restore/web-extension
mkdir -p ~/alfresco_restore/messages

移行元VM:Alfrescoの停止

移行元VM
sudo systemctl stop alfresco-content.service
sudo systemctl stop alfresco-search.service
# 停止確認
sudo systemctl status alfresco-content.service
# → inactive (dead) になればOK

screenでセッションを保持する

転送に時間がかかるため、端末を閉じてもサーバー上で継続できるよう screen を使用します。

移行元VM
# screenセッション開始
screen -S alfresco_migrate

# デタッチ(セッションを維持したまま端末を閉じる)
# Ctrl + A → D

# 後で再接続
screen -r alfresco_migrate

4 移行元からデータ転送(rsync)変更

以下のコマンドはすべて移行元VM上で実行します。--omit-dir-timesオプションでディレクトリのタイムスタンプ変更エラーを回避します。rsyncは差分転送のため、中断後に再実行しても続きから再開されます。

コンテンツストア

移行元VM
sudo rsync -avz --progress --omit-dir-times \
  /var/opt/alfresco/content-services/content/ \
  ユーザー名@移行先VMのIPアドレス:~/alfresco_restore/content/

Solrインデックス・バックアップ

移行元VM
sudo rsync -avz --progress --omit-dir-times \
  /var/opt/alfresco/search-services/ \
  ユーザー名@移行先VMのIPアドレス:~/alfresco_restore/search-services/

Solrモデル・設定

移行元VM
sudo rsync -avz --progress --omit-dir-times \
  /etc/opt/alfresco/search-services/ \
  ユーザー名@移行先VMのIPアドレス:~/alfresco_restore/search-services-config/

カスタマイズ設定(カスタムモデルがある場合)

移行元VM
sudo rsync -avz --progress --omit-dir-times \
  /etc/opt/alfresco/content-services/classpath/alfresco/extension/ \
  ユーザー名@移行先VMのIPアドレス:~/alfresco_restore/extension/

sudo rsync -avz --progress --omit-dir-times \
  /etc/opt/alfresco/content-services/classpath/alfresco/web-extension/ \
  ユーザー名@移行先VMのIPアドレス:~/alfresco_restore/web-extension/

sudo rsync -avz --progress --omit-dir-times \
  /etc/opt/alfresco/content-services/classpath/alfresco/messages/ \
  ユーザー名@移行先VMのIPアドレス:~/alfresco_restore/messages/

データベースダンプ

移行元VM
# ダンプ作成
  su -
  su - postgres
  pg_dumpall > /tmp/alfresco_dump
  exit

# 移行先VMへ転送
scp /tmp/alfresco_dump \
  ユーザー名@移行先VMのIPアドレス:/tmp/

5 移行先へデータを適用

移行先VMで一時ディレクトリから正式パスへ移動します。

Alfrescoを停止

移行先VM
sudo systemctl stop alfresco-content.service
sudo systemctl stop alfresco-search.service

コンテンツストアの差替

移行先VM
# 既存コンテンツを削除
sudo rm -rf /var/opt/alfresco/content-services/content/contentstore
sudo rm -rf /var/opt/alfresco/content-services/content/contentstore.deleted

# 移行データをコピー
sudo cp -a ~/alfresco_restore/content/contentstore \
  /var/opt/alfresco/content-services/content/
sudo cp -a ~/alfresco_restore/content/contentstore.deleted \
  /var/opt/alfresco/content-services/content/

Solrデータの差替

移行先VM
# 既存Solrインデックスを削除
sudo rm -rf /var/opt/alfresco/search-services/alfresco/index
sudo rm -rf /var/opt/alfresco/search-services/archive/index
sudo rm -rf /etc/opt/alfresco/search-services/solrhome/alfrescoModels

# 移行データをコピー
sudo cp -a ~/alfresco_restore/search-services/alfresco/index \
  /var/opt/alfresco/search-services/alfresco/
sudo cp -a ~/alfresco_restore/search-services/archive/index \
  /var/opt/alfresco/search-services/archive/
sudo cp -a ~/alfresco_restore/search-services-config/solrhome/alfrescoModels \
  /etc/opt/alfresco/search-services/solrhome/

権限を修正

移行先VM
sudo chown -hR alfresco:alfresco /var/opt/alfresco/content-services/content/
sudo chown -hR alfresco:alfresco /var/opt/alfresco/search-services/
sudo chown -hR alfresco:alfresco /etc/opt/alfresco/search-services/solrhome/

一時移行データの削除

正式パスへのコピーが完了し、Alfrescoが正常に起動・動作することを確認してから削除します。本番稼働確認後2〜4週間を目安に保持し、問題がなければ削除してください。

確認項目確認方法
Alfrescoへのログインブラウザから http://移行先IP:8080/share にアクセス
過去データの閲覧移行前のメール・ドキュメントが参照できること
新着メールの取り込みgetmailが正常に動作していること
検索の動作Solrインデックスが有効なこと
数日間の本番運用問題が出ないことを確認
移行先VM(本番稼働確認後に実行)
# 一時ディレクトリの容量を確認
du -sh ~/alfresco_restore/

# 一時移行データを削除
rm -rf ~/alfresco_restore/
ℹ️
移行元VMはそのまま保持する
移行先の本番稼働が安定するまで、移行元VM(旧サーバー)は停止したまま保持することを推奨します。万一の際にDBダンプや旧コンテンツストアを参照・復元できる状態を維持するためです。移行元VMの廃棄は、移行先が長期間安定稼働したことを確認してから判断してください。

6 データベースの移行

移行先VM
# PostgreSQLでDBを再作成
su -
su - postgres
psql
drop database alfresco ;
create database alfresco ;
\q

# ダンプをリストア
psql -f /tmp/alfresco_dump
exit

PostgreSQLパスワードの確認・設定

alfresco-global.propertiesdb.password とPostgreSQLの alfresco ユーザーのパスワードを一致させます。

移行先VM
# 設定ファイルのパスワードを確認
sudo grep "db.password" \
  /etc/opt/alfresco/content-services/classpath/alfresco-global.properties

# PostgreSQLのパスワードを設定ファイルに合わせる
su -
su - postgres
psql
ALTER USER alfresco WITH PASSWORD '設定ファイルのdb.password';
\q
⚠️
パスワードが一致しないとAlfresco起動時に FATAL: password authentication failed for user "alfresco" エラーが発生します。
ℹ️
DBダンプファイルの削除
/tmp/alfresco_dump は本番稼働確認後に削除してください。削除前に容量を確認しておくと安心です。
du -sh /tmp/alfresco_dump && rm -f /tmp/alfresco_dump

7 カスタマイズ設定の移行

⚠️
カスタムモデルを移行しないと404エラーが発生します
custom-model-context.xml と モデル定義XML(customModel.xml 等)の両方を配置してください。
移行先VM
# カスタムモデルを配置
sudo cp -a ~/alfresco_restore/extension/. \
  /etc/opt/alfresco/content-services/classpath/alfresco/extension/

# Share設定を配置
sudo cp -a ~/alfresco_restore/web-extension/. \
  /etc/opt/alfresco/content-services/classpath/alfresco/web-extension/

# メッセージファイルを配置
sudo cp -a ~/alfresco_restore/messages/. \
  /etc/opt/alfresco/content-services/classpath/alfresco/messages/

# 権限を修正
sudo chown -R alfresco:alfresco \
  /etc/opt/alfresco/content-services/classpath/alfresco/extension
sudo chown -R alfresco:alfresco \
  /etc/opt/alfresco/content-services/classpath/alfresco/web-extension
sudo chown -R alfresco:alfresco \
  /etc/opt/alfresco/content-services/classpath/alfresco/messages

配置確認

移行先VM
ls /etc/opt/alfresco/content-services/classpath/alfresco/extension/
# custom-model-context.xml と customModel.xml 等が存在すること

8 Alfresco起動・確認

移行先VM
sudo systemctl start alfresco-content.service
sudo systemctl start alfresco-search.service

# ログで起動確認
tail -f /var/log/alfresco/catalina.out
起動成功の確認ポイント
catalina.outに Alfresco started が出力され、ブラウザから http://移行先VMのIP:8080/alfresco にアクセスできれば移行完了です。

移行元VMのAlfresco再起動(本番継続)

移行元VM
sudo systemctl start alfresco-content.service
sudo systemctl start alfresco-search.service

9 サーバー移行後の WebDAV URL 修正

サーバー移行後、Share の「共有」パネルに表示される WebDAV URL が旧サーバーの IP アドレスのままになる場合があります。

ファイル修正箇所
alfresco-global.properties alfresco.host が空欄または旧 IP になっている
share-config-custom.xml <repository-url> が旧 IP になっている
share-config-custom.xml CSRFPolicy の <referer><origin> が旧 IP になっている

① alfresco-global.properties の修正

alfresco.host が空欄の場合、WebDAV URL の生成時にデフォルト値として旧 IP が使われることがあります。

移行先VM
sudo grep -E "alfresco.host|alfresco.port|alfresco.protocol" \
  /etc/alfresco/alfresco-global.properties

以下のように新サーバーの IP・ポートを明示してください。

/etc/alfresco/alfresco-global.properties(変更箇所)
alfresco.host=新サーバーの IP アドレス
alfresco.port=8080
alfresco.protocol=http

② share-config-custom.xml の修正

WebDAV URL の表示元となる <repository-url> と、CSRF フィルターの <referer><origin> に旧 IP が残っていないか確認します。

移行先VM
# 旧 IP が残っているか確認
sudo grep "旧サーバーの IP アドレス" \
  /etc/opt/alfresco/content-services/classpath/alfresco/web-extension/share-config-custom.xml

旧 IP が検出された場合は sed で一括置換します。

移行先VM
# repository-url のポートが異なる場合は個別に置換
sudo sed -i \
  's|http://旧IP:80/alfresco|http://新IP:8080/alfresco|g' \
  /etc/opt/alfresco/content-services/classpath/alfresco/web-extension/share-config-custom.xml

# referer / origin の旧 IP を一括置換
sudo sed -i \
  's|http://旧IP:8080|http://新IP:8080|g' \
  /etc/opt/alfresco/content-services/classpath/alfresco/web-extension/share-config-custom.xml

# 置換後の確認(何も表示されなければ OK)
sudo grep "旧IP" \
  /etc/opt/alfresco/content-services/classpath/alfresco/web-extension/share-config-custom.xml
⚠️
<repository-url> のポート番号に注意
alfresco-global.propertiesalfresco.port=80 のままだった場合、<repository-url> には :80 で記録されていることがあります。sed で置換する際はポート番号まで含めて指定してください。

③ Alfresco を再起動して確認

移行先VM
sudo systemctl restart alfresco

# 起動ログを確認
tail -f /var/log/alfresco/catalina.out

Share にログイン後、任意のフォルダ詳細画面の「共有」パネルを開き、WebDAV URL が新サーバーの IP アドレスになっていれば修正完了です。

確認ポイント
「共有」パネルの WebDAV URLhttp://新IP:8080/alfresco/webdav/... と表示されれば正常です。

10 日本語対応(プレビューフォント・LibreOffice)

Alfresco 26.x + Ubuntu 24.04 環境では、Word・Excel のプレビューで日本語が表示されない場合があります。Transform Service(alfresco-tengine-aio)が内部で使用する LibreOffice に日本語フォントを追加することで解決できます。

ℹ️
Transform Service が使用する LibreOffice のパスは systemctl cat alfresco-tengine-aio-DLIBREOFFICE_HOME= で確認できます。本手順では /opt/libreoffice7.2/ を前提としています。

① 日本語フォントのインストール

移行先VM
sudo apt install fonts-noto-cjk -y

② LibreOffice のフォントディレクトリに CJK フォントをコピー

移行先VM
sudo cp /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc \
  /opt/libreoffice7.2/share/fonts/truetype/
sudo cp /usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc \
  /opt/libreoffice7.2/share/fonts/truetype/
sudo cp /usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc \
  /opt/libreoffice7.2/share/fonts/truetype/
sudo fc-cache -fv /opt/libreoffice7.2/share/fonts/

③ フォント代替設定(fc_local.conf)

Word 文書で使われる游明朝・游ゴシック等を Noto フォントに代替させます。/opt/libreoffice7.2/share/fonts/truetype/fc_local.conf</fontconfig> 直前に以下を追加します。

/opt/libreoffice7.2/share/fonts/truetype/fc_local.conf(追加箇所)
        <!-- Japanese font aliases -->
        <alias binding="same">
          <family>游明朝</family>
          <accept><family>Noto Serif CJK JP</family></accept>
        </alias>
        <alias binding="same">
          <family>Yu Mincho</family>
          <accept><family>Noto Serif CJK JP</family></accept>
        </alias>
        <alias binding="same">
          <family>游ゴシック</family>
          <accept><family>Noto Sans CJK JP</family></accept>
        </alias>
        <alias binding="same">
          <family>Yu Gothic</family>
          <accept><family>Noto Sans CJK JP</family></accept>
        </alias>
        <alias binding="same">
          <family>Meiryo</family>
          <accept><family>Noto Sans CJK JP</family></accept>
        </alias>
        <alias binding="same">
          <family>MS Gothic</family>
          <accept><family>Noto Sans CJK JP</family></accept>
        </alias>
        <alias binding="same">
          <family>MS Mincho</family>
          <accept><family>Noto Serif CJK JP</family></accept>
        </alias>

④ Java fallback フォントの設定

Transform Service は Java 21 で動作しています。Java 側にも fallback フォントを追加します。

移行先VM
sudo mkdir -p /opt/openjdk-21.0.9/lib/fonts/fallback
sudo ln -sf /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc \
  /opt/openjdk-21.0.9/lib/fonts/fallback/
sudo ln -sf /usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc \
  /opt/openjdk-21.0.9/lib/fonts/fallback/

⑤ LibreOffice の registry に CJK フォント代替を登録

移行先VM
sudo tee /opt/libreoffice7.2/share/registry/cjk-fonts.xcu << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<oor:component-data xmlns:oor="http://openoffice.org/2001/registry"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  oor:name="VCL" oor:package="org.openoffice.VCL">
  <node oor:name="Fonts">
    <node oor:name="FontSubstitutions">
      <node oor:name="MS Gothic" oor:op="replace">
        <prop oor:name="ReplacementFont"><value>Noto Sans CJK JP</value></prop>
      </node>
      <node oor:name="MS Mincho" oor:op="replace">
        <prop oor:name="ReplacementFont"><value>Noto Serif CJK JP</value></prop>
      </node>
      <node oor:name="Yu Gothic" oor:op="replace">
        <prop oor:name="ReplacementFont"><value>Noto Sans CJK JP</value></prop>
      </node>
      <node oor:name="Yu Mincho" oor:op="replace">
        <prop oor:name="ReplacementFont"><value>Noto Serif CJK JP</value></prop>
      </node>
      <node oor:name="Meiryo" oor:op="replace">
        <prop oor:name="ReplacementFont"><value>Noto Sans CJK JP</value></prop>
      </node>
    </node>
  </node>
</oor:component-data>
EOF

⑥ サービス再起動

移行先VM
sudo systemctl stop alfresco-tengine-aio
sudo pkill -u alfresco -f soffice.bin 2>/dev/null || true
sudo systemctl start alfresco-tengine-aio
sudo systemctl restart alfresco-content.service
再起動後に Word 文書をAlfrescoにアップロードしてプレビューを確認してください。既存ファイルで文字化けが残る場合はブラウザキャッシュをクリア(Ctrl+Shift+Delete)した後に再確認してください。それでも表示されない場合は rendition を削除して再生成します。

rendition の削除と再生成(既存ファイルの文字化け対処)

移行先VM
# ノードIDを指定してrenditionを削除
source /etc/alfresco/credentials
FILE_NODE="ノードID"

curl -s -u "$ALFRESCO_USER:$ALFRESCO_PASS" -X DELETE \
  "$ALFRESCO_HOST/alfresco/api/-default-/public/alfresco/versions/1/nodes/$FILE_NODE/renditions/doclib"

# doclib renditionを再生成
curl -s -u "$ALFRESCO_USER:$ALFRESCO_PASS" -X POST \
  -H "Content-Type: application/json" \
  "$ALFRESCO_HOST/alfresco/api/-default-/public/alfresco/versions/1/nodes/$FILE_NODE/renditions" \
  -d '{"id":"doclib"}'
⚠️
pdf rendition は REST API の DELETE で削除されない場合があります。その場合は PostgreSQL で直接ノードを特定して削除してください。
SELECT child.uuid FROM alf_node parent JOIN alf_child_assoc ca ON parent.id = ca.parent_node_id JOIN alf_node child ON ca.child_node_id = child.id JOIN alf_node_properties p ON child.id = p.node_id JOIN alf_qname q ON p.qname_id = q.id WHERE parent.uuid = 'ファイルのノードID' AND q.local_name = 'name' AND p.string_value = 'pdf';

11 トラブルシューティング

カスタムモデルで404エラーが発生する

💡
custom-model-context.xml と モデル定義XML の両方が /etc/opt/alfresco/content-services/classpath/alfresco/extension/ に存在するか確認してください。片方だけでは動作しません。

DB認証エラーで起動失敗する

エラーログ
FATAL: password authentication failed for user "alfresco"
💡
alfresco-global.propertiesdb.password を確認し、PostgreSQLの alfresco ユーザーのパスワードと一致させてください。

rsync転送時にPermission deniedが発生する

💡
転送先の親ディレクトリまで含めて alfresco:alfresco 所有・パーミッション 750 になっていないか確認してください。一時ディレクトリ(~/alfresco_restore/)に転送してから移動する方法が安全です。

No space left on deviceが発生する

💡
LVMを使用している場合は lvextend + resize2fs でディスクを拡張してください。Solrインデックスは省略してAlfresco起動後に管理コンソールから再インデックスを実行する方法も有効です。

それでも起動・ログインできない場合(Ansibleで再インストール)

移行先VM
# vars/secrets.ymlを初期化
sudo vi vars/secrets.yml
# → 記載内容を全て削除して保存

# アンインストール
pipenv run ansible-playbook \
  playbooks/platform-cleanup.yml -i inventory_local.yml

# Vaultパスワード再作成
openssl rand -base64 21 > ~/.vault_pass.txt
export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass.txt
pipenv run ansible-playbook \
  -e vault_init=encrypted_file playbooks/secrets-init.yml

# 再インストール
pipenv run ansible-playbook playbooks/acs.yml \
  -i inventory_local.yml \
  -e "acs_play_repository_acs_edition=Community"

2026年5月18日月曜日

alfresco26.x メール取り込み設定(スパム対策あり)

1. システム構成の概要

メールサーバーから自動受信したメールをSpamAssassinでフィルタリングし、Alfrescoに取り込む構成です。

📬 メールサーバー (POP3S)
getmail
spamc-wrapper.sh
SpamAssassin
postfix
🗂 Alfresco
コンポーネント役割備考
getmail 6.xPOP3S でメール取得cron で5分毎に実行
SpamAssassin 4.0スパム判定・件名に ***SPAM*** 追加スコア7以上は破棄
postfix 3.8Alfresco への配送・遅延制御5秒/通の遅延設定
Alfresco 26.1メール格納・振り分けCommunity版 Ansible インストール
ℹ️ Alfresco Community版はSMTPの細かい制御ができないため、postfixで遅延処理を行い配送エラーを防止しています。

2. Alfresco 事前設定(alfresco-global.properties)

Alfresco のメール受信機能を有効にするため、設定ファイルにメール関連プロパティを追加します。

① サンプルファイルから設定を確認

terminal
$ vi /etc/opt/alfresco/content-services/classpath/alfresco-global.properties.sample

② alfresco-global.properties に追記

terminal
$ sudo vi /etc/opt/alfresco/content-services/classpath/alfresco-global.properties

ファイル末尾の ### Begin - Custom user properties - ANSIBLE MANAGED BLOCK セクションに追記します。

alfresco-global.properties(追記内容)
# Enable/Disable the inbound email service.
email.inbound.enabled=true
# Email Server properties
email.server.enabled=true
email.server.port=1025 # 25はpostfixと干渉するため変更
email.server.domain=alfresco.example.com
email.inbound.unknownUser=admin
alfresco.host=サーバーのIPアドレス # 空欄だとWebDAV URLが旧IPで表示される
alfresco.port=8080
alfresco.protocol=http
⚠️ email.server.port=25 はpostfixが使用しているため、1025など別のポートに変更してください。alfresco.host を空欄にすると Share の WebDAV URL 表示で旧サーバーの IP が使われることがあります。必ず設定してください。

③ Alfrescoサービスを再起動

terminal
$ sudo systemctl restart alfresco-content.service

3. Postfix のインストールと設定

インストール

terminal
$sudo apt install postfix -y
$sudo systemctl enable --now postfix

/etc/postfix/main.cf の設定

/etc/postfix/main.cf
myhostname = alfresco.example.com
mydomain = example.com
inet_interfaces = localhost
relayhost = [alfresco.example.com]:1025
message_size_limit = 40960000
# 配送遅延(Alfrescoの処理速度に合わせて調整)
smtp_destination_rate_delay = 5s
smtp_destination_concurrency_limit = 1
⚠️ 遅延設定なしで振り分けルールが設定されたフォルダに配送すると、処理しきれず配送エラーや0byteファイルが発生します。

4. getmail のインストールと設定

インストール

terminal
$sudo apt install getmail6 -y && mkdir -m 0700 ~/.getmail

~/.getmail/getmailrc の設定

~/.getmail/getmailrc
[options]
read_all = false
max_messages_per_session = 10
[retriever]
type = SimplePOP3SSLRetriever
server = mail.example.com
username = info@example.com
password = xxxxxxxx
[destination]
type = MDA_external
path = /usr/local/bin/spamc-wrapper.sh
arguments = ("%(sender)",)

cron 設定(5分毎)

crontab -e
# 標準エラーを /dev/null に捨てないと配送エラーになる場合がある
*/5 * * * * /usr/bin/getmail >> /var/log/getmail.log 2>&1

5. SpamAssassin の導入

インストール

terminal
$sudo apt install spamassassin spamc -y
$sudo systemctl enable --now spamd

/etc/default/spamd の設定

Ubuntu 24.04 では /etc/default/spamdOPTIONS--siteconfigpath を追加しないと、local.cf のブラックリスト設定が spamd に読み込まれません。

⚠️ この設定がないと spamassassin -t ではブラックリストが有効でも、spamc 経由では無効になります。必ず設定してください。
/etc/default/spamd(OPTIONS行を変更)
# 変更前
OPTIONS="--create-prefs --max-children 5 --helper-home-dir"
# 変更後(--siteconfigpath を追加)
OPTIONS="--create-prefs --max-children 5 --helper-home-dir --siteconfigpath /etc/spamassassin"
terminal
$sudo systemctl restart spamd

/etc/spamassassin/local.cf の設定

/etc/spamassassin/local.cf
required_score 5.0
ok_locales ja
ok_languages ja en
rewrite_header Subject ***SPAM***
# ブラックリスト(スパム送信元として多い国別ドメイン)
blacklist_from *@*.cn
blacklist_from *@*.su
blacklist_from *@スパムドメイン.*
blacklist_from MAILER-DAEMON@*
# ホワイトリスト(自組織・信頼するドメイン)
whitelist_from *@example.com
whitelist_from *@信頼ドメイン.co.jp
whitelist_from *@docomo.ne.jp
whitelist_from *@softbank.ne.jp
whitelist_from *@au.com
スコア対応
5.0 以上スパム判定(件名に ***SPAM*** 追加)
7.0 以上破棄(spamc-wrapper.sh で Alfresco に配送しない)
5.0 未満正常メール(Alfresco へ配送)

6. spamc-wrapper スクリプト

getmail から呼び出され、SpamAssassin でフィルタリング後に postfix 経由で Alfresco へ配送します。

⚠️ postfix の content_filter = spamassassin を設定するとメールループが発生します。必ずコメントアウトし、getmailrc からラッパースクリプトを直接呼び出す方式にしてください。
/usr/local/bin/spamc-wrapper.sh
#!/bin/bash
# MAILER-DAEMON は破棄
if [[ "$1" == *"MAILER-DAEMON"* ]] || [[ "$1" == "" ]]; then
echo "DISCARDED: MAILER-DAEMON" >> /tmp/spamc-wrapper.log
exit 0
fi
TMPFILE=$(mktemp)
/usr/bin/spamc -f > "$TMPFILE"
# スコアを取得
SPAM_FLAG=$(grep "X-Spam-Flag:" "$TMPFILE" | head -1 | awk '{print $2}')
SPAM_SCORE=$(grep "X-Spam-Status:" "$TMPFILE" | grep -oP 'score=\K[0-9.]+' | sort -rn | head -1)
# スコア7以上は破棄
if [ -n "$SPAM_SCORE" ]; then
SCORE_INT=$(echo "$SPAM_SCORE" | cut -d. -f1)
if [ "$SCORE_INT" -ge 7 ]; then
echo "DISCARDED(score): $1 score=$SPAM_SCORE" >> /tmp/spamc-wrapper.log
rm -f "$TMPFILE"; exit 0
fi
fi
# X-Spam-Flag: YES は破棄
if grep -qi "^X-Spam-Flag: YES" "$TMPFILE"; then
echo "DISCARDED(flag-yes): $1" >> /tmp/spamc-wrapper.log
rm -f "$TMPFILE"; exit 0
fi
# 件名・X-Spam-Prev-SubjectにSPAMが含まれる場合も破棄
if grep -i "^Subject:\|^X-Spam-Prev-Subject:" "$TMPFILE" | grep -qi "SPAM"; then
echo "DISCARDED(subject): $1" >> /tmp/spamc-wrapper.log
rm -f "$TMPFILE"; exit 0
fi
# ISO-2022-JP → UTF-8 変換
# ヘッダーのcharset指定またはJISエスケープシーケンスで判定
if grep -qi "charset.*iso-2022-jp\|charset.*jis" "$TMPFILE" || grep -q $'\x1b\$B\|\x1b\$@' "$TMPFILE"; then
CONVERTED=$(mktemp)
iconv -f ISO-2022-JP -t UTF-8//IGNORE "$TMPFILE" > "$CONVERTED" 2>/dev/null
if [ -s "$CONVERTED" ]; then
echo "CONVERTED(iso2022jp->utf8): $1" >> /tmp/spamc-wrapper.log
sed -i 's/charset=iso-2022-jp/charset=UTF-8/gI' "$CONVERTED"
sed -i 's/charset="iso-2022-jp"/charset="UTF-8"/gI' "$CONVERTED"
mv "$CONVERTED" "$TMPFILE"
else
echo "CONVERT_FAILED(iso2022jp->utf8): $1" >> /tmp/spamc-wrapper.log
rm -f "$CONVERTED"
fi
fi
# Alfrescoへ配送
/usr/sbin/sendmail -oi -f "$1" mail@alfresco.example.com < "$TMPFILE"
rm -f "$TMPFILE"
terminal
$sudo chmod +x /usr/local/bin/spamc-wrapper.sh

7. Alfresco スクリプト群

メール格納フォルダのルールに登録するJavaScriptスクリプトです。リポジトリ > Data Dictionary > Scripts に登録し、メール格納フォルダのルールに設定します。

スクリプト役割実行設定
mailRename.js件名に送信日時を付加・URLエンコード文字を全角に置換・MIMEタイプ修正通常実行
mailFolderCreate.jsメール本体受信時にフォルダを作成・アスペクト付与通常実行
mailFolderMove.jsメールをフォルダへ移動バックグラウンド実行
mailSort.js送信者アドレスで振り分け・SPAMはspamフォルダへ・自組織ドメインは別サイトへ通常実行
mailSortAdd.js手動振り分け時に送信者アドレスを登録各振り分けフォルダのルール
⚠️ mailFolderMove.js のみ「バックグラウンドで実行」にチェックが必要です。move API はバックグラウンド実行が必要なため、別スクリプトに分離しています。

mailRename.js — ファイル名に送信日時を追加・MIMEタイプ修正

mailRename.js
// 送信日時を取得してファイル名に付加
var mailDate = document.properties['cm:sentdate'];
var creatDate = document.properties['cm:created'];
if (mailDate != null && document.isDocument) {
var year_str = ('0' + mailDate.getFullYear()).slice(-2);
var month_str = ('0' + (1 + mailDate.getMonth())).slice(-2);
var day_str = ('0' + mailDate.getDate()).slice(-2);
var hour_str = ('0' + mailDate.getHours()).slice(-2);
var minute_str = ('0' + mailDate.getMinutes()).slice(-2);
var second_str = ('0' + mailDate.getSeconds()).slice(-2);
var Csecond_str = ('0' + creatDate.getSeconds()).slice(-1);
var format_str = 'YYMMDDhhmmssz'
.replace(/YY/g, year_str).replace(/MM/g, month_str)
.replace(/DD/g, day_str).replace(/hh/g, hour_str)
.replace(/mm/g, minute_str).replace(/ss/g, second_str)
.replace(/z/g, Csecond_str);
var stringDate = format_str + '_';
} else {
var stringDate = '';
}
// MIMEタイプを拡張子で判定・修正
var fullName = document.properties['cm:name'];
var lowerName = new String(fullName).toLowerCase();
var ext = lowerName.lastIndexOf('.') >= 0 ? lowerName.substring(lowerName.lastIndexOf('.')+1) : '';
if (ext==='pdf') { document.mimetype='application/pdf'; }
else if (ext==='xlsx') { document.mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; }
else if (ext==='xls') { document.mimetype='application/vnd.ms-excel'; }
else if (ext==='docx') { document.mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document'; }
else if (ext==='doc') { document.mimetype='application/msword'; }
else if (ext==='pptx') { document.mimetype='application/vnd.openxmlformats-officedocument.presentationml.presentation'; }
else if (ext==='ppt') { document.mimetype='application/vnd.ms-powerpoint'; }
else if (ext==='csv') { document.mimetype='text/csv'; }
else if (ext==='zip') { document.mimetype='application/zip'; }
else {
var mailContent = document.content;
if ((mailContent.match(/(<([^>]+)>)/gi) || []).length > 5) { document.mimetype='text/html'; }
}
// URLエンコード文字を全角に置換
var replaced = fullName
.replace(/%3a/g,':').replace(/%2f/g,'/').replace(/%3f/g,'?')
.replace(/%7c/g,'|').replace(/%22/g,'"').replace(/%2a/g,'*')
.replace(/%3c/g,'<').replace(/%3e/g,'>');
document.properties['cm:name'] = stringDate + replaced;
document.save();

mailFolderCreate.js — メールフォルダ作成

mailFolderCreate.js
var parentNode = companyhome.childByNamePath('Shared/mail');
var mailFrom = document.properties['cm:originator'];
if (mailFrom != null) {
var fullName = document.properties['cm:name'];
var fileName = fullName.split('.')[0];
var titleFolder = space.childByNamePath(fileName);
if (fullName.indexOf('.') == -1 && titleFolder.isDocument
|| titleFolder == null && space.hasPermission('CreateChildren')) {
titleFolder = space.createFolder('⁑' + fileName);
var mailContent = new String(document.content)
.replace(/\r?\n/g,' ')
.replace(/[^0-9A-Za-z\u3041-\u9fff\uFF10-\uFF9F]/g, '');
titleFolder.properties['cm:description'] = mailContent.slice(0,60);
titleFolder.save();
var props = new Array(2);
props['cm:sentdate'] = document.properties['cm:sentdate'];
props['cm:originator'] = mailFrom;
titleFolder.addAspect('cm:emailed', props);
var CSprops = new Array(1);
CSprops['cs:publishdate'] = document.properties['cm:sentdate'];
titleFolder.addAspect('cs:published', CSprops);
}
parentNode.properties['cs:address'] = titleFolder;
parentNode.save();
}

mailFolderMove.js — メールをフォルダへ移動(バックグラウンド実行)

mailFolderMove.js
var parentNode = companyhome.childByNamePath('Shared/mail');
var nodeString = parentNode.properties['cs:address'];
var convNode = search.findNode(nodeString);
var props = new Array(2);
props['cs:publishdate'] = convNode.properties['cm:sentdate'];
props['cs:publisher'] = convNode.properties['cm:originator'];
document.addAspect('cs:published', props);
document.move(convNode);

mailSort.js — 振り分けスクリプト 最新版

件名にSPAMを含むメールは最優先でspamフォルダへ、自組織ドメインのメールは別サイトのフォルダへ直接移動します。それ以外は各振り分けフォルダの cs:address と照合して移動します。

移動後に setInheritsPermissions(true) を呼び出すことで、移動後のフォルダが再移動できなくなる問題(SHARED ACL問題)を防止しています。

ℹ️ SHARED ACL問題について:フォルダルールで別サイトのフォルダへ document.move() した後、そのフォルダを再度移動しようとすると「移動できませんでした」エラーが発生することがあります。setInheritsPermissions(true) を追加することでACLがDEFINING状態に再設定され、再移動が可能になります。
mailSort.js
// ① SPAMは「spam」フォルダへ(sa-learn学習用)
var fileName = document.properties['cm:name'];
if (fileName.indexOf("SPAM") != -1) {
var dest = document.parent.childByNamePath('spam');
document.move(dest);
}
else {
var mailFrom = document.properties['cm:originator'];
if (mailFrom != null) {
// ② 自組織ドメインは別サイトのフォルダへ直接移動
if (new String(mailFrom).toLowerCase().indexOf('@example.com') != -1) {
var teishutsu = search.findNode(
'workspace://SpacesStore/移動先フォルダのノードID');
if (teishutsu != null) {
document.move(teishutsu);
document.setInheritsPermissions(true); // SHARED ACL問題の対策
}
}
// ③ それ以外はcs:addressで振り分け先判定
else {
function getAdd(sortFolder) {
dest = document.parent.childByNamePath(sortFolder);
if (dest == null) return new RegExp('(?!)');
var adList = dest.properties['cs:address'];
if (adList == null) return new RegExp('(?!)');
var adListStr = new String(adList).trim();
if (adListStr==='' || adListStr==='null') return new RegExp('(?!)');
return new RegExp(adListStr.replace(/\r?\n/g, '|'));
}
if (getAdd('フォルダA').test(mailFrom)) { document.move(dest); }
else if (getAdd('フォルダB').test(mailFrom)) { document.move(dest); }
else if (getAdd('フォルダC').test(mailFrom)) { document.move(dest); }
else if (getAdd('その他').test(mailFrom)) { document.move(dest); }
// 必要に応じて else if を追加
}
}
}
⚠️ cs:address の容量上限に注意:各振り分けフォルダの cs:address は最大50,000文字(d:text型)です。上限に達するとルール実行時にエラーが大量ループしサーバー全体の負荷が急増します。定期的に整理してください。

mailSortAdd.js — アドレス登録スクリプト

mailSortAdd.js
var created = document.properties['cm:created'];
var modified = document.properties['cm:modified'];
// 作成日と変更日が異なる=手動移動の場合のみ続行
if (created != modified) {
var mailFrom = document.properties['cm:originator'];
if (mailFrom != null) {
var parentNode = document.parent;
var adList = parentNode.properties['cs:address'];
if (adList == null || new String(adList).trim()==='' || new String(adList).trim()==='null') {
parentNode.properties['cs:address'] = mailFrom;
parentNode.save();
} else {
var adListStr = new String(adList);
var regexp = new RegExp(adListStr.replace(/\r?\n/g, '|'));
if (!regexp.test(mailFrom)) {
parentNode.properties['cs:address'] = adListStr + '\n' + mailFrom;
parentNode.save();
}
}
}
}

8. カスタムモデルの設定

アスペクト名プロパティ用途
cs:publishedcs:publishdated:date発行日(ソート用)
cs:publisherd:text発行者
cs:maillistcs:addressd:text(maxLength=50000)振り分けアドレスリスト
⚠️ cs:addressd:text 型・maxLength=50000 で設定してください。上限を超えるとエラーが大量ループしサーバー全体の負荷が急増します。

モデルXML(cs:maillist アスペクト部分)

bunsho_model.xml(抜粋)
<aspect name="cs:maillist">
<title>メール一覧</title>
<properties>
<property name="cs:address">
<title>アドレスリスト</title>
<type>d:text</type>
<mandatory>false</mandatory>
<multiple>false</multiple>
<constraints>
<constraint name="cs:ADDRESS_LENGTH" type="LENGTH">
<parameter name="maxLength"><value>50000</value></parameter>
<parameter name="minLength"><value>0</value></parameter>
</constraint>
</constraints>
</property>
</properties>
</aspect>

振り分け先フォルダへのアスペクト設定

1
振り分け先フォルダを右クリック → 「アスペクトの管理」
2
「使用可能なアスペクト」から cs:maillist(メール一覧) を選択 → 「追加」
3
「変更を適用」 → 振り分け先フォルダ全てに繰り返す

9. Alfresco Share の設定(メールエイリアス)

メール受信先フォルダに Eメールエイリアスを設定します。

1
メール受信先フォルダを右クリック → 「アスペクトの管理」
2
「Eメールエイリアス(emailserver:aliasable)」を選択 → 「追加」→「変更を適用」
3
フォルダを右クリック → 「プロパティを編集」 → 「Eメールエイリアス」に送信先名を入力(例:mail
4
「保存」
設定箇所設定値(例)メールアドレス
Eメールエイリアスmailmail@alfresco.example.com
email.server.domainalfresco.example.com
postfix relayhost[alfresco.example.com]:1025Alfresco SMTPポートへ中継

10. spamフォルダの定期学習・自動整理

件名に ***SPAM*** が付いたメールを専用フォルダへ振り分け、定期的に SpamAssassin のベイジアンフィルタへ学習させたうえで自動整理します。

認証情報の外部ファイル管理

⚠️ 認証情報をスクリプト本体に直書きすると crontab や Git 履歴から漏洩するリスクがあります。必ず外部ファイルに分離してください。
/etc/alfresco/credentials
ALFRESCO_USER=admin
ALFRESCO_PASS=xxxxxxxx
ALFRESCO_HOST=http://localhost:8080
SPAM_FOLDER_ID=spamフォルダのノードID
CLEAR_SCRIPT_ID=clearAndDeleteSpam.jsのノードID
SONOTA_ID=その他フォルダのノードID
BATCH_SCRIPT_ID=deleteSpamBatch.jsのノードID
terminal(パーミッション設定)
$sudo chmod 640 /etc/alfresco/credentials
$sudo chown root:実行ユーザー名 /etc/alfresco/credentials
⚠️ ファイルのオーナーが root:root のままだと、cronを一般ユーザーで実行した際に Permission denied エラーになります。cronを実行するユーザーをグループオーナーに設定し、640 権限にしてください。

deleteSpamBatch.js — 蓄積SPAMを少しずつ削除

deleteSpamBatch.js
var BATCH_SIZE = 100;
var sonotaFolder = companyhome.childByNamePath('Shared/mail/その他');
var deletedCount = 0;
var children = sonotaFolder.children;
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.isContainer) {
var folderName = new String(child.name);
if (folderName.indexOf('SPAM') != -1) {
child.remove();
deletedCount++;
if (deletedCount >= BATCH_SIZE) { break; }
}
}
}
logger.log('削除完了: ' + deletedCount + '件(上限: ' + BATCH_SIZE + '件)');

spam-batch-delete.sh — バッチ削除シェルスクリプト

/usr/local/bin/spam-batch-delete.sh
#!/bin/bash
source /etc/alfresco/credentials
LOGFILE="/var/log/spam-batch-delete.log"
echo "=== $(date) 実行 ===" >> "$LOGFILE"
# 残り件数を確認
REMAINING=$(curl -s -u "$ALFRESCO_USER:$ALFRESCO_PASS" \
"$ALFRESCO_HOST/alfresco/api/-default-/public/alfresco/versions/1/nodes/$SONOTA_ID/children?maxItems=1&where=(isFolder=true)" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d['list']['pagination']['totalItems'])" 2>/dev/null)
echo "残り件数: $REMAINING" >> "$LOGFILE"
if [ "$REMAINING" = "0" ]; then
echo "削除完了。cronを無効化してください。" >> "$LOGFILE"
exit 0
fi
# バッチ削除実行
curl -s -u "$ALFRESCO_USER:$ALFRESCO_PASS" \
-X POST -H "Content-Type: application/json" \
"$ALFRESCO_HOST/alfresco/s/api/actionQueue?async=false" \
-d "{\"actionedUponNode\":\"workspace://SpacesStore/$SONOTA_ID\",\"actionDefinitionName\":\"script\",\"parameterValues\":{\"script-ref\":\"workspace://SpacesStore/$BATCH_SCRIPT_ID\"}}" \
>> "$LOGFILE" 2>&1

cron登録

ℹ️ タイムゾーンを日本時間(JST)に設定してからcronを登録してください。sudo timedatectl set-timezone Asia/Tokyo で設定できます。sudo crontab -e(root)と crontab -e(一般ユーザー)は別ファイルで管理されます。どのユーザーで登録したか必ず記録してください。
一般ユーザー crontab(crontab -e)
# getmail 5分毎
*/5 * * * * /usr/bin/getmail > /dev/null 2>&1
# 蓄積済みSPAMのバッチ削除(完了後にこの行を削除)
0 */2 * * * /usr/local/bin/spam-batch-delete.sh
ℹ️ /var/log/spam-batch-delete.log に「削除完了。cronを無効化してください。」と表示されたら、crontabから spam-batch-delete.sh の行を削除してください。

11. ISO-2022-JP メール文字化け対応

古いメールクライアントから送信されたISO-2022-JP(JIS)エンコードのメールはAlfrescoがUTF-8として処理するため文字化けします。spamc-wrapper.sh でAlfrescoへ配送前にUTF-8へ変換することで対処します。

11-1. ISO-2022-JP(JISエンコード)メールの文字化け対応

古いメールクライアントから送信されたISO-2022-JPエンコードのメールはAlfrescoがUTF-8として処理するため文字化けします。spamc-wrapper.sh でAlfrescoへ配送前にUTF-8へ変換することで対処します。

ℹ️ ISO-2022-JPメールはヘッダーに charset=iso-2022-jp または本文に \x1b$B(JISエスケープ)を含みます。//IGNORE オプションで不正バイトを無視して変換することで、変換失敗を防止します。

第6章の spamc-wrapper.sh にISO-2022-JP変換処理が含まれています(Alfrescoへの配送直前に自動変換)。変換ログは /tmp/spamc-wrapper.logCONVERTED(iso2022jp->utf8) として記録されます。

11-2. 既存ISO-2022-JPファイルの一括変換

サーバー移行前に蓄積済みのISO-2022-JPメールを一括変換するスクリプトです。REST API経由でコンテンツをダウンロード・変換・アップロードします。

/usr/local/bin/iso2022jp-convert.sh(抜粋)
#!/bin/bash
source /etc/alfresco/credentials
LOGFILE="/var/log/alfresco/iso2022jp-convert.log"
BATCH_SIZE=100
SKIP_COUNT=0 # 中断・再開時はここを変更
# ISO-2022-JPか判定して変換・アップロード
if grep -q $'\x1b\$B\|\x1b\$@' "$TMPFILE" || file "$TMPFILE" | grep -qi "iso-2022\|jis"; then
iconv -f ISO-2022-JP -t UTF-8//IGNORE "$TMPFILE" > "$CONVERTED_FILE" 2>/dev/null
if [ -s "$CONVERTED_FILE" ]; then
curl -s -u "$ALFRESCO_USER:$ALFRESCO_PASS" -X PUT \
-H "Content-Type: text/plain; charset=UTF-8" \
--data-binary @"$CONVERTED_FILE" \
"$ALFRESCO_HOST/.../nodes/$NODE_ID/content?majorVersion=false"
fi
fi
項目内容
対象mail配下のtext/plainファイル(約95,000件)
処理時間約3〜4時間(ISO-2022-JPは全体の約26%)
中断・再開ログの進捗を確認してSKIP_COUNTを変更して再実行
実行推奨時間業務時間外(screenコマンドで実行)
バージョン記録majorVersion=falseのためマイナーバージョンとして記録
⚠️ 実行前に必ずデータベースのバックアップを取得してください。sudo -u postgres pg_dump alfresco > /tmp/alfresco_backup_$(date +%Y%m%d).sql

12. トラブルシューティング

移動したフォルダが再移動できない(SHARED ACL問題)

  • 原因:フォルダルールで document.move() を実行後、ノードのACLがSHARED(type=2)状態になる
  • 症状:Share UIで「移動できませんでした」、REST APIで setFixedAcls: unexpected shared acl エラー
  • 新規メール:修正版 mailSort.jssetInheritsPermissions(true) で防止済み
  • 既存ノード(数件):ゴミ箱経由での復旧が安全(下記参照)
ℹ️ ゴミ箱経由での復旧手順:(1) Share UIで対象フォルダをゴミ箱へ移動 → (2) http://サーバーIP:8080/share/page/user/admin/user-trashcan にアクセス → (3) [復元] をクリック → (4) 復元されたフォルダを目的のフォルダへ移動

添付ファイルのMIMEタイプ誤設定

  • 原因:メール取り込み時に添付ファイルのMIMEタイプが text/html に誤設定される
  • 新規メール:修正版 mailRename.js で自動的に正しいMIMEタイプが設定される
  • 既存ファイル:fixMime.js をData Dictionary/Scriptsに登録してREST API経由で実行

メールループ(too many hops)

🚨 postfix の content_filter = spamassassin を設定するとメールループが発生します。必ずコメントアウトしてください。

振り分けアドレス上限超過

  • 症状:IntegrityException: String length is not in range [0; 50,000] が大量ループしサーバーの応答が低下する
  • 対処:対象フォルダの cs:address を REST API で null にクリアし必要なアドレスのみ再登録する

cronが動かない(認証エラー)

  • 原因:/etc/alfresco/credentials のパーミッションが root:root 600 のままでcron実行ユーザーが読めない
  • 対処:sudo chown root:実行ユーザー名 /etc/alfresco/credentials && sudo chmod 640 /etc/alfresco/credentials

cronが動かない(ログファイルへの書き込みエラー)

  • 原因:/var/log/spam-batch-delete.log のオーナーが root:root でcron実行ユーザーが書き込めない
  • 対処:sudo chown 実行ユーザー名:実行ユーザー名 /var/log/spam-batch-delete.log

ログ確認コマンド

terminal
$sudo tail -50 /var/log/mail.log | grep -E "status=|error|bounce"
$cat /tmp/spamc-wrapper.log | tail -30
$sudo tail -100 /var/log/alfresco/alfresco.log | grep -i "error\|permission\|move"
$tail -10 /var/log/spam-batch-delete.log

設定確認チェックリスト

  • postfix の content_filter がコメントアウトされている
  • spamc-wrapper.sh に実行権限がある(chmod +x)
  • getmailrc の destination が spamc-wrapper.sh を参照している
  • SpamAssassin(spamd)が起動している
  • /etc/default/spamd の OPTIONS に --siteconfigpath が設定されている
  • 振り分けフォルダに cs:maillist アスペクトが適用されている
  • /etc/alfresco/credentials のパーミッションが root:実行ユーザー 640 になっている
  • /var/log/spam-batch-delete.log のオーナーが実行ユーザーになっている
  • alfresco-global.properties の alfresco.host にサーバーIPが設定されている
  • spamc-wrapper.sh にISO-2022-JP → UTF-8変換処理が含まれている
正常に設定できると、受信メールが自動的にスパム判定・振り分けされてAlfrescoに格納されます。

Alfresco Community 26.1 / Ubuntu 24.04 / Ansible インストール環境での設定例です。

2025年7月19日土曜日

alfresco community7.0 → 7.4 ansible アップグレード

【はじめに】 

alfresco community(ansibleインストール)のアップグレードにつまずき、気がつけばv25.1になっていたが、最近やっと成功したため、設定を記録しておく。v25.1に直接アップグレートできるのはv7.4以降のため、今回はv7.4へのアップグレート手順を記載する。

【手順の概要】

1.対応しているOS ここではubuntu22.04 server をインストール

2.alfresco7.4をansibleで自動構築する。

alfresco7.4(リリースVer.2.3.0)をダウンロード

sudo curl -OL https://github.com/Alfresco/alfresco-ansible-deployment/archive/refs/tags/v2.3.0.zip

ダウンロードしたファイルを解凍

sudo apt install unzip #必要時
sudo unzip v2.3.0.zip

解凍したフォルダへ移動

cd alfresco-ansible-deployment-2.3.0

python3系のパッケージ管理システムpipをインストールし、pipenvを導入

sudo apt-get install python3-pip
pip3 install --user pipenv

pipenvによるAnsible依存関係のインストール

python3 -m pipenv install --deploy
python3 -m pipenv run ansible-galaxy install -r requirements.yml

Ansible vaultのパスワードを生成

openssl rand -base64 21 > ~/.vault_pass.txt
export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass.txt

シークレットを自動生成

sudo chmod 777 vars   #下記のタスクでエラーが出る場合
python3 -m pipenv run ansible-playbook -e vault_init=encrypted_file playbooks/secrets-init.yml

アクセスに使用するドメインURLを指定。可能性のあるドメインURLを全て指定する。指定を誤るとAlfrescoが起動してもファイル操作等ができない。設定内容はalfresco-global.propertiesに記録される。

sudo vi inventory_local.yml
---
all:
  vars:
    ansible_connection: local
  children:
    repository:
      vars:
        known_urls:
          - http://localhost/share #自サーバーのURLに変更 例192.168.100.1:8080/share
          - https://localhost/share
      hosts:
        localhost:

Ansibleのalfrescoインストールタスクを実行

sudo chmod 777 configuration_files #エラーが出る場合
python3 -m pipenv run ansible-playbook playbooks/acs.yml -i inventory_local.yml -e "@community-extra-vars.yml"

3.移行元サーバーからのデータ受入のため、samba serverを設定

sambaインストール

sudo apt install samba

共有フォルダ作成

sudo mkdir -p /smb/share
sudo chmod -R 777 /smb/share

設定ファイルに追記

sudo vi /etc/samba/smb.conf
[Share]
path = /smb/share
browseable = yes
read only = no
guest ok = yes

再起動で設定を反映

sudo systemctl restart smbd

4.移行元サーバーからデータ抽出・受入

※移行元サーバーで作業

移行先のサーバーのsambaフォルダをマウント

sudo mkdir /mnt/smb #任意のフォルダ名
sudo mount -t cifs //移行先サーバのIPアドレス/share /mnt/smb

移行元のalfrescoを停止

sudo systemctl stop alfresco-content.service
sudo systemctl stop alfresco-search.service

データを移行先サーバーへコールドバックアップ

sudo rsync -avh /var/opt/alfresco/content-services/content /mnt/smb #shareコンテンツ
sudo rsync -avh /var/opt/alfresco/search-services/alfresco /mnt/smb #solrインデックス
sudo rsync -avh /var/opt/alfresco/search-services/archive /mnt/smb #solrバックアップ
sudo rsync -avh /etc/opt/alfresco/search-services/solrhome/alfrescoModels /mnt/smb #solrモデル

データベースをバックアップ

su -
su - postgres
pg_dumpall > /mnt/smb/任意のファイル名
exit

【必要時】カスタマイズ設定をバックアップ

sudo rsync -avh /etc/opt/alfresco/content-services/classpath/alfresco/extension /mnt/smb
sudo rsync -avh /etc/opt/alfresco/content-services/classpath/alfresco/web-extension /mnt/smb
sudo rsync -avh /etc/opt/alfresco/content-services/classpath/alfresco/messages /mnt/smb

5.移行先でのデータ差替

shareコンテンツの移行

#shareコンテンツデータ削除
sudo rm -R /var/opt/alfresco/content-services/content/contentstore
sudo rm -R /var/opt/alfresco/content-services/content/contentstore.deleted
#移行元からコピーしたshareコンテンツデータをインストール先へ移動
sudo mv /smb/share/content/contentstore /smb/share/content/contentstore.deleted /var/opt/alfresco/content-services/content/

#所有者をalfrescoに変更

sudo chown -hR alfresco:alfresco /var/opt/alfresco/content-services/

solrデータの移行

#solrデータディレクトリ削除
sudo rm -R /opt/alfresco/search-services/alfresco/index
sudo rm -R /opt/alfresco/search-services/archive/index
#solrモデル削除
sudo rm -R /etc/opt/alfresco/search-services/solrhome/alfrescoModels
#solrデータディレクトリ移行
sudo mv /smb/share/alfresco/index /opt/alfresco/search-services/alfresco/
sudo mv /smb/share/archive/index /opt/alfresco/search-services/archive/
#solrモデル移行
sudo mv /smb/share/alfrescoModels /etc/opt/alfresco/search-services/solrhome/
#所有者をalfrescoに変更
sudo chown -hR alfresco:alfresco /opt/alfresco/search-services/alfresco/
sudo chown -hR alfresco:alfresco /opt/alfresco/search-services/archive/
sudo chown -hR alfresco:alfresco /etc/opt/alfresco/search-services/solrhome/

データベースの移行

【必要時】rootパスワードを設定する。

sudo passwd root
su -
su -postgres
psql
drop database alfresco ;
create database alfresco ;
\q
psql  -f /smb/share/ダンプしたファイル名
exit

【必要時】カスタマイズ設定の移行

sudo mv /smb/share/alfresco/extension/custom-model-context.xml /smb/share/alfresco/extension/customModel.xml /etc/opt/alfresco/content-services/classpath/alfresco/extension/.
sudo mv /smb/share/alfresco/web-extension/share-config-custom.xml /etc/opt/alfresco/content-services/classpath/alfresco/web-extension/.
sudo mv /smb/share/alfresco/messages /etc/opt/alfresco/content-services/classpath/alfresco/
sudo chown -R alfresco:alfresco /etc/opt/alfresco/content-services/classpath/alfresco/extension
sudo chown -R alfresco:alfresco /etc/opt/alfresco/content-services/classpath/alfresco/web-extension
sudo chown -R alfresco:alfresco /etc/opt/alfresco/content-services/classpath/alfresco/messages

6.alfresco起動

sudo systemctl start alfresco-content.service
sudo systemctl start alfresco-search.service

【追加】ログインできない場合

vars/secrets.ymlを初期化して、再度インストールタスクを実行
alfresco-global.propertiesをカスタマイズしている場合は、インストールタスク終了後再度設定

sudo vi vars/secrets.yml
 記載内容を全て削除
openssl rand -base64 21 > ~/.vault_pass.txt
export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass.txt
python3 -m pipenv run ansible-playbook -e vault_init=encrypted_file playbooks/secrets-init.yml
python3 -m pipenv run ansible-playbook playbooks/acs.yml -i inventory_local.yml -e "@community-extra-vars.yml"

2025年6月10日火曜日

alfresco25.1 ソートのカスタマイズ

コンテンツの作成者・作成日を基準にソートできるようにする。

参照 aegif Labo Blog

1.モデルマネージャー モデルを作成

①管理ツールからモデルマネージャーを選択

②モデルの作成

③名前をクリック

④アスペクトの作成をクリック

⑤アスペクトの作成

⑥プロパティの作成をクリック

⑦プロパティの作成

⑧モデルの有効化

2.UIの設定(ソートをカスタマイズ)

sudo vi /etc/opt/alfresco/content-services/classpath/alfresco/web-extension/share-config-custom.xml

612行目 以下をコピー

 <!--
         Sorting Options
         The 'sort' config element contains the name of the content model field to sort against and can be of the form:
         - short QName string e.g. "cm:name"
         - any other valid sortable fts-alfresco special field e.g. "TYPE"
         The field can be optionally followed by |true or |false to indicate sort direction,
         where true = ascending, false = descending
      -->
      <sorting>
         <sort label="label.name">cm:name|true</sort>
         <sort label="label.popularity">cm:likesRatingSchemeCount|false</sort>
         <sort label="label.title">cm:title</sort>
         <sort label="label.description">cm:description</sort>
         <sort label="label.created">cm:created</sort>
         <sort label="label.creator">cm:creator</sort>
         <sort label="label.modified">cm:modified</sort>
         <sort label="label.modifier">cm:modifier</sort>
         <sort label="label.size">cm:content.size</sort>
         <sort label="label.mimetype">cm:content.mimetype</sort>
         <sort label="label.type">TYPE</sort>
      </sorting>

sudo vi tomcat/shared/classes/alfresco/web-extension/share-config-custom.xml
<alfresco-config>
    
#<---------------中略--------------->
 <!-- Document Library config section -->
<config evaluator="string-compare" condition="DocumentLibrary" replace="true">
#上記を貼付 ソートラベルを追加
     
<!--
         Sorting Options
         The 'sort' config element contains the name of the content model field to sort against and can be of the form:
         - short QName string e.g. "cm:name"
         - any other valid sortable fts-alfresco special field e.g. "TYPE"
         The field can be optionally followed by |true or |false to indicate sort direction,
         where true = ascending, false = descending
      -->
      <sorting>  
         <sort label="label.name">cm:name|true</sort>                                                                              <sort label="label.popularity">cm:likesRatingSchemeCount|false</sort>
         <sort label="label.title">cm:title</sort>
         <sort label="label.description">cm:description</sort>
         <sort label="label.created">cm:created</sort>
         <sort label="label.creator">cm:creator</sort>
         <sort label="label.modified">cm:modified</sort>
         <sort label="label.modifier">cm:modifier</sort>
         <sort label="label.size">cm:content.size</sort>
         <sort label="label.mimetype">cm:content.mimetype</sort>
         <sort label="label.type">TYPE</sort>

         <sort label="label.published">cs:publishDate</sort>
      </sorting>

3.アスペクトの表示名の定義ファイルを設定

sudo vi /etc/opt/alfresco/content-services/classpath/alfresco/web-extension/custom-messages-context.xml
#下記を記載
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
    <bean id="custom.resources" class="org.springframework.extensions.surf.util.ResourceBundleBootstrapComponent">
        <property name="resourceBundles">
            <list>
                <value>alfresco.messages.custom-messages</value>
            </list>
        </property>
     </bean>
</beans>

4.アスペクトの表示名の英語表記ファイルを作成

sudo mkdir /etc/opt/alfresco/content-services/classpath/alfresco/messages
sudo vi /etc/opt/alfresco/content-services/classpath/alfresco/messages/custom-messages.properties
label.published=Published

5.アスペクトの表示名の日本語表記ファイルを作成

sudo vi /etc/opt/alfresco/content-services/classpath/alfresco/messages/custom-messages_ja.properties
#日本語はunicodeで表記
label.published=\u767A\u884C\u65E5

5.alfrescoサーバーの再起動

sudo systemctl restart alfresco-content.service