Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
assets
_build
.cargo
deps
.elixir_ls
priv
priv/static
native/philomena/target
node_modules
123 changes: 123 additions & 0 deletions .github/workflows/production.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
name: Production Images

on:
push:
branches:
- master
tags:
- '*'

jobs:
build-and-push-philomena:
name: 'Build and Publish Philomena'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Checkout repository
uses: actions/checkout@v5

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/philomena-dev/philomena

- name: Build and push Philomena image
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/production/Dockerfile
platforms: 'linux/amd64'
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

build-and-push-web:
name: 'Build and Publish Web'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Checkout repository
uses: actions/checkout@v5

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/philomena-dev/philomena-web

- name: Build and push Philomena Web Server image
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/production/web/Dockerfile
platforms: 'linux/amd64'
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

build-and-push-fiberglass:
name: 'Build and Publish Fiberglass Server'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Checkout repository
uses: actions/checkout@v5

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/philomena-dev/fiberglass-server

- name: Build and push Fiberglass Media Processing image
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/production/fiberglass/Dockerfile
platforms: 'linux/amd64'
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ services:
- '5173:5173'

postgres:
image: postgres:17.6-alpine
image: postgres:17.7-alpine
environment:
- POSTGRES_PASSWORD=postgres
volumes:
Expand Down
101 changes: 101 additions & 0 deletions docker/production/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# We need to grab "psql" from the Postgres image for database setup
FROM postgres:17.7-alpine AS pg

#
# Step 1: Build Philomena release
#

FROM elixir:1.18.4-alpine AS builder

WORKDIR /tmp/philomena

ENV MIX_ENV=prod
ENV NODE_ENV=production
ENV PATH=$PATH:/root/.cargo/bin

ADD https://api.github.com/repos/philomena-dev/fiberglass-wrapper/git/refs/heads/master /tmp/fiberglass_wrapper_version.json

# Install dependencies and build tools
RUN apk update --allow-untrusted \
&& apk add build-base git npm nodejs wget rust cargo --allow-untrusted \
&& mix local.hex --force \
&& mix local.rebar --force

# Build fiberglass-wrapper from source
RUN git clone --depth 1 https://github.com/philomena-dev/fiberglass-wrapper /tmp/fiberglass_wrapper \
&& cd /tmp/fiberglass_wrapper \
&& cargo build --release

# Copy repo files into the image
COPY . /tmp/philomena

# Install and compile assets
RUN cd /tmp/philomena/assets \
&& NODE_ENV=development npm install \
&& npm run deploy

# Build the application and create symlinks for easier access
RUN cd /tmp/philomena \
&& mix deps.get \
&& mix release --overwrite

# Digest and copy static assets
RUN mix phx.digest -o /tmp/philomena/_build/prod/rel/philomena/lib/philomena-*/priv/static

#
# Step 2: Copy only the final release into a minimal image
# Also copy psql from the Postgres image
#

FROM alpine:3.23

LABEL org.opencontainers.image.authors="liamwhite <liamwhite@users.noreply.github.com>, Nighty <luna@nighty.cloud>, and contributors"
LABEL org.opencontainers.image.description="The official Philomena Docker image intended for production use."
LABEL org.opencontainers.image.source="https://github.com/philomena-dev/philomena"
LABEL org.opencontainers.image.licenses="AGPL-3.0-only"

# Install runtime dependencies
# Required by Erlang/Elixir: libncursesw libstdc++ libgcc
# Required by psql: libedit krb5-libs libldap
RUN apk update \
&& apk add --no-cache libncursesw libstdc++ libgcc libedit krb5-libs libldap

# Set up a non-root user to run the application
RUN addgroup -g 1000 -S philomena \
&& adduser -u 1000 -S philomena -G philomena

# Copy the finished release and the config (because of .json files) from the builder stage...
COPY --from=builder --chown=1000:1000 /tmp/philomena/_build/prod/rel/philomena /srv/philomena
COPY --from=builder --chown=1000:1000 /tmp/philomena/config /srv/philomena/config

# Copy fiberglass-wrapper executable too
COPY --from=builder /tmp/fiberglass_wrapper/target/release/fiberglass-wrapper /usr/local/bin/fiberglass-wrapper

