SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor

VPS-এ নিজের CalDAV ক্যালেন্ডার সার্ভার সেটআপ করার নিয়ম

Google ছাড়াই ফোন ও ল্যাপটপে ক্যালেন্ডার সিঙ্ক করতে Radicale ব্যবহার করুন। এই গাইডে TLS কনফিগারেশন, সার্ভার ডিসকভারি এবং ক্লায়েন্ট সেটআপের পূর্ণাঙ্গ ধাপগুলো দেখানো হয়েছে।

আপনি যা তৈরি করছেন

একটি self-hosted ক্যালেন্ডার হলো আপনার নিয়ন্ত্রণে থাকা একটি VPS-এ চলমান একটি CalDAV সার্ভার, যা TLS-এর পেছনে সুরক্ষিত এবং প্রতিটি ব্যবহারকারীর জন্য আলাদা লগইন সুবিধা রয়েছে। আপনার পকেটের ফোন এবং ডেস্কের ল্যাপটপে একই ইভেন্ট দেখা যাবে, এমনকি আপনার সঙ্গীর ল্যাপটপেও একই তথ্য থাকবে। এর মাঝে কোনো Google অ্যাকাউন্ট থাকবে না।

এটি একটি self-hosted বুকিং পেজ থেকে ভিন্ন একটি কাজ। বুকিং পেজ অপরিচিতদের জন্য: এটি আপনার ফাঁকা সময়গুলো প্রকাশ করে এবং কাউকে একটি স্লট বুক করার সুযোগ দেয়। ক্যালেন্ডার সার্ভার আপনার নিজের ডিভাইসের জন্য: এটি ইভেন্টগুলো সংরক্ষণ করে এবং প্রতিটি ক্লায়েন্টের মধ্যে তথ্যের সামঞ্জস্য বজায় রাখে। মানুষ সাধারণত দুটিই ব্যবহার করে, এবং বুকিং টুলটি তখন আপনার তৈরি করা এই CalDAV সার্ভার থেকে প্রাপ্যতা যাচাই করে।

ইনস্টলেশনটি বেশ ছোট। Radicale একটি Python প্যাকেজ এবং এতে প্রায় দশ লাইনের কনফিগারেশন থাকে। সেটআপটি প্রথম মাস পার করতে পারবে কি না তা নির্ভর করে TLS, discovery, প্রতি ব্যবহারকারীর কালেকশন এবং ব্যাকআপের ওপর। নিচে এগুলোর ওপরই সবচেয়ে বেশি গুরুত্ব দেওয়া হয়েছে।

CalDAV কী এবং এটি কেন গুরুত্বপূর্ণ?

CalDAV হলো HTTP-এর মাধ্যমে ক্যালেন্ডার সিঙ্ক করার একটি পদ্ধতি। এটি RFC 4791-এ WebDAV (web distributed authoring and versioning, RFC 4918-এ সংজ্ঞায়িত অতিরিক্ত HTTP মেথডের একটি সেট)-এর এক্সটেনশন হিসেবে সংজ্ঞায়িত। একটি ক্যালেন্ডার হলো একটি কালেকশন, যা অনেকটা ডিরেক্টরির মতো কাজ করে। প্রতিটি ইভেন্ট এর ভেতরে থাকা একটি ফাইল, যা iCalendar টেক্সট ফরম্যাটে (RFC 5545) লেখা থাকে; এটি আপনার মেইলে থাকা .ics অ্যাটাচমেন্টের মতোই একটি ফরম্যাট।

ক্লায়েন্টরা সাধারণ HTTP-এর সাথে কিছু অতিরিক্ত মেথড ব্যবহার করে। PROPFIND জানতে চায় সেখানে কী আছে এবং এর কী কী প্রপার্টি রয়েছে। REPORT একটি ফিল্টার করা অংশ চায়, যেমন একটি নির্দিষ্ট তারিখের সীমার মধ্যে থাকা সব ইভেন্ট। PUT একটি ইভেন্ট লেখে এবং DELETE সেটি মুছে ফেলে। প্রতিটি ইভেন্টে একটি UID লাইন থাকে এবং এই আইডেন্টিফায়ারের মাধ্যমেই দুটি ডিভাইস বুঝতে পারে যে তারা একই ইভেন্ট দেখছে, কোনো কপি নয়।

এর মূল সুবিধা হলো পোর্টেবিলিটি, আর এই কারণেই এটি ব্যবহার করা হয়। iOS, macOS, Thunderbird, Evolution এবং DAVx⁵-এর মাধ্যমে Android—সবই CalDAV সাপোর্ট করে। আপনার ডেটা আপনার বর্তমান সার্ভারের সাথে আবদ্ধ নয়। ফাইলগুলো অন্য একটি CalDAV সার্ভারে সরিয়ে নিন, ক্লায়েন্টদের নতুন হোস্টনাম দেখিয়ে দিন, আর কোনো কিছু পরিবর্তন করার প্রয়োজন হবে না।

CardDAV-ও একইভাবে কাজ করে। এটি কন্টাক্টের জন্য একই ধারণা, যা RFC 6352-এ সংজ্ঞায়িত এবং ইভেন্টের পরিবর্তে vCard ফাইল সংরক্ষণ করে। নিচে উল্লিখিত প্রতিটি সার্ভার একই অ্যাকাউন্ট থেকে উভয় প্রোটোকলই সাপোর্ট করে, তাই একবার ক্যালেন্ডার সেটআপ হয়ে গেলে, অ্যাড্রেস বুক চালু করা কেবল একটি চেকবাক্সের বিষয়।

কোন CalDAV সার্ভারটি আপনার চালানো উচিত?

Radicale হলো সবচেয়ে ছোট কার্যকর সমাধান। এটি Python-এ চলে, কোনো ডাটাবেসের প্রয়োজন হয় না এবং ফাইলগুলো সাধারণ ফোল্ডার হিসেবে জমা থাকে। এই গাইডে এটি ব্যবহার করা হয়েছে কারণ একটি পারিবারিক ক্যালেন্ডারের জন্য এর চেয়ে বেশি কিছুর প্রয়োজন নেই এবং ভোর তিনটার সময় এতে কোনো সমস্যা হওয়ার সম্ভাবনা খুবই কম।

Baikal হলো এমন একটি বিকল্প যাতে একটি ওয়েব অ্যাডমিন প্যানেল রয়েছে। এটি PHP এবং sabre/dav লাইব্রেরিতে চলে, ব্যবহারকারী ও ক্যালেন্ডারের তথ্য SQLite বা MySQL-এ রাখে এবং আপনাকে কমান্ড লাইনের পরিবর্তে ব্রাউজার থেকেই নতুন ব্যবহারকারী যোগ করার সুবিধা দেয়। যখন আপনার সার্ভারে ঘনঘন অ্যাকাউন্ট যোগ বা বাদ দেওয়ার প্রয়োজন হয়, তখন এটি বেছে নিন।

Nextcloud তখন উপযুক্ত যখন ক্যালেন্ডার আপনার অনেকগুলো ফিচারের মধ্যে একটি মাত্র ফিচার। আপনি ক্যালেন্ডার, কন্টাক্ট, ফাইল এবং মোবাইল অ্যাপের সুবিধা পাবেন, তবে এর বিনিময়ে আপনাকে PHP-FPM, একটি ডাটাবেস এবং ব্যাকগ্রাউন্ড জব রানার পরিচালনা করতে হবে। যদি আপনার প্রয়োজনের তুলনায় এটি অনেক বেশি ভারী মনে হয়, তবে হালকা Nextcloud বিকল্পগুলো আপনার চাহিদা পূরণ করতে পারে এবং self-hosted file sync সেই কাজের অর্ধেক সমাধান করে যার জন্য মানুষ সাধারণত Nextcloud ইনস্টল করে।

DAViCal হলো দীর্ঘদিনের পরীক্ষিত PostgreSQL ভিত্তিক বিকল্প। এটি কেবল তখনই বিবেচনা করুন যদি আপনি ইতিমধ্যে PostgreSQL ব্যবহার করেন এবং ক্যালেন্ডারের ডাটা সেখানে রাখতে চান।

Ubuntu 24.04-এ Radicale ইনস্টল করা

আগস্ট 2026 অনুযায়ী Radicale 3.5.10 ছিল বর্তমান রিলিজ। এটিকে একটি আলাদা virtual environment-এ ইনস্টল করুন।

sudo apt update
sudo apt install -y python3-venv apache2-utils nginx
sudo useradd --system --user-group --home-dir / --shell /usr/sbin/nologin radicale
sudo install -d -o radicale -g radicale -m 750 /var/lib/radicale/collections
sudo install -d -m 750 -o root -g radicale /etc/radicale
sudo python3 -m venv /opt/radicale/venv
sudo /opt/radicale/venv/bin/pip install --upgrade radicale

Virtual environment ব্যবহার করা কোনো শৌখিনতা নয়। সিস্টেম Python-এ sudo pip install radicale চালানো error: externally-managed-environment দিয়ে বন্ধ হয়ে যায়, কারণ Ubuntu তার Python-কে apt-এর মালিকানাধীন হিসেবে চিহ্নিত করে যাতে pip কোনো প্যাকেজ করা ফাইল ওভাররাইট করতে না পারে।

/etc/radicale/config লিখুন:

[server]
hosts = 127.0.0.1:5232

[auth]
type = htpasswd
htpasswd_filename = /etc/radicale/users
htpasswd_encryption = autodetect

[storage]
filesystem_folder = /var/lib/radicale/collections

hosts ইচ্ছাকৃতভাবে loopback-এ bind করে। nginx TLS termination সম্পন্ন করে এবং সেই পোর্টে অনুরোধ পাঠায়, তাই Radicale সরাসরি ইন্টারনেটের মুখোমুখি হয় না। 0.0.0.0:5232-এর আপস্ট্রিম উদাহরণে একটি এনক্রিপশনহীন সার্ভিস প্রকাশ করা হয় যা পাসওয়ার্ড গ্রহণ করে, এটিই এখানে সবচেয়ে গুরুত্বপূর্ণ ভুল।

