diff --git a/.dockerignore b/.dockerignore index 1269488..4f8233a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,3 @@ data +db-data +.env diff --git a/.env.mariadb b/.env.mariadb new file mode 100644 index 0000000..21e328e --- /dev/null +++ b/.env.mariadb @@ -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= diff --git a/.env.sqlite b/.env.sqlite new file mode 100644 index 0000000..5e8292a --- /dev/null +++ b/.env.sqlite @@ -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= diff --git a/.gitignore b/.gitignore index 82f0c3a..b1ee384 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /data/ +/db-data/ +/.env diff --git a/Dockerfile b/Dockerfile index e7212e6..f09c749 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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." ARG WRITEFREELY_VERSION=v0.15.0 -ARG WRITEFREELY_FORK=writeas/writefreely +ARG WRITEFREELY_FORK=writefreely/writefreely RUN apk -U upgrade \ && apk add --no-cache nodejs npm make g++ git sqlite-dev \ @@ -38,14 +38,23 @@ RUN mkdir /stage && \ # Final image FROM alpine:3.19 +ARG WRITEFREELY_UID=1000 +ARG WRITEFREELY_GID=1000 + 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 bin/writefreely-docker.sh /writefreely/ WORKDIR /writefreely VOLUME /data EXPOSE 8080 -USER daemon + +RUN chown -R writefreely:writefreely /writefreely + +USER writefreely ENTRYPOINT ["/writefreely/writefreely-docker.sh"] diff --git a/README.md b/README.md index 4de4e38..2311d4a 100644 --- a/README.md +++ b/README.md @@ -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. -## Getting s tarted +## Getting started 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 - **`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_PASSWORD`**: The password for the database. - **`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_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 * `/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. diff --git a/bin/writefreely-docker.sh b/bin/writefreely-docker.sh index 570dcfb..da78a9f 100755 --- a/bin/writefreely-docker.sh +++ b/bin/writefreely-docker.sh @@ -20,16 +20,85 @@ set -e cd /data 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 - ${WRITEFREELY} -migrate - exec ${WRITEFREELY} + log "Migration required. Running migration..." + ${WRITEFREELY} -migrate + exec ${WRITEFREELY} fi if [ -e ./config.ini ]; then - ${WRITEFREELY} -init-db - ${WRITEFREELY} -gen-keys - exec ${WRITEFREELY} + initialize_database + generate_keys + create_admin_user + create_writer_user + exec ${WRITEFREELY} fi WRITEFREELY_BIND_PORT="${WRITEFREELY_BIND_PORT:-8080}" @@ -39,44 +108,116 @@ WRITEFREELY_SITE_DESCRIPTION="${WRITEFREELY_SITE_DESCRIPTION:-My Writefreely blo cat >./config.ini <