Development container for the weblog
I set up a development environment for the weblog using a Docker container. The inspiration was the excellent collection of user-friendly containerized applications from linuxserver.io. They even provide complete operating systems with integrated desktop environments, such as Webtop.
One standout container is their code-server, a browser based version of Microsoft VSCode. Since I work on my weblog from different locations, using a code-server based container would allow me to streamline development by eliminating the need to install dependencies on multiple machines.The container should support the full development cycle: retrieving the code from GitHub, editing, debugging in the gui, and pushing updates back to GitHub, which triggers automatic deployment on Cloudflare Pages.
Setting Up the Docker Container
I started by creating a Dockerfile
based on the code-server container:
FROM lscr.io/linuxserver/code-server:latest
WORKDIR /config/workspace
I then added a compose.yaml
file as per the code-server instructions:
services:
weblog:
build:
context: .
dockerfile: Dockerfile
container_name: weblog
volumes:
- weblog-data:/config
environment:
- PUID=0
- PGID=0
- TZ=Europe/Amsterdam
- DEFAULT_WORKSPACE=/config/workspace
ports:
- 8443:8443
restart: unless-stopped
volumes:
weblog-data:
I used a named volume for the working directory such that it is persistent in between container instances.
Adding Node.js for Astro Framework
Since Astro is a Node.js framework, I needed to install Node.js in the container. I could have used linuxserver.io’s mod system, in particular, the NodeJS mod. However, using a mod would repeat the installation on each startup of the container. I decided to install Node.js during container build time and added the following to the Dockerfile
:
ARG NODE_VERSION
# Install Nodejs
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | sudo -E bash - && \
apt install -y nodejs
To compose.yaml
I added:
args:
- NODE_VERSION=20
Cloning Weblog Code with GitHub CLI
To clone the private weblog GitHub repository, I installed the Github CLI in the container using the following Dockerfile instructions:
RUN (type -p wget >/dev/null || (sudo apt update && sudo apt-get install wget -y)) \
&& sudo mkdir -p -m 755 /etc/apt/keyrings \
&& wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& sudo apt update \
&& sudo apt install gh -y
To authenticate with Github, the GH_TOKEN
environment variable can be used, or the authentication can be done manually via gh auth login
. I added the environment variable to the compose.yaml
such that it is copied from the host if it exists and ignored otherwise:
environment:
- GH_TOKEN
The init.sh
script simplifies the setup process and is included in the container
#!/bin/bash
if [ -z "$GH_TOKEN" ]; then
echo "GH_TOKEN is not set. Authenticating..."
gh auth login || { echo "Authentication failed."; exit 1; }
else
echo "GH_TOKEN is set. Skipping manual authentication."
fi
gh repo clone https://[email protected]/XXX/weblog
cd weblog
npm install
npm run astro telemetry disable
The dos2unix
utility converts the script to avoid issues with Windows-style line endings:
RUN apt update && \
apt install -y wget sudo git vim curl unzip dos2unix
COPY init.sh .
RUN dos2unix init.sh && chmod a+x init.sh
Installing VSCode Extensions for Astro
To enable Astro support in code-server, I used linuxserver.io’s mod system with the Extension Arguments mod to install the Astro extension inside code-server. I updated compose.yaml
with:
environment:
- DOCKER_MODS=linuxserver/mods:code-server-extension-arguments
- VSCODE_EXTENSION_IDS=astro-build.astro-vscode
Running the Weblog in Development Mode
A port mapping is added in compose.yaml
to access the weblog locally from outside the container when run in development mode, :
ports:
- 4321:4321
By default the weblog running in development mode is only made available on the localhost interface. Hence it is not globally (i.e. outside the container) available. To make the development server listen on all interfaces, I modified the astro.config.mjs
file in the Astro project:
export default defineConfig({
...
server: {
host: true
},
});
Complete Docker and Compose files
Finally, here is the complete Dockerfile
:
FROM lscr.io/linuxserver/code-server:latest
WORKDIR /config/workspace
# Install some utilities
RUN apt update && \
apt install -y wget sudo git vim curl unzip dos2unix
COPY app/* .
# Prepare scripts
RUN dos2unix init.sh && \
chmod a+x init.sh
ARG NODE_VERSION
# Install Nodejs
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | sudo -E bash - && \
apt install -y nodejs
# Install Github client
RUN (type -p wget >/dev/null || (sudo apt update && sudo apt-get install wget -y)) \
&& sudo mkdir -p -m 755 /etc/apt/keyrings \
&& wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& sudo apt update \
&& sudo apt install gh -y
And the compose.yaml
:
services:
weblog:
build:
context: .
dockerfile: Dockerfile
args:
- NODE_VERSION=20
container_name: weblog
volumes:
- weblog-data:/config
environment:
- DOCKER_MODS=linuxserver/mods:code-server-extension-arguments
- VSCODE_EXTENSION_IDS=astro-build.astro-vscode
- GH_TOKEN
- PUID=0
- PGID=0
- TZ=Europe/Amsterdam
- DEFAULT_WORKSPACE=/config/workspace
ports:
- 8443:8443
- 4321:4321
restart: unless-stopped
volumes:
weblog-data: