# Ghost to WriteFreely: Migration to the Fediverse ![Person tippt auf Laptop-Tastatur neben Kaffeetasse mit Kingston-Aufdruck, Monitor zeigt Rocket Book Academy Website](/content/images/from-ghost-to-writefreely-my-migration-to-the-fediverse/blogging.webp) ## Why WriteFreely? After years with various blogging platforms, I was looking for something **simpler**. Ghost was great, but: ✅ **Native ActivityPub Integration** - My blog is automatically available in the Fediverse ✅ **Minimal Resource Usage** - Single binary, no Node.js, no complex infrastructure ✅ **Focus on Writing** - No distractions, just writing ✅ **Self-hosted** - Full control over my data ✅ **Markdown-native** - No formatting battles ## Setup: WriteFreely on LXC (Proxmox) ### Why Native Installation Instead of Docker? After several frustrating hours with Docker mount problems, I decided on native installation. **Best decision ever!** ```bash # Download WriteFreely binary cd /opt wget tar -xzf writefreely_0.15.0_linux_arm64.tar.gz mv writefreely /opt/writefreely cd /opt/writefreely # Interactive configuration ./writefreely --config ``` ### Configuration (config.ini) ```bash [server] bind = 0.0.0.0 # Important for reverse proxy port = 8080 https = false # Reverse proxy handles HTTPS [app] site_name = My Blog host = # Your real domain! single_user = true federation = true # This is the key! public_registration = false [database] type = sqlite3 # Simpler than MySQL for single user filename = writefreely.db ``` ### As systemd Service ```bash # Create service file sudo tee /etc/systemd/system/writefreely.service << 'EOF' [Unit] Description=WriteFreely After=network.target [Service] Type=simple User=www-data Group=www-data WorkingDirectory=/opt/writefreely ExecStart=/opt/writefreely/writefreely Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable writefreely sudo systemctl start writefreely ``` ### Reverse Proxy (Traefik/Nginx) Example configuration: - **Frontend**: `blog.example.com` - **Backend**: `http://192.168.1.100:8080` - **SSL**: Automatic ## Migration from Ghost ### Export from Ghost Ghost Admin → Settings → Labs → "Export content" ### Migration Script (Python) Since WriteFreely's import features are limited, I migrated most posts manually. For automatic migration: ```python #!/usr/bin/env python3 import json import requests from datetime import datetime def migrate_ghost_to_writefreely(ghost_export, writefreely_url, token): with open(ghost_export, 'r') as f: data = json.load(f) posts = data['db'][0]['data']['posts'] for post in posts: if post['status'] == 'published': # WriteFreely API Call payload = { 'body': convert_html_to_markdown(post['html']), 'title': post['title'] } # ... API integration ``` **My tip**: For small blogs (< 20 posts), manual copying is often faster and cleaner. ## Custom CSS: The Perfect Dark Theme After many iterations, here's my final WriteFreely dark theme: ```css /* WriteFreely Custom Dark Theme */ /* === SANS-SERIF FONT === */ body, html, * { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif !important; } /* === ANTHRACITE DESIGN === */ body, html { background: #2e2e2e !important; color: #f0f0f0 !important; } /* === COLORED HEADING HIERARCHY === */ body h1 { color: #ffffff !important; font-size: 1.8rem !important; } body h2 { color: #7db3f3 !important; font-size: 1.5rem !important; } body h3 { color: #98d982 !important; font-size: 1.3rem !important; } body h4 { color: #f9cc81 !important; font-size: 1.2rem !important; } /* === LINKS === */ body a { color: #7db3f3 !important; } body a:hover { color: #98d982 !important; } /* === CODE BOXES (This was a battle!) === */ body pre { background: #1e1e1e !important; color: #f0f0f0 !important; border: 1px solid #444 !important; border-radius: 8px !important; padding: 1rem !important; } body code { background: #1e1e1e !important; color: #f0f0f0 !important; border: 1px solid #444 !important; border-radius: 8px !important; padding: 0.2rem 0.4rem !important; } /* === IMAGES WITH ROUNDED CORNERS === */ body img { border-radius: 12px !important; max-width: 100% !important; } /* === REMOVE FOOTER === */ body footer { display: none !important; } ``` ### HTML Shortcuts for Beautiful Images For consistent image presentation, I use these HTML shortcuts: ```html Description
Description
Caption here
``` ## ActivityPub: Automatically in the Fediverse The best thing about WriteFreely: **It just works!** - **My blog**: `@username@blog.example.com` - **Followers**: Automatically via Mastodon, Pleroma, etc. - **Posts**: Automatically federated to the Fediverse - **Interaction**: Comments via ActivityPub possible ### Testing Federation ```bash # Test WebFinger curl # ActivityPub profile curl -H "Accept: application/activity+json" ``` ## Troubleshooting: Common Problems ### Problem 1: Code boxes stay white **Solution**: Edit WriteFreely's `write.css` directly: ```bash cd /opt/writefreely/static/css sudo nano write.css # Search for: background:#f8f8f8 # Replace with: background:#1e1e1e ``` ### Problem 2: CSS not applied **Solution**: Aggressively clear browser cache, test different browsers. ### Problem 3: ActivityPub doesn't work **Solution**: - `federation = true` in config.ini - `host = (not localhost!) - Reverse proxy configured correctly ## Webspace for Images Separate container for static assets: ```yaml # docker-compose.yml for webspace services: webspace: image: httpd:latest volumes: - ./webspace:/usr/local/apache2/htdocs labels: - "traefik.http.routers.webspace.rule=(Host(`cdn.example.com`))" # ... Additional labels ``` ## Conclusion: Is the Switch Worth It? **Definitely yes!** After migration: ✅ **Much faster** - Page loads lightning fast ✅ **Less maintenance** - One binary, no updates, no Node.js ✅ **Fediverse integration** - My posts automatically reach more people ✅ **Focus on writing** - No distractions from complex themes/plugins ✅ **Resource efficient** - Runs smoothly on small LXC ## Resources - **WriteFreely**: [https://writefreely.org](https://writefreely.org/) - **ActivityPub Plugin (WordPress)**: [https://wordpress.org/plugins/activitypub/](https://wordpress.org/plugins/activitypub/) - **Fediverse Test**: [https://fediverse.party](https://fediverse.party/) _Migration completed: ✅ Self-hosted, ✅ Fediverse-ready, ✅ Minimal & fast_