# ...and the production scripts from the repository
COPY --chown=1000:1000 docker/production/purge-cache /usr/local/bin/purge-cache
COPY --chown=1000:1000 docker/production/run-cron /usr/local/bin/run-cron
COPY --chown=1000:1000 docker/production/run-cron-daily /usr/local/bin/run-cron-daily
COPY --chown=1000:1000 docker/production/run-production /usr/local/bin/run-production
COPY --chown=1000:1000 docker/production/setup-production /usr/local/bin/setup-production
COPY --chown=1000:1000 docker/production/programs/* /usr/local/bin/

# Copy postgres client.
COPY --from=pg /usr/local/bin/psql /usr/local/bin/psql
COPY --from=pg /usr/local/bin/pg_isready /usr/local/bin/pg_isready
COPY --from=pg /usr/local/lib/libpq.so /usr/local/lib/libpq.so
COPY --from=pg /usr/local/lib/libpq.so.5 /usr/local/lib/libpq.so.5
COPY --from=pg /usr/local/lib/libpq.so.5.17 /usr/local/lib/libpq.so.5.17

# A "philomena" symlink for easier access
RUN ln -sf /srv/philomena/bin/philomena /usr/local/bin/philomena

USER philomena

# Create the static assets symlink as the philomena user
RUN ln -sf /srv/philomena/lib/philomena-*/priv /srv/philomena/priv

WORKDIR /srv/philomena

EXPOSE 4000-4002

CMD ["/usr/local/bin/run-production"]
22 changes: 22 additions & 0 deletions docker/production/fiberglass/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM ghcr.io/philomena-dev/fiberglass:2025-12-10

LABEL org.opencontainers.image.authors="liamwhite <liamwhite@users.noreply.github.com>, Nighty <luna@nighty.cloud>, and contributors"
LABEL org.opencontainers.image.description="Legacy Philomena image processing tools, used by Philomena 1.2.x and older. Deprecated in favor of Mediaproc."
LABEL org.opencontainers.image.source="https://github.com/philomena-dev/philomena"
LABEL org.opencontainers.image.licenses="AGPL-3.0-only"

WORKDIR /tmp/fiberglass-server

COPY docker/production/fiberglass/fiberglass-server.ru /tmp/fiberglass-server/fiberglass-server.ru

USER root

RUN apk add ruby ruby-dev build-base rsvg-convert \
&& gem install rack puma rackup base64 \
&& apk del build-base \
&& rm -f /sbin/apk \
&& rm -rf /etc/apk /lib/apk /usr/share/apk /var/lib/apk

USER fiberglass

CMD puma -b tcp://0.0.0.0:8080 -w 8 -t 1:1 /tmp/fiberglass-server/fiberglass-server.ru
83 changes: 83 additions & 0 deletions docker/production/fiberglass/fiberglass-server.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
require 'open3'
require 'base64'
require 'fileutils'
require 'securerandom'

$PERMITTED_COMMANDS = %w[convert ffmpeg ffprobe file gifsicle identify image-intensities jpegtran magick mediastat mediathumb optipng safe-rsvg-convert svgstat]

class Application
def call(env)
req = Rack::Request.new(env)

if req.post?
run(req.body.read)
else
[405, {}, []]
end
end

private

def run(input)
# Container-side script. Can be more lax here.

cwd = "/tmp/#{SecureRandom.uuid}"
FileUtils.mkdir_p(cwd)
FileUtils.cd(cwd)

progname = nil
args = []
files = []

# Parse input
input.each_line.with_index do |line, index|
line.chomp!

if index == 0
progname = Base64.strict_decode64(line)

unless $PERMITTED_COMMANDS.include?(progname.chomp)
return [400, {}, []]
end

next
end

if index == 1
args = line.split(",").map { |a| Base64.strict_decode64(a) }
next
end

name, contents = line.split(":")
files << name
File.write(name, Base64.strict_decode64(contents.to_s))
end

# Run command
stdout, stderr, status = Open3.capture3(progname, *args)

# Generate output
output = []

output.push status.exitstatus.to_s
output.push "\n"

output.push Base64.strict_encode64(stdout)
output.push "\n"

output.push Base64.strict_encode64(stderr)
output.push "\n"

files.each do |file|
output.push Base64.strict_encode64(File.read(file))
output.push "\n"
end

FileUtils.cd("/")
FileUtils.rm_rf(cwd)

[200, {}, output]
end
end

run Application.new
2 changes: 2 additions & 0 deletions docker/production/programs/convert
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper convert "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/ffmpeg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper ffmpeg "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/ffprobe
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper ffprobe "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/file
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper file "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/gifsicle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper gifsicle "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/identify
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper identify "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/image-intensities
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper image-intensities "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/jpegtran
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper jpegtran "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/magick
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper magick "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/mediastat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper mediastat "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/mediathumb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper mediathumb "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/optipng
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper optipng "$@"
2 changes: 2 additions & 0 deletions docker/production/programs/safe-rsvg-convert
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
safe-wrapper safe-rsvg-convert "$@"
6 changes: 6 additions & 0 deletions docker/production/programs/safe-wrapper
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
if [[ -z "${FIBERGLASS_URL}" ]]; then
export FIBERGLASS_URL=http://fiberglass:8080
fi

fiberglass-wrapper "$@"
Loading