Add enhanced configuration and Docker Compose support for WriteFreely (#2)

* Update ini configuration. Add docker-compose examples
* remove unneeded network config
* Add docker compose instructions
* Correct sqlite location
* do not wait for MariaDB
* Use writefreely user
* Add .env instructions for docker compose
* Retry init if database is not ready
* Ignore production directories
* Improve init checks
* refactor init script

---------

Co-authored-by: Germán Martín <gmartin@gmartin.net>
This commit is contained in:
Germán Martín 2024-06-12 11:59:37 +02:00 committed by GitHub
parent 0f4b06fa8f
commit a15d4e58cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 399 additions and 41 deletions

View file

@ -1 +1,3 @@
data data
db-data
.env

38
.env.mariadb Normal file
View file

@ -0,0 +1,38 @@
# General Configuration
WRITEFREELY_BIND_PORT=8080
WRITEFREELY_BIND_HOST=0.0.0.0
WRITEFREELY_SITE_NAME="My Blog"
WRITEFREELY_SITE_DESCRIPTION="My fancy blog"
# Database Configuration
MARIADB_USER=writefreely
MARIADB_PASSWORD=changeme
MARIADB_DATABASE=writefreely
MARIADB_ROOT_PASSWORD=changeme
WRITEFREELY_DATABASE_DATABASE=mysql
WRITEFREELY_DATABASE_USERNAME=${MARIADB_USER}
WRITEFREELY_DATABASE_PASSWORD=${MARIADB_PASSWORD}
WRITEFREELY_DATABASE_NAME=${MARIADB_DATABASE}
WRITEFREELY_DATABASE_HOST=writefreely-db
WRITEFREELY_DATABASE_PORT=3306
# Application Settings
WRITEFREELY_HOST=
WRITEFREELY_SINGLE_USER=true
WRITEFREELY_OPEN_REGISTRATION=false
WRITEFREELY_MIN_USERNAME_LEN=4
WRITEFREELY_MAX_BLOG=4
WRITEFREELY_FEDERATION=true
WRITEFREELY_PUBLIC_STATS=true
WRITEFREELY_PRIVATE=false
WRITEFREELY_LOCAL_TIMELINE=true
WRITEFREELY_USER_INVITES=
# Writefreely Users
WRITEFREELY_ADMIN_USER=admin
WRITEFREELY_ADMIN_PASSWORD=changeme
WRITEFREELY_WRITER_USER=
WRITEFREELY_WRITER_PASSWORD=

31
.env.sqlite Normal file
View file

@ -0,0 +1,31 @@
# General Configuration
WRITEFREELY_BIND_PORT=8080
WRITEFREELY_BIND_HOST=0.0.0.0
WRITEFREELY_SITE_NAME="My Blog"
WRITEFREELY_SITE_DESCRIPTION="My fancy blog"
# Database Configuration
WRITEFREELY_DATABASE_DATABASE=sqlite3
WRITEFREELY_SQLITE_FILENAME=./writefreely.db
WRITEFREELY_DATABASE_USERNAME=writefreely
WRITEFREELY_DATABASE_PASSWORD=changeme
WRITEFREELY_DATABASE_NAME=writefreely
# Application Settings
WRITEFREELY_HOST=
WRITEFREELY_SINGLE_USER=true
WRITEFREELY_OPEN_REGISTRATION=false
WRITEFREELY_MIN_USERNAME_LEN=4
WRITEFREELY_MAX_BLOG=4
WRITEFREELY_FEDERATION=true
WRITEFREELY_PUBLIC_STATS=true
WRITEFREELY_PRIVATE=false
WRITEFREELY_LOCAL_TIMELINE=true
WRITEFREELY_USER_INVITES=
# Writefreely Users
WRITEFREELY_ADMIN_USER=admin
WRITEFREELY_ADMIN_PASSWORD=changeme
WRITEFREELY_WRITER_USER=
WRITEFREELY_WRITER_PASSWORD=

2
.gitignore vendored
View file

@ -1 +1,3 @@
/data/ /data/
/db-data/
/.env

View file

@ -7,7 +7,7 @@ LABEL org.opencontainers.image.source="https://github.com/writefreely/writefreel
LABEL org.opencontainers.image.description="WriteFreely is a clean, minimalist publishing platform made for writers. Start a blog, share knowledge within your organization, or build a community around the shared act of writing." LABEL org.opencontainers.image.description="WriteFreely is a clean, minimalist publishing platform made for writers. Start a blog, share knowledge within your organization, or build a community around the shared act of writing."
ARG WRITEFREELY_VERSION=v0.15.0 ARG WRITEFREELY_VERSION=v0.15.0
ARG WRITEFREELY_FORK=writeas/writefreely ARG WRITEFREELY_FORK=writefreely/writefreely
RUN apk -U upgrade \ RUN apk -U upgrade \
&& apk add --no-cache nodejs npm make g++ git sqlite-dev \ && apk add --no-cache nodejs npm make g++ git sqlite-dev \
@ -38,14 +38,23 @@ RUN mkdir /stage && \
# Final image # Final image
FROM alpine:3.19 FROM alpine:3.19
ARG WRITEFREELY_UID=1000
ARG WRITEFREELY_GID=1000
RUN apk -U upgrade && apk add --no-cache openssl ca-certificates RUN apk -U upgrade && apk add --no-cache openssl ca-certificates
RUN addgroup -g ${WRITEFREELY_GID} -S writefreely && adduser -u ${WRITEFREELY_UID} -S -G writefreely writefreely
COPY --from=build --chown=daemon:daemon /stage /writefreely COPY --from=build --chown=daemon:daemon /stage /writefreely
COPY bin/writefreely-docker.sh /writefreely/ COPY bin/writefreely-docker.sh /writefreely/
WORKDIR /writefreely WORKDIR /writefreely
VOLUME /data VOLUME /data
EXPOSE 8080 EXPOSE 8080
USER daemon
RUN chown -R writefreely:writefreely /writefreely
USER writefreely
ENTRYPOINT ["/writefreely/writefreely-docker.sh"] ENTRYPOINT ["/writefreely/writefreely-docker.sh"]

View file

@ -2,7 +2,7 @@
This project builds a Docker image for [WriteFreely](https://github.com/writefreely/writefreely), a minimalist, privacy-focused, and federated blogging platform. The image is uses on Alpine Linux. This project builds a Docker image for [WriteFreely](https://github.com/writefreely/writefreely), a minimalist, privacy-focused, and federated blogging platform. The image is uses on Alpine Linux.
## Getting s tarted ## Getting started
To get started, the easiest way to test it out is running the following command: To get started, the easiest way to test it out is running the following command:
@ -31,6 +31,7 @@ The following variables will be used to construct the `config.ini` on first star
## Database Configuration ## Database Configuration
- **`WRITEFREELY_DATABASE_DATABASE`**: Specifies the type of database used, such as `mysql` or `sqlite3`. - **`WRITEFREELY_DATABASE_DATABASE`**: Specifies the type of database used, such as `mysql` or `sqlite3`.
- **`WRITEFREELY_SQLITE_FILENAME`**: (Optional) DB filename if `sqlite3` detabase is selected. Defaults to `/data/writefreely.db`.
- **`WRITEFREELY_DATABASE_USERNAME`**: The username for the database. - **`WRITEFREELY_DATABASE_USERNAME`**: The username for the database.
- **`WRITEFREELY_DATABASE_PASSWORD`**: The password for the database. - **`WRITEFREELY_DATABASE_PASSWORD`**: The password for the database.
- **`WRITEFREELY_DATABASE_NAME`**: The name of the database to connect to. - **`WRITEFREELY_DATABASE_NAME`**: The name of the database to connect to.
@ -50,6 +51,93 @@ The following variables will be used to construct the `config.ini` on first star
- **`WRITEFREELY_LOCAL_TIMELINE`**: Whether or not the instance reader (and the Public option on blogs) is enabled - **`WRITEFREELY_LOCAL_TIMELINE`**: Whether or not the instance reader (and the Public option on blogs) is enabled
- **`WRITEFREELY_USER_INVITES`**: Who is allowed to send user invites, if anyone. A blank value disables invites for all users. Valid choices: empty, user, or admin - **`WRITEFREELY_USER_INVITES`**: Who is allowed to send user invites, if anyone. A blank value disables invites for all users. Valid choices: empty, user, or admin
## Writefreely Users
- **`WRITEFREELY_ADMIN_USER`**: Administrator user name. In single user instances is editor too.
- **`WRITEFREELY_ADMIN_PASSWORD`**: Administrator password
### Volumes ### Volumes
* `/data`: Directory where WriteFreely stores its data, including database files and configuration. * `/data`: Directory where WriteFreely stores its data, including database files and configuration.
### Using Docker Compose
You can use Docker Compose to set up WriteFreely with different database configurations. The configuration files are already included in this repository. Follow the steps below to start the services.
#### Clone the Repository
First, clone this repository:
```bash
git clone https://github.com/yourusername/writefreely-docker.git
cd writefreely-docker
```
#### Prepare the Data Directory
Create the data directory and assign the appropriate permissions:
```bash
mkdir data
sudo chown 1000:1000 data
```
#### Configure the Environment
Before starting the services, you need to copy the appropriate .env file and edit it to configure the environment variables, especially the passwords.
##### For MariaDB
Copy the .env.mariadb file to .env:
```bash
cp .env.mariadb .env
```
##### For SQLite
Copy the .env.sqlite file to .env:
```bash
cp .env.sqlite .env
```
Then, edit the .env file to set the appropriate values for your environment:
```bash
nano .env
```
Ensure to set secure passwords and other necessary configuration options.
#### Start the Services
##### MariaDB
To use the **MariaDB** configuration, run:
```bash
docker-compose -f docker-compose.mariadb.yaml up
```
##### SQLite
To use the **SQLite** configuration, run:
```bash
docker-compose -f docker-compose.sqlite3.yaml up
```
### Building the Image
If you want to build the image yourself, clone this repository and run the following command inside the repository's directory:
```bash
docker build -t yourusername/writefreely .
```
Replace `yourusername` with your Docker Hub username or a suitable image name.
### Contributing
Contributions are welcome! Please fork this repository and submit pull requests for any enhancements or bug fixes.

View file

@ -20,16 +20,85 @@ set -e
cd /data cd /data
WRITEFREELY=/writefreely/writefreely WRITEFREELY=/writefreely/writefreely
attempts=0
max_attempts=5
log() {
echo "$(date '+%Y/%m/%d %H:%M:%S') $1"
}
validate_url() {
URL="$1"
if echo "$URL" | grep -Eq "^https?://[a-zA-Z0-9._-]+"; then
return 0 # Success
else
return 1 # Failure
fi
}
retry_command() {
local cmd=$1
attempts=0
until $cmd; do
attempts=$((attempts+1))
if [ $attempts -ge $max_attempts ]; then
log "Failed to execute '$cmd' after $attempts attempts."
return 1
fi
log "Retrying '$cmd' ($attempts/$max_attempts)..."
sleep 5
done
return 0
}
initialize_database() {
log "Initializing database..."
if ! retry_command "${WRITEFREELY} --init-db"; then
log "Initialization of database failed. Removing config.ini."
rm ./config.ini
exit 1
fi
}
generate_keys() {
log "Generating keys..."
${WRITEFREELY} --gen-keys
}
create_admin_user() {
if [ -n "$WRITEFREELY_ADMIN_USER" ]; then
${WRITEFREELY} user create --admin ${WRITEFREELY_ADMIN_USER}:${WRITEFREELY_ADMIN_PASSWORD}
log "Created admin user ${WRITEFREELY_ADMIN_USER}"
else
log "Admin user not defined"
exit 1
fi
}
create_writer_user() {
if [ -n "$WRITEFREELY_WRITER_USER" ]; then
${WRITEFREELY} user create ${WRITEFREELY_WRITER_USER}:${WRITEFREELY_WRITER_PASSWORD}
log "Created writer user ${WRITEFREELY_WRITER_USER}"
fi
}
validate_url "$WRITEFREELY_HOST" || {
log "Error: $WRITEFREELY_HOST is not a valid URL. It must start with http:// or https:// and be followed by a valid hostname."
exit 1
}
if [ -e ./config.ini ] && [ -e ./keys/email.aes256 ]; then if [ -e ./config.ini ] && [ -e ./keys/email.aes256 ]; then
${WRITEFREELY} -migrate log "Migration required. Running migration..."
exec ${WRITEFREELY} ${WRITEFREELY} -migrate
exec ${WRITEFREELY}
fi fi
if [ -e ./config.ini ]; then if [ -e ./config.ini ]; then
${WRITEFREELY} -init-db initialize_database
${WRITEFREELY} -gen-keys generate_keys
exec ${WRITEFREELY} create_admin_user
create_writer_user
exec ${WRITEFREELY}
fi fi
WRITEFREELY_BIND_PORT="${WRITEFREELY_BIND_PORT:-8080}" WRITEFREELY_BIND_PORT="${WRITEFREELY_BIND_PORT:-8080}"
@ -39,44 +108,116 @@ WRITEFREELY_SITE_DESCRIPTION="${WRITEFREELY_SITE_DESCRIPTION:-My Writefreely blo
cat >./config.ini <<EOF cat >./config.ini <<EOF
[server] [server]
hidden_host = hidden_host =
port = ${WRITEFREELY_BIND_PORT} port = ${WRITEFREELY_BIND_PORT}
bind = ${WRITEFREELY_BIND_HOST} bind = ${WRITEFREELY_BIND_HOST}
tls_cert_path = tls_cert_path =
tls_key_path = tls_key_path =
templates_parent_dir = /writefreely autocert =
static_parent_dir = /writefreely templates_parent_dir = /writefreely
pages_parent_dir = /writefreely static_parent_dir = /writefreely
keys_parent_dir = pages_parent_dir = /writefreely
keys_parent_dir =
hash_seed =
gopher_port = 0
[database] [database]
type = ${WRITEFREELY_DATABASE_DATABASE} type = ${WRITEFREELY_DATABASE_DATABASE}
username = ${WRITEFREELY_DATABASE_USERNAME} filename = ${WRITEFREELY_SQLITE_FILENAME:-/data/writefreely.db}
password = ${WRITEFREELY_DATABASE_PASSWORD} username = ${WRITEFREELY_DATABASE_USERNAME}
database = ${WRITEFREELY_DATABASE_NAME} password = ${WRITEFREELY_DATABASE_PASSWORD}
host = ${WRITEFREELY_DATABASE_HOST} database = ${WRITEFREELY_DATABASE_NAME}
port = ${WRITEFREELY_DATABASE_PORT} host = ${WRITEFREELY_DATABASE_HOST}
port = ${WRITEFREELY_DATABASE_PORT}
tls = false
[app] [app]
site_name = ${WRITEFREELY_SITE_NAME} site_name = ${WRITEFREELY_SITE_NAME}
site_description = ${WRITEFREELY_SITE_DESCRIPTION} site_description = ${WRITEFREELY_SITE_DESCRIPTION}
host = ${WRITEFREELY_HOST:-http://${WRITEFREELY_BIND_HOST}:${WRITEFREELY_BIND_PORT}} host = ${WRITEFREELY_HOST:-http://${WRITEFREELY_BIND_HOST}:${WRITEFREELY_BIND_PORT}}
theme = write theme = write
disable_js = false editor =
webfonts = true disable_js = false
landing = webfonts = true
single_user = ${WRITEFREELY_SINGLE_USER:-false} landing =
open_registration = ${WRITEFREELY_OPEN_REGISTRATION:-false} simple_nav = false
min_username_len = ${WRITEFREELY_MIN_USERNAME_LEN:-3} wf_modesty = false
max_blogs = ${WRITEFREELY_MAX_BLOG:-1} chorus = false
federation = ${WRITEFREELY_FEDERATION:-true} forest = false
public_stats = ${WRITEFREELY_PUBLIC_STATS:-false} disable_drafts = false
private = ${WRITEFREELY_PRIVATE:-false} single_user = ${WRITEFREELY_SINGLE_USER:-false}
local_timeline = ${WRITEFREELY_LOCAL_TIMELINE:-false} open_registration = ${WRITEFREELY_OPEN_REGISTRATION:-false}
user_invites = ${WRITEFREELY_USER_INVITES} min_username_len = ${WRITEFREELY_MIN_USERNAME_LEN:-3}
max_blogs = ${WRITEFREELY_MAX_BLOG:-4}
federation = ${WRITEFREELY_FEDERATION:-true}
public_stats = ${WRITEFREELY_PUBLIC_STATS:-false}
monetization = false
notes_only = false
private = ${WRITEFREELY_PRIVATE:-false}
local_timeline = ${WRITEFREELY_LOCAL_TIMELINE:-false}
user_invites = ${WRITEFREELY_USER_INVITES}
update_checks = false
disable_password_auth = false
[email]
domain =
mailgun_private =
[oauth.slack]
client_id =
client_secret =
team_id =
callback_proxy =
callback_proxy_api =
[oauth.writeas]
client_id =
client_secret =
auth_location =
token_location =
inspect_location =
callback_proxy =
callback_proxy_api =
[oauth.gitlab]
client_id =
client_secret =
host =
display_name =
callback_proxy =
callback_proxy_api =
[oauth.gitea]
client_id =
client_secret =
host =
display_name =
callback_proxy =
callback_proxy_api =
[oauth.generic]
client_id =
client_secret =
host =
display_name =
callback_proxy =
callback_proxy_api =
token_endpoint =
inspect_endpoint =
auth_endpoint =
scope =
allow_disconnect = false
map_user_id =
map_username =
map_display_name =
map_email =
EOF EOF
${WRITEFREELY} --init-db chmod 600 ./config.ini
${WRITEFREELY} --gen-keys
initialize_database
generate_keys
create_admin_user
create_writer_user
exec ${WRITEFREELY} exec ${WRITEFREELY}

View file

@ -0,0 +1,32 @@
services:
writefreely-web:
container_name: writefreely-web
image: jrasanen/writefreely:latest
build:
context: .
init: true
env_file:
- .env
volumes:
- ./data:/data
ports:
- 8080:8080
depends_on:
- writefreely-db
restart: unless-stopped
writefreely-db:
container_name: writefreely-db
image: mariadb:latest
init: true
volumes:
- ./db-data:/var/lib/mysql
env_file:
- .env
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "mariadb-admin ping -h localhost -u${MARIADB_USER} -p${MARIADB_PASSWORD} || exit 1"]
interval: 30s
timeout: 10s
retries: 5
start_period: 10s

View file

@ -0,0 +1,15 @@
services:
writefreely-web:
container_name: writefreely-web
image: jrasanen/writefreely:latest
build:
context: .
init: true
env_file:
- .env
volumes:
- ./data:/data
ports:
- 8080:8080
restart: unless-stopped