5.7 KiB
Eternity Project web server
A Dockerized publishing service for eternityproject.fi. It provides local accounts, password hashing, authenticated publishing, and owner-only post editing. Content is persisted to SQLite in a named Docker volume.
Run it
- Copy
.env.exampleto.envand replaceSECRET_KEYwith a long random string. - Build and start the service:
docker compose up --build -d
Open http://localhost:8000, create the first account, and publish a field note. The first request initializes the database automatically.
Posts can include one JPEG, PNG, or WebP image up to 8 MB. Images are converted to optimized WebP files in the persistent Docker data volume; the article shows a compact preview that opens full-size when selected.
Long posts can also include multiple ordered step images. Upload them under Step images, then place [[image:1]], [[image:2]], and so on directly in the article text where each repair step needs an image. Each step image supports an optional caption and opens full-size when selected.
Accounts and MFA
The initial administrator account is admin with password admin, as requested for first-run access. Sign in, scan the displayed QR code with any iPhone or Android TOTP authenticator, and change this password before exposing the service to the internet. New registrations are held for approval in Accounts; accepted users must enroll a TOTP authenticator before they can publish.
Secure the initial administrator
With the Docker service running, rotate the initial password locally. The command prompts for a new password without writing it to a file or command history. It also clears the old MFA binding so that the next administrator sign-in requires a new QR-based authenticator enrollment.
# Windows PowerShell
.\scripts\rotate-admin.ps1
# Linux, macOS, or any POSIX shell
sh ./scripts/rotate-admin.sh
After it prints ADMIN_PASSWORD_ROTATED_MFA_RESET, sign in as admin with the new password, scan the fresh QR code with an authenticator application, and enter its six-digit code to complete enrollment. Store the new password in a password manager.
Email and password recovery
Registration now requires an email address and a confirmation link before the account can sign in. Members can change their email address from the navigation; the current address remains active until the link sent to the new address is confirmed. Verification and password-reset links expire after 24 hours and one hour respectively, and can only be used once. Administrators can send the same recovery email to any approved member from Accounts.
All browser POST forms are protected by server-validated CSRF tokens.
Set PUBLIC_URL and the MAIL_* values in .env to send recovery emails. The SMTP account must support STARTTLS on the configured port. Review TODO.md before production deployment.
Configure SMTP delivery
- Copy
.env.exampleto.envif it does not exist. - Set
PUBLIC_URL=https://eternityproject.fi. - Enter the SMTP host, port, username, password or provider app password, and verified sender address. Use port
587for STARTTLS. - Rebuild the service so Compose applies the values:
docker compose up --build -d
- Confirm the SMTP connection, TLS handshake, and credentials without sending an email:
python ./scripts/check-smtp.py
The command prints SMTP_CONNECTION_OK only after the SMTP server accepts the STARTTLS connection and authenticates the configured account. It prints a clear configuration or connection error otherwise and never sends a message.
- Send a delivery test to an inbox you control:
python ./scripts/send-test-email.py --to you@example.com
The command works on Windows, Linux, and macOS. It prints SMTP_TEST_SENT_TO=<address> only after the SMTP server accepts the message. Confirm the message arrives, then use Forgot your password? in the application to verify a real reset email and link. The existing PowerShell alternative remains available as ./scripts/test-smtp.ps1 -To you@example.com.
SMTP connection and delivery have been verified for the current deployment environment.
Automated database backups
The portable backup tool creates a consistent snapshot from the running Docker service using SQLite's backup API. It retains the most recent 30 days by default; snapshots are stored in the ignored backups/ directory.
python ./scripts/backup-database.py
python ./scripts/verify-backup.py ./backups/eternity-YYYYMMDDTHHMMSSZ.db
The restore verification copies the selected snapshot to a temporary location, checks SQLite integrity, and reports the recovered user and post counts. It never changes the live database.
Schedule a daily backup from the project directory. Ensure the scheduler environment provides SECRET_KEY for Docker Compose interpolation, or use the same .env file used to start the service.
0 2 * * * cd /srv/docker-ep-blog-web-server && SECRET_KEY="$(grep '^SECRET_KEY=' .env | cut -d= -f2-)" python3 ./scripts/backup-database.py >> backups/backup.log 2>&1
On Windows, create a daily Task Scheduler task with Start in set to the project directory and this program/argument pair:
Program: python.exe
Arguments: .\scripts\backup-database.py
Run python ./scripts/verify-backup.py <backup-file> after the first scheduled backup and at least quarterly. Keep an encrypted copy of backups/ outside the Docker host.
Production notes
The current deployment runs behind an Nginx reverse proxy with TLS enabled for eternityproject.fi. Keep SECRET_KEY strong and unique; the Compose file intentionally refuses to start without it. Back up the eternity_data Docker volume, which contains accounts and posts.