- Key Features
- Screenshots
- Quick Start
- Management
- Configuration
- Reverse Proxy Templates
- Security
- Architecture
- Project Structure
- Disclaimer
- Support
- License
"What words would you leave behind?"
Aeterna is a dead man's switch. You write messages. You check in regularly. If you stop checking in, your messages are delivered.
It's that simple. And that important.
Aeterna holds these words. It watches. It waits. And when the time comes, it delivers.
- Email Delivery: Automatic delivery of your messages and files to your loved ones if you fail to check in.
- Webhook Integration: Trigger external services (home automation, custom scripts, etc.) when your switch is activated.
- File Attachments: Securely attach sensitive documents, photos, or instructions to your switches.
- Auto-Cleanup: Attachments are automatically deleted from the server immediately after delivery for maximum privacy.
- One-Click Install: Comprehensive installation wizard.
- Heartbeat System: Simple check-in mechanism via web UI or a quick-link from your email.
- Privacy-Focused Architecture: Messages and attachments are encrypted at rest (AES-256-GCM) on your private server, ensuring they are only decrypted at the moment of delivery.
Dashboard |
Creating a Switch |
Settings |
git clone https://github.com/alpyxn/aeterna.git
cd aeterna
./install.shIf you prefer not to use the automated installation script, you can deploy Aeterna directly with our published Docker images.
-
Create a new folder and move into it:
mkdir -p aeterna && cd aeterna
-
Create required directories and encryption key:
mkdir -p data secrets openssl rand -base64 32 | tr -d '\n' > secrets/encryption_key chmod 600 secrets/encryption_key
-
Create
.env:SERVER_IP="$(curl -4fsS ifconfig.me || curl -4fsS icanhazip.com || true)" if [ -z "$SERVER_IP" ]; then echo "Could not detect public IPv4 automatically. Set SERVER_IP manually." >&2 exit 1 fi cat > .env <<EOF # Use your public domain (recommended) or server IP DOMAIN=${SERVER_IP} ENV=production VITE_API_URL=/api # Must match exactly what you open in the browser ALLOWED_ORIGINS=http://${SERVER_IP}:5000,http://localhost:5000,http://127.0.0.1:5000 BASE_URL=http://${SERVER_IP}:5000 PROXY_MODE=simple EOF
Notes:
- If you use a domain, set:
ALLOWED_ORIGINS=https://your-domainBASE_URL=https://your-domain
ALLOWED_ORIGINSmust include the exact origin shown in your browser address bar (scheme + host + port).
-
Create
docker-compose.ymlusing package images:services: backend: image: ghcr.io/alpyxn/aeterna-backend:main env_file: - .env environment: - DATABASE_PATH=/app/data/aeterna.db - ENV=production - ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-*} - BASE_URL=${BASE_URL:-http://${DOMAIN}:5000} command: ["./main", "--encryption-key-file=/run/secrets/encryption_key"] secrets: - encryption_key volumes: - ./data:/app/data restart: always networks: - aeterna-net frontend: image: ghcr.io/alpyxn/aeterna-frontend:main depends_on: - backend restart: always networks: - aeterna-net proxy: image: nginx:alpine ports: - "5000:80" volumes: - ./proxy-simple.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - backend - frontend restart: always networks: - aeterna-net secrets: encryption_key: file: ./secrets/encryption_key networks: aeterna-net: driver: bridge
-
Create
proxy-simple.conf:server { listen 80; server_name localhost; resolver 127.0.0.11 valid=30s; set $backend_upstream http://backend:3000; location / { proxy_pass http://frontend:80; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /api/ { proxy_pass $backend_upstream; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
-
Start the stack:
docker compose up -d
-
Open Aeterna:
If you prefer Docker Hub, replace image names with:
docker.io/alpyxn/aeterna-backend:maindocker.io/alpyxn/aeterna-frontend:main
During installation, you will be prompted to choose a mode:
-
Production (Reverse Proxy + SSL) - Recommended
- Specifically configured to work with Nginx and Let's Encrypt automatically via the script.
- You can also adapt this for Caddy, Apache, or Traefik.
- Secure headers and configuration
-
Development (Simple) - Not Recommended for Production
- Runs directly on port 5000 (IP address only)
- No encryption/SSL - insecure for sensitive data
- Useful only for local testing or development
The install.sh script includes management commands:
| Command | Description |
|---|---|
./install.sh --update |
Update to the latest version |
./install.sh --backup |
Create a full backup of data and config |
./install.sh --status |
Check service health and status |
./install.sh --uninstall |
Remove containers and installation |
The installer guides you through basic configuration:
- Domain: Your domain name (required for SSL)
- Encryption: Automatically generates a unique AES-256 key
SMTP Settings (required for sending emails) are configured post-installation through the application's Settings menu. This allows for live testing and easier management.
Ready-to-use examples for Nginx, Traefik, and Caddy are available in:
This document also includes required .env values (ALLOWED_ORIGINS, BASE_URL) and deployment notes.
Aeterna handles security automatically:
- Encryption: Messages and file attachments are encrypted at rest using AES-256-GCM.
- Key Management: The encryption key is generated securely and stored in
secrets/encryption_key. It is never exposed in environment variables or configuration files. - Data Pruning: File attachments are permanently deleted from the disk after successful delivery to the recipient.
- SSL: Automatic certificate management via Let's Encrypt (in Production mode).
backend/ Go API server
frontend/ React application
Both components can run in Docker containers or natively. SQLite is used for storage (single file database). You can use any reverse proxy (proxy, caddy, apache) to serve them together and provide SSL.
.
├── assets/ # Images and design assets
├── backend/ # Go source code
│ ├── cmd/ # Entry points (main.go)
│ └── internal/ # Core business logic, handlers, and services
├── frontend/ # React frontend source
│ ├── src/ # Components, pages, and hooks
│ └── public/ # Static assets for the web
├── secrets/ # Encryption keys (ignored by git)
├── docker-compose.* # Deployment various configurations
└── install.sh # Automated installation scriptAeterna deals with sensitive data and high-stakes outcomes (automated delivery if you stop checking in). Read the full disclaimer for limitations of liability, your responsibilities for deployment and compliance, and what the software does not guarantee.
💖 Support the Project
If you find this project useful, consider supporting its development. Every contribution is greatly appreciated!
| Asset | Network | Address |
|---|---|---|
| Bitcoin (BTC) | Bitcoin | bc1qtusxvc2agmvz88f5h7avznvrqmgl50tewj7h3u |
| Solana (SOL) | Solana | 7bJdCSZN8FUDXXUWDWkxjtS5oM6DGah8PQsXv1XomgWf |
| USDT | ERC-20 / BEP-20 | 0x5102Ca44De2dF3c1f6711a70076EAa3e5f0fD1c8 |
| Monero (XMR) | Monero | 87U6EcarbbWUkVh15DeGSjEVkrhprbGR9ieAzHpYDivVi2WJK64sUWDDSpdqH5UFdDcpKgkXShTvVAFAbPJ4f7YYFvgaAku |
GPL-3.0
Named for the Latin word meaning "eternal" — because some messages are meant to outlast us.