এখন অ্যাকাউন্টগুলোর পালা। -5 SHA-512 crypt নির্বাচন করে, যা Radicale কোনো অতিরিক্ত মডিউল ছাড়াই htpasswd_encryption = autodetect দিয়ে পড়তে পারে:

sudo htpasswd -5 -c /etc/radicale/users you
sudo htpasswd -5 /etc/radicale/users partner
sudo chown root:radicale /etc/radicale/users
sudo chmod 640 /etc/radicale/users

-c ফাইলটি তৈরি করে এবং এর আগের সব তথ্য মুছে ফেলে। এটি শুধুমাত্র প্রথম ব্যবহারকারীর জন্য ব্যবহার করুন। কয়েক মাস পর আবার htpasswd -5 -c চালালে প্রথমটির পরে যোগ করা সব অ্যাকাউন্ট মুছে যাবে, এবং এর লক্ষণ হলো একজন ব্যবহারকারী ঠিকমতো সিঙ্ক করতে পারলেও বাকি সবার পাসওয়ার্ড প্রম্পট বারবার আসতে থাকবে। Bcrypt-ও কাজ করে, তবে এর জন্য radicale[bcrypt] অতিরিক্ত ইনস্টল করতে হয়।

Radicale ডকুমেন্টেশনের ইউনিট থেকে অভিযোজিত করে /etc/systemd/system/radicale.service তৈরি করুন:

[Unit]
Description=CalDAV and CardDAV server
After=network.target
Requires=network.target

[Service]
ExecStart=/opt/radicale/venv/bin/python -m radicale
Restart=on-failure
User=radicale
UMask=0027
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
NoNewPrivileges=true
ReadWritePaths=/var/lib/radicale/

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now radicale
curl -i http://127.0.0.1:5232/

একটি সঠিক ফলাফল হলো 401 Unauthorized এবং সাথে একটি WWW-Authenticate হেডার: সার্ভিসটি লিসেন করছে এবং অথেন্টিকেশন চালু আছে। Connection refused মানে এটি কখনোই শুরু হয়নি, এবং journalctl -u radicale -n 50 সেই অপশনটির নাম বলে যা এটি প্রত্যাখ্যান করেছে। ProtectSystem=strict এই সার্ভিসের জন্য ফাইলসিস্টেমকে রিড-অনলি হিসেবে মাউন্ট করে, তাই ReadWritePaths=/var/lib/radicale/ হলো সেই লাইন যা এটিকে ইভেন্ট সেভ করার অনুমতি দেয়। সেই লাইনটি বাদ দিলে রিড কাজ করবে কিন্তু সব রাইট অপারেশন ব্যর্থ হবে।

TLS ঐচ্ছিক নয়, কারণ ক্লায়েন্টরা প্লেইনটেক্সট গ্রহণ করে না

CalDAV, HTTP Basic ব্যবহার করে প্রমাণীকরণ (authentication) সম্পন্ন করে, যা প্রতিটি অনুরোধের সাথে user:password বেস64 (base64) এনকোড করা তথ্য পাঠায়। বেস64 একটি এনকোডিং, এনক্রিপশন নয়। প্লেইন HTTP ব্যবহার করলে আপনি ফোন এবং সার্ভারের মধ্যবর্তী প্রতিটি নেটওয়ার্ককে আপনার পাসওয়ার্ড দিয়ে দিচ্ছেন, যা সারাদিন প্রতিটি সিঙ্কের সময় ঘটে।

ক্লায়েন্টরা আপনার জন্য এটি বাধ্যতামূলক করে। Radicale-এর ডকুমেন্টেশনে উল্লেখ আছে যে, macOS Calendar.app অনিরাপদ HTTP-এর মাধ্যমে ক্রেডেনশিয়াল পাঠাতে নীরবে অস্বীকার করতে পারে এবং iOS-এর আচরণও একই রকম। অ্যাকাউন্টটি কনফিগার করা হয়েছে বলে মনে হলেও এটি কখনোই সিঙ্ক হয় না এবং কোনো ত্রুটির বার্তাও দেখায় না।

প্রথমে cal.example.com-এর জন্য একটি A রেকর্ড VPS-এর দিকে নির্দেশ করুন, কারণ সার্টিফিকেট অথরিটি এটি যাচাই করে। এরপর /etc/nginx/sites-available/cal.example.com তৈরি করুন:

server {
    listen 80;
    server_name cal.example.com;

    location / {
        proxy_pass        http://localhost:5232/;
        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header  X-Forwarded-Proto $scheme;
        proxy_set_header  Host $http_host;
        proxy_pass_header Authorization;
    }

    location = /.well-known/caldav  { return 301 https://$host/; }
    location = /.well-known/carddav { return 301 https://$host/; }
}

চারটি প্রক্সি হেডার লাইন Radicale-এর ডকুমেন্টেশন থেকে নেওয়া হয়েছে। এগুলো যেভাবে আছে সেভাবেই রাখুন।

sudo ln -s /etc/nginx/sites-available/cal.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d cal.example.com
curl -i -u you https://cal.example.com/

nginx -t কমান্ডটি syntax is ok এবং test is successful প্রদর্শন করে। এটি নিশ্চিত হওয়ার পরেই রিলোড করুন, কারণ ভুল ফাইলসহ রিলোড করলে পুরনো কনফিগারেশনই চলতে থাকে এবং পরবর্তী রিস্টার্ট পর্যন্ত ভুলটি ধরা পড়ে না। Certbot সরাসরি সাইট ফাইলটি এডিট করে: এটি সার্টিফিকেট ইনস্টল করে, ব্লকটিকে পোর্ট 443-এ সরিয়ে নেয় এবং পোর্ট 80 থেকে একটি রিডাইরেক্ট যোগ করে। চূড়ান্ত curl কমান্ডটি পাসওয়ার্ড চাইবে এবং এর আউটপুট হিসেবে 200 আসা উচিত, যা Radicale-এর নিজস্ব ওয়েব ইন্টারফেস। 502 Bad Gateway আসার অর্থ হলো Nginx চলছে কিন্তু Radicale পোর্ট 5232-এ লিসেন করছে না।

ফোনে অ্যাকাউন্ট যোগ করার সময় ব্যর্থ হয় কেন?

এর কারণ হলো discovery। RFC 6764-এ বর্ণনা করা হয়েছে কীভাবে একটি ক্লায়েন্ট একটি hostname-কে ক্যালেন্ডার URL-এ রূপান্তর করে। এটি প্রথমে একটি _caldavs._tcp SRV রেকর্ড খোঁজে, তারপর https://cal.example.com/.well-known/caldav-এর জন্য অনুরোধ পাঠায় এবং DAV root-এ একটি redirect আশা করে। সেখান থেকে এটি current-user-principal-এর জন্য অনুরোধ করে, তারপর সেই principal-এর calendar-home-set-এর জন্য অনুরোধ করে, এবং কেবল তখনই এটি আপনার ক্যালেন্ডারগুলো দেখতে পায়। একটি ফোনে সার্ভারের জন্য মাত্র একটি ফিল্ড থাকে, তাই প্রতিটি ধাপকে কোনো হস্তক্ষেপ ছাড়াই কাজ করতে হয়।

curl -sI https://cal.example.com/.well-known/caldav

সঠিক উত্তরটি হলো HTTP/2 301, যার সাথে একটি location: https://cal.example.com/ হেডার থাকে। সেখানে একটি 404 থাকার কারণেই iOS বলে যে এটি অ্যাকাউন্টের তথ্য যাচাই করতে পারছে না, অথচ একই নেটওয়ার্কে থাকা Thunderbird কাজ করে: Thunderbird আপনার টাইপ করা সম্পূর্ণ URL ব্যবহার করে, তাই এটির কখনোই redirect-এর প্রয়োজন হয় না।

redirect-এর লক্ষ্য সার্ভারের ওপর নির্ভর করে। সাইটের root-এ থাকা Radicale, /-এ redirect করে। Baikal-এর সাথে কিছু নমুনা রুল থাকে যা 308 স্ট্যাটাসসহ /dav.php-এ redirect করে। Nextcloud, /remote.php/dav/-এ redirect করে।

ক্যালেন্ডার তৈরি করুন এবং আপনার সঙ্গীর সাথে একটি শেয়ার করুন

অনেক ক্লায়েন্ট ক্যালেন্ডার তৈরি করতে পারে না, শুধুমাত্র সাবস্ক্রাইব করতে পারে। ব্রাউজারে https://cal.example.com/ খুলুন, you হিসেবে লগ ইন করুন এবং সেখানে ক্যালেন্ডারটি তৈরি করুন। ডিস্কে এটি /var/lib/radicale/collections/collection-root/you/-এর অধীনে জমা হয়, যেখানে ফোল্ডারের নামের জন্য একটি জেনারেটেড আইডেন্টিফায়ার থাকে।

Radicale-এর ডিফল্ট রাইটস ব্যাকএন্ড হলো owner_only: একটি অথেন্টিকেটেড অ্যাকাউন্ট শুধুমাত্র /USERNAME/-এর অধীনে তার নিজস্ব কালেকশন পড়তে এবং লিখতে পারে, অন্য কিছু নয়। বেশিরভাগ পরিবারের জন্য এটিই সঠিক সেটিংস এবং ক্যালেন্ডার শেয়ার করার সবচেয়ে সহজ উপায় হলো একটি তৃতীয় অ্যাকাউন্ট ব্যবহার করা। htpasswd দিয়ে household তৈরি করুন, সেই লগইনের অধীনে শেয়ার করা ক্যালেন্ডারটি তৈরি করুন এবং প্রতিটি ডিভাইসে এটিকে দ্বিতীয় CalDAV অ্যাকাউন্ট হিসেবে যোগ করুন। এটি iOS সহ প্রতিটি ক্লায়েন্টে কাজ করে, কারণ ক্যালেন্ডারটি সেই অ্যাকাউন্টের নিজস্ব হোমে থাকে।

যখন আপনি আরও সূক্ষ্ম নিয়ন্ত্রণ চান, তখন রুল-ভিত্তিক রাইটসে স্যুইচ করুন। /etc/radicale/config-এ এটি যোগ করুন:

[rights]
type = from_file
file = /etc/radicale/rights

তারপর, Radicale ডকুমেন্টেশনের উদাহরণ অনুযায়ী /etc/radicale/rights করুন:

[root]
user: .+
collection:
permissions: R

[principal]
user: .+
collection: {user}
permissions: RW

[own-calendars]
user: .+
collection: {user}/[^/]+
permissions: rw

[shared-household]
user: you|partner
collection: you/2f0a9c1e-1f4c-4c2b-9a1b-0d2f7a5c9e11
permissions: rw

বড় হাতের অক্ষর এবং ছোট হাতের অক্ষরের অর্থ ভিন্ন। R এবং W এমন কালেকশন পড়ে এবং লেখে যা ক্যালেন্ডার বা অ্যাড্রেস বুক নয়, যা মূলত একটি প্রিন্সিপাল ফোল্ডার। r এবং w ক্যালেন্ডারগুলো নিজে পড়ে এবং লেখে। উপরের স্টোরেজ পাথ থেকে আপনার ক্যালেন্ডারের আসল ফোল্ডারের নাম দিয়ে সেই আইডেন্টিফায়ারটি প্রতিস্থাপন করুন।

একটি সীমাবদ্ধতা হলো: যে ক্লায়েন্ট শুধুমাত্র ক্যালেন্ডার হোম সেট পড়ে, সেটি অন্য ব্যবহারকারীর পাথে থাকা ক্যালেন্ডার প্রদর্শন করবে না, কারণ ডিসকভারি সেখানে যায় না। Thunderbird এবং DAVx⁵ সম্পূর্ণ URL ব্যবহার করে এটি যোগ করতে পারে। iOS তা পারে না, আর এই কারণেই শেয়ার করা অ্যাকাউন্টের পদ্ধতিটি সবসময় কাজ করে।

ক্লায়েন্ট সেটআপ করুন, কারণ এখানেই self-hosted ক্যালেন্ডার ব্যবহারের সমাপ্তি ঘটে

iPhone এবং iPad। Settings খুলুন, তারপর Calendar (সাম্প্রতিক iOS ভার্সনে এটি Apps-এর অধীনে থাকে), তারপর Calendar Accounts, Add Account, Other, Add CalDAV Account-এ যান। Server হিসেবে cal.example.com দিন, এরপর ব্যবহারকারীর নাম ও পাসওয়ার্ড লিখুন। Description শুধুমাত্র একটি লেবেল। যদি এটি সেভ না হয়, তবে অ্যাকাউন্টটি আবার খুলুন: advanced ভিউতে Use SSL, port এবং সম্পূর্ণ account URL দেখা যাবে; URL-টি পেস্ট করলে তা সরাসরি discovery প্রক্রিয়া এড়িয়ে যাবে।

Android। এতে কোনো বিল্ট-ইন CalDAV ক্লায়েন্ট নেই। F-Droid বা Google Play থেকে DAVx⁵ ইনস্টল করুন, আপনার ব্যবহারকারীর নামসহ https://cal.example.com/ বেস URL ব্যবহার করে একটি অ্যাকাউন্ট যোগ করুন, তারপর আপনার প্রয়োজনীয় ক্যালেন্ডারগুলো টিক দিন। DAVx⁵ সরাসরি Android ক্যালেন্ডার প্রোভাইডারে তথ্য লেখে, তাই আপনার ব্যবহৃত যেকোনো ক্যালেন্ডার অ্যাপেই ইভেন্টগুলো দেখা যাবে।

Thunderbird। New Calendar, On the Network, তারপর আপনার ব্যবহারকারীর নাম এবং https://cal.example.com/ লোকেশন দিন। এটি কী কী খুঁজে পেয়েছে তার তালিকা দেখাবে এবং কোন ক্যালেন্ডারগুলো যোগ করতে হবে তা জানতে চাইবে।

macOS। System Settings, Internet Accounts, Add Other Account, CalDAV-এ যান, Account Type ম্যানুয়াল হিসেবে সেট করুন, তারপর একই ব্যবহারকারীর নাম, পাসওয়ার্ড এবং সার্ভার অ্যাড্রেস দিন।

CalDAV একটি পোলিং প্রোটোকল। এর স্পেসিফিকেশনে কোনো পুশ (push) সুবিধা নেই, তাই ল্যাপটপে কোনো ইভেন্ট যোগ করলে তা সাথে সাথে ফোনে না এসে পরবর্তী সিঙ্ক-এর সময় আসবে। প্রতিটি ক্লায়েন্টে এমন একটি বিরতি (interval) সেট করুন যা আপনার জন্য সুবিধাজনক, তবে মনে রাখবেন ফোনে বিরতির সময় কম হলে ব্যাটারি বেশি খরচ হয়।

স্টোর ব্যাকআপ নিন, যা কেবল কিছু ফাইল

Radicale-এ আপনার ক্যালেন্ডার হলো .ics ফাইলের একটি ডিরেক্টরি, যেখানে প্রতিটি ইভেন্টের জন্য একটি করে ফাইল থাকে এবং প্রতিটি কালেকশনের জন্য একটি ছোট প্রপার্টি ফাইল থাকে। ডিরেক্টরি কপি করতে পারে এমন যেকোনো টুল দিয়েই আপনি ব্যাকআপ নিতে পারেন এবং ব্যাকআপটি ঠিকঠাক আছে কি না তা নিশ্চিত করতে less দিয়ে ফাইলগুলো খুলে দেখতে পারেন। ডাটাবেস ডাম্পের তুলনায় এটি একটি বড় সুবিধা, কারণ ডাটাবেস ডাম্প সরাসরি পড়া যায় না।

sudo systemctl stop radicale
sudo tar czf /root/radicale-$(date +%F).tar.gz -C /var/lib/radicale collections
sudo systemctl start radicale

আর্কাইভ তৈরির কয়েক সেকেন্ডের জন্য সার্ভিসটি বন্ধ রাখুন, যাতে ফাইল পড়ার সময় কোনো ক্লায়েন্ট রাইট অপারেশনের মাঝপথে আটকে না থাকে। আর্কাইভটি এরপর সার্ভার থেকে সরিয়ে অন্য কোথাও কপি করে রাখুন, কারণ একই VPS-এ রাখা ব্যাকআপ সার্ভার ফেইল করলে কোনো কাজে আসবে না। রিস্টোর করার প্রক্রিয়াটি হলো উল্টো: ফাইল এক্সট্র্যাক্ট করুন, sudo chown -R radicale:radicale /var/lib/radicale/collections করুন এবং সার্ভিসটি চালু করুন। প্রতিটি ক্লায়েন্টের কাছেও তাদের ক্যালেন্ডারের একটি লোকাল কপি থাকে, তাই ফেইল হওয়ার পর যে ল্যাপটপটি সিঙ্ক করেনি, সেটি আপনার ডাটার দ্বিতীয় কপি হিসেবে কাজ করবে।

কখন Baikal বা Nextcloud বেশি উপযোগী

Baikal 0.12.1 সংস্করণটি 5 আগস্ট 2026-এ মুক্তি পেয়েছে এবং এর জন্য PHP 8.2 বা তার পরবর্তী সংস্করণ প্রয়োজন। এটিকে web root-এর বাইরে আনপ্যাক করুন এবং শুধুমাত্র এর html ডিরেক্টরিটিকে উন্মুক্ত রাখুন:

sudo apt install -y php-fpm php-sqlite3 php-xml php-mbstring php-curl unzip
cd /tmp
curl -LO https://github.com/sabre-io/Baikal/releases/download/0.12.1/baikal-0.12.1.zip
sudo unzip -q baikal-0.12.1.zip -d /srv
sudo chown -R www-data:www-data /srv/baikal/Specific /srv/baikal/config

এই দুটি ডিরেক্টরিই কেবল web server দ্বারা রাইট করা হয়, তাই অন্য কোনো কিছু রাইট করার অনুমতি দেওয়ার প্রয়োজন নেই। আপনার nginx server block-এর ভেতরে Baikal-এর জন্য নির্দিষ্ট অংশগুলো হলো:

root /srv/baikal/html;
index index.php;

location ~ /(\.ht|Core|Specific|config) { deny all; }

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

location = /.well-known/caldav  { return 308 /dav.php; }
location = /.well-known/carddav { return 308 /dav.php; }

nginx রিলোড করুন, ব্রাউজারে সাইটটি ওপেন করুন, এবং সেটআপ উইজার্ডটি অ্যাডমিন অ্যাকাউন্ট ও SQLite ডাটাবেস তৈরি করবে। ক্লায়েন্ট সেটআপ Radicale-এর মতোই, যেখানে সার্ভার অ্যাড্রেস হিসেবে https://cal.example.com/ ব্যবহার করতে হবে, কারণ well-known রুলটি ডিসকভারি রিকোয়েস্টকে /dav.php-এ পাঠিয়ে দেয়।

Nextcloud তখনই কার্যকর হয় যদি আপনি একই লগইনের অধীনে ফাইল এবং ফোন অ্যাপও ব্যবহার করতে চান। এর DAV রুট হলো /remote.php/dav/, এবং একই ডিসকভারি রুল এখানেও প্রযোজ্য। এগুলোর যেকোনোটি ব্যবহারের ক্ষেত্রে, সার্ভিসটিকে কন্টেইনারে চালালে আপনার হোস্ট মেশিনের PHP ভার্সনের সাথে কোনো সংঘর্ষ হবে না: Docker Compose on a VPS-এ compose ফাইল এবং এর সামনের reverse proxy সম্পর্কে আলোচনা করা হয়েছে, এবং what is worth self-hosting in 2026 নিবন্ধটি আপনাকে সিদ্ধান্ত নিতে সাহায্য করবে যে আপনি এই পথে কতদূর এগিয়ে যেতে চান।

ব্যর্থতার ধরন এবং যে বার্তাগুলো আপনি দেখবেন

প্রতিটি সিঙ্ক 401 (401) এরর দেয়। হয় পাসওয়ার্ড ফাইলে থাকা অ্যাকাউন্টগুলো অন্য কোনো htpasswd -c এর কারণে মুছে গেছে, অথবা radicale ব্যবহারকারী ফাইলটি পড়তে পারছে না। sudo -u radicale cat /etc/radicale/users দিয়ে পরীক্ষা করুন; যদি 'permission denied' দেখায় তবে সেটিই আপনার সমস্যার কারণ। সমাধান হলো ফাইলটিকে radicale গ্রুপে রাখা এবং মোড 640 (640) সেট করা। Radicale ডিফল্টভাবে প্রতিটি ব্যর্থ লগইনের পর এক সেকেন্ড অপেক্ষা করে, তাই পুরনো পাসওয়ার্ড ব্যবহারকারী ক্লায়েন্টকে রিজেক্ট হওয়ার বদলে ধীরগতির মনে হতে পারে।

PROPFIND এর জন্য nginx 405 (405) এরর দেয়। URL-টিকে একটি স্ট্যাটিক ফাইল হিসেবে পরিবেশন করা হচ্ছে, তাই WebDAV মেথডটি Radicale পর্যন্ত পৌঁছাতে পারছে না। এন্ডপয়েন্টটি সরাসরি পরীক্ষা করুন:

curl -u you -X PROPFIND -H "Depth: 0" -i https://cal.example.com/you/

একটি কার্যকর DAV কালেকশন 207 Multi-Status উত্তর দেয়। অন্য যেকোনো কিছু আসার অর্থ হলো অনুরোধটি ওয়েব সার্ভারেই আটকে গেছে।

ফোন অ্যাকাউন্ট যাচাই করতে পারছে না, কিন্তু ব্রাউজারে ঠিকঠাক কাজ করছে। এর দুটি সাধারণ কারণ থাকে। ওয়েল-নোন রিডাইরেক্ট (well-known redirect) অনুপস্থিত, যা উপরের curl কমান্ড দিয়ে পরীক্ষা করা যায়। অথবা সার্টিফিকেট চেইন অসম্পূর্ণ, যা ব্রাউজারগুলো স্বয়ংক্রিয়ভাবে ইন্টারমিডিয়েট সার্টিফিকেট খুঁজে ঠিক করে নেয়, কিন্তু iOS তা করে না। শেল থেকে এটি পরীক্ষা করুন:

openssl s_client -connect cal.example.com:443 -servername cal.example.com </dev/null

Verify return code: 0 (ok) খুঁজুন। যদি এটি ব্যর্থ হয়, তবে nginx কনফিগারেশন cert.pem কে নির্দেশ করছে যেখানে এটিকে fullchain.pem কে নির্দেশ করা উচিত ছিল।

ইমপোর্টের পর ইভেন্ট ডুপ্লিকেট হয়ে যায়। প্রতিটি ইভেন্টের একটি UID থাকে এবং ক্লায়েন্টরা সেটিকে পরিচয় হিসেবে গণ্য করে। একই ফাইল এমন কোনো টুলের মাধ্যমে দুবার ইমপোর্ট করলে যা আইডেন্টিফায়ার নতুন করে তৈরি করে, তখন দুটি ইভেন্ট তৈরি হয় যা আর কখনো মার্জ হবে না। একটি ডিভাইস থেকে অতিরিক্ত কপিগুলো মুছে ফেলুন এবং ডিলিট সিঙ্ক হতে দিন।

রিবুটের পর সবকিছু কাজ করা বন্ধ করে দেয়। সার্ভিসটি ম্যানুয়ালি চালু করা হয়েছিল। sudo systemctl is-enabled radicale কমান্ডটি disabled প্রিন্ট করে, এবং sudo systemctl enable --now radicale কমান্ডটি স্থায়ীভাবে সমস্যার সমাধান করে।

FAQ

আমার কি সত্যিই একটি self-hosted CalDAV সার্ভারের জন্য TLS প্রয়োজন?

হ্যাঁ। CalDAV সার্ভার HTTP Basic authentication ব্যবহার করে, তাই প্রতিটি অনুরোধের সাথে পাসওয়ার্ড base64 এনকোড হয়ে যায় এবং base64 সহজেই ডিকোড করা সম্ভব। ক্লায়েন্ট অ্যাপগুলোও এটি বাধ্যতামূলক করে: macOS Calendar.app অনিরাপদ HTTP-তে ক্রেডেনশিয়াল পাঠাতে অস্বীকার করতে পারে এবং iOS-এর ক্ষেত্রেও একই ঘটনা ঘটে, ফলে অ্যাকাউন্টটি সেভ হলেও সিঙ্ক হয় না। sudo certbot --nginx -d cal.example.com ব্যবহার করাই এক্ষেত্রে একমাত্র সমাধান।

Thunderbird কাজ করলেও আমার ফোন কেন অ্যাকাউন্ট যোগ করতে ব্যর্থ হচ্ছে?

Thunderbird আপনার দেওয়া পূর্ণ URL ব্যবহার করে। ফোন আপনাকে শুধুমাত্র একটি সার্ভার ফিল্ড দেয়, তাই এটি RFC 6764 ডিসকভারি অনুসরণ করে: এটি https://cal.example.com/.well-known/caldav-এর জন্য অনুরোধ পাঠায় এবং DAV রুটে একটি রিডাইরেক্ট আশা করে। এই রিডাইরেক্ট না থাকলে ফোনটি 404 এরর পায় এবং অ্যাকাউন্ট যাচাই করতে পারে না। nginx-এ location = /.well-known/caldav { return 301 https://$host/; } যোগ করুন, তারপর curl -sI https://cal.example.com/.well-known/caldav দিয়ে নিশ্চিত করুন যে আপনি একটি 301 রেসপন্স এবং একটি location হেডার পাচ্ছেন।

দুইজন কি একটি ক্যালেন্ডার শেয়ার করতে পারে?

হ্যাঁ, এর সবচেয়ে নির্ভরযোগ্য উপায় হলো একটি শেয়ার্ড লগইন ব্যবহার করা। htpasswd দিয়ে একটি তৃতীয় অ্যাকাউন্ট তৈরি করুন, শেয়ার্ড ক্যালেন্ডারটি তার অধীনে রাখুন এবং প্রতিটি ডিভাইসে দ্বিতীয় CalDAV অ্যাকাউন্ট হিসেবে সেটি যোগ করুন। Radicale-এর রাইটস ফাইলে অন্য ব্যবহারকারীর পাথের অধীনে কোনো কালেকশনে নির্দিষ্ট ব্যবহারকারীকে read এবং write পারমিশন দেওয়া যায়, কিন্তু যে ক্লায়েন্ট শুধুমাত্র তার নিজস্ব ক্যালেন্ডার হোম সেট পড়ে, সেটি এটি প্রদর্শন করবে না। তাই এই পদ্ধতিটি iOS-এর চেয়ে Thunderbird এবং DAVx⁵-এর জন্য বেশি উপযোগী।

VPS নষ্ট হয়ে গেলে আমার ইভেন্টগুলোর কী হবে?

Radicale-এর ক্ষেত্রে ডেটা সাধারণ টেক্সট ফরম্যাটে থাকে: /var/lib/radicale/collections/collection-root/ পাথের অধীনে প্রতিটি ইভেন্টের জন্য একটি করে .ics ফাইল থাকে, যা আপনি tar দিয়ে ব্যাকআপ নিতে পারেন এবং less দিয়ে পড়তে পারেন। রিস্টোর করার প্রক্রিয়া হলো ফাইলগুলো এক্সট্র্যাক্ট করা, chown -R radicale:radicale চালানো এবং সার্ভিসটি চালু করা। প্রতিটি সিঙ্ক করা ক্লায়েন্টের কাছেও একটি লোকাল কপি থাকে, তাই সার্ভার নষ্ট হওয়ার আগে যে ল্যাপটপটি আপ-টু-ডেট ছিল, তাতে আপনার ক্যালেন্ডারের একটি পূর্ণাঙ্গ কপি সংরক্ষিত থাকে।

CalDAV সার্ভার কি আমার কন্টাক্টগুলোও সিঙ্ক করে?

কন্টাক্টের জন্য CardDAV ব্যবহৃত হয়, যা RFC 6352-এ সংজ্ঞায়িত একটি প্রোটোকল এবং এটি ইভেন্টের পরিবর্তে vCard ফাইল সংরক্ষণ করে। Radicale, Baikal এবং Nextcloud একই অ্যাকাউন্ট এবং একই হোস্টনাম থেকে এটি সার্ভ করে। Android-এ, DAVx⁵ একই অ্যাকাউন্ট থেকে ক্যালেন্ডার এবং কন্টাক্ট সিঙ্ক করে। iOS-এ আপনাকে একই ক্রেডেনশিয়াল ব্যবহার করে CardDAV টাইপের একটি দ্বিতীয় অ্যাকাউন্ট যোগ করতে হয়, আর এই কারণেই /.well-known/carddav রিডাইরেক্টটি আপনার nginx কনফিগারেশনে CalDAV-এর পাশাপাশি থাকা প্রয়োজন।

#caldav#calendar#radicale#self-hosting#sync