diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..84682fc
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,32 @@
+FROM --platform=$BUILDPLATFORM golang:1.18 AS psiphon_builder
+WORKDIR /go
+LABEL stage=builder
+ARG VERSION=2.0.23
+ARG BUILDPLATFORM
+ARG BUILDOS
+ARG BUILDARCH
+ARG TARGETS
+ENV DIR=/go/src/github.com/Psiphon-Labs/psiphon-tunnel-core \
+ GO111MODULE=off \
+ CGO_ENABLED=0
+RUN TARGET_PALTFORMS=${TARGETS:-"$BUILDOS/$BUILDARCH"}; \
+ mkdir -p ${DIR} && \
+ curl -sL https://github.com/Psiphon-Labs/psiphon-tunnel-core/archive/refs/tags/v${VERSION}.tar.gz | tar xz -C ${DIR} --strip-components=1 && \
+ (IFS=','; for PLATFORM in $TARGET_PALTFORMS; \
+ do \
+ OS=${PLATFORM%%/*} && \
+ ARCH=${PLATFORM##*/} && \
+ GOOS=${OS} GOARCH=${ARCH} go install -a -tags netgo -ldflags '-w -extldflags "-static"' github.com/Psiphon-Labs/psiphon-tunnel-core/ConsoleClient && \
+ BINARY=$(find /go/bin/* -name "ConsoleClient*") && \
+ mv ${BINARY} /go/psiphon_${OS}_${ARCH}; \
+ done)
+
+FROM alpine:3.16.0
+RUN mkdir -p /psiphon /config
+ARG TARGETOS
+ARG TARGETARCH
+COPY start_psiphon psiphon.config /psiphon/
+COPY --from=psiphon_builder /go/psiphon_${TARGETOS}_${TARGETARCH} /psiphon/psiphon
+EXPOSE 8080 1080
+VOLUME /config
+CMD ["/bin/sh", "/psiphon/start_psiphon"]
diff --git a/README.md b/README.md
index cf037d1..7d8d207 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,65 @@
-# psiphon
+
+# Psiphon Docker
Docker image for Psiphon
+
+Psiphon is an Internet censorship circumvention system.
+This docker image runs the ConsoleClient from the [psiphon-tunnel-core](https://github.com/Psiphon-Labs/psiphon-tunnel-core "psiphon-tunnel-core").
+
+This build uses `docker buildx` plugin with `docker-container` driver.
+
+## Installation Steps
+
+1. Ensure buildx is enabled for docker
+2. Create a builder instance for multi-arch
+3. Build docker image for current platform or multi-arch
+```
+# choose target platforms
+TARGETS="linux/amd64,linux/386,linux/arm64,linux/arm"
+
+# Create a builder instance
+sudo docker buildx create --name cross-platform \
+--platform ${TARGETS} --use
+
+# Build for current platform and load to docker image
+sudo docker buildx build -t / . --load
+
+# Build for multi-arch and push to registry
+sudo docker build --build-arg TARGETS=${TARGETS} \
+-t / \
+--platform ${TARGETS} . --push
+```
+***
+
+## To run using docker-compose (recommended):
+```
+version: "3.5"
+services:
+ psiphon:
+ image: swarupsengupta2007/psiphon:latest
+ container_name: psiphon
+ environment:
+ - PUID=1000
+ - PGID=1000
+ volumes:
+ - /path/to/psiphon/config:/config
+ ports:
+ - 1080:1080
+ - 8080:8080
+ restart: unless-stopped
+```
+
+## To run using docker-cli:
+`docker run --name psiphon -d -p 8080:8080 -p 1080:1080 -v /home/swarup/psiphon/config/:/config swarupsengupta2007/psiphon`
+
+The following Environment var are available:
+|ENV variable|Description|Default|
+|--|--|--|
+|PUID|The UID for psiphon process|1000|
+|PGID|The GID for psiphon process|1000|
+
+Following ports and volumes are available
+|Option|switch|Description|Default|
+|--|--|--|--|
+|HTTP PORT|-p host_port:8080|http proxy port|8080|
+|SOCKS PORT|-p host_port:1080|socks proxy port|1080|
+|VOLUME|-v /path/to/config:/config|The container storage|/config|
diff --git a/psiphon.config b/psiphon.config
new file mode 100644
index 0000000..1a591c2
--- /dev/null
+++ b/psiphon.config
@@ -0,0 +1,84 @@
+{
+ "DataRootDirectory": "/config/",
+ "DeviceRegion": "US",
+ "MigrateDataStoreDirectory": "/config",
+ "MigrateObfuscatedServerListDownloadDirectory": "/config/osl",
+ "MigrateRemoteServerListDownloadFilename": "/config/remote_server_list",
+ "ListenInterface": "any",
+ "LocalHttpProxyPort": 8080,
+ "LocalSocksProxyPort": 1080,
+ "NetworkID": "949F2E962ED7A9165B81E977A3B4758B",
+ "ObfuscatedServerListRootURLs": [
+ {
+ "OnlyAfterAttempts": 0,
+ "SkipVerify": false,
+ "URL": "aHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3BzaXBob24vd2ViL21qcjQtcDIzci1wdXdsL29zbA=="
+ },
+ {
+ "OnlyAfterAttempts": 2,
+ "SkipVerify": true,
+ "URL": "aHR0cHM6Ly93d3cuc3lzdGVtc2FmYXJpdW5pdmVyc2l0eWRlYnQuY29tL3dlYi9tanI0LXAyM3ItcHV3bC9vc2w="
+ },
+ {
+ "OnlyAfterAttempts": 2,
+ "SkipVerify": true,
+ "URL": "aHR0cHM6Ly93d3cueHlkaWFtb25kZGJleHBlcnQuY29tL3dlYi9tanI0LXAyM3ItcHV3bC9vc2w="
+ },
+ {
+ "OnlyAfterAttempts": 2,
+ "SkipVerify": true,
+ "URL": "aHR0cHM6Ly93d3cuYmxvZ3NmbWNhbmNlcmNpdGl6ZW4uY29tL3dlYi9tanI0LXAyM3ItcHV3bC9vc2w="
+ }
+ ],
+ "PropagationChannelId": "92AACC5BABE0944C",
+ "RemoteServerListSignaturePublicKey": "MIICIDANBgkqhkiG9w0BAQEFAAOCAg0AMIICCAKCAgEAt7Ls+/39r+T6zNW7GiVpJfzq/xvL9SBH5rIFnk0RXYEYavax3WS6HOD35eTAqn8AniOwiH+DOkvgSKF2caqk/y1dfq47Pdymtwzp9ikpB1C5OfAysXzBiwVJlCdajBKvBZDerV1cMvRzCKvKwRmvDmHgphQQ7WfXIGbRbmmk6opMBh3roE42KcotLFtqp0RRwLtcBRNtCdsrVsjiI1Lqz/lH+T61sGjSjQ3CHMuZYSQJZo/KrvzgQXpkaCTdbObxHqb6/+i1qaVOfEsvjoiyzTxJADvSytVtcTjijhPEV6XskJVHE1Zgl+7rATr/pDQkw6DPCNBS1+Y6fy7GstZALQXwEDN/qhQI9kWkHijT8ns+i1vGg00Mk/6J75arLhqcodWsdeG/M/moWgqQAnlZAGVtJI1OgeF5fsPpXu4kctOfuZlGjVZXQNW34aOzm8r8S0eVZitPlbhcPiR4gT/aSMz/wd8lZlzZYsje/Jr8u/YtlwjjreZrGRmG8KMOzukV3lLmMppXFMvl4bxv6YFEmIuTsOhbLTwFgh7KYNjodLj/LsqRVfwz31PgWQFTEPICV7GCvgVlPRxnofqKSjgTWI4mxDhBpVcATvaoBl1L/6WLbFvBsoAUBItWwctO2xalKxF5szhGm8lccoc5MZr8kfE0uxMgsxz4er68iCID+rsCAQM=",
+ "RemoteServerListURLs": [
+ {
+ "OnlyAfterAttempts": 0,
+ "SkipVerify": false,
+ "URL": "aHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3BzaXBob24vd2ViL21qcjQtcDIzci1wdXdsL3NlcnZlcl9saXN0X2NvbXByZXNzZWQ="
+ },
+ {
+ "OnlyAfterAttempts": 2,
+ "SkipVerify": true,
+ "URL": "aHR0cHM6Ly93d3cuc3lzdGVtc2FmYXJpdW5pdmVyc2l0eWRlYnQuY29tL3dlYi9tanI0LXAyM3ItcHV3bC9zZXJ2ZXJfbGlzdF9jb21wcmVzc2Vk"
+ },
+ {
+ "OnlyAfterAttempts": 2,
+ "SkipVerify": true,
+ "URL": "aHR0cHM6Ly93d3cueHlkaWFtb25kZGJleHBlcnQuY29tL3dlYi9tanI0LXAyM3ItcHV3bC9zZXJ2ZXJfbGlzdF9jb21wcmVzc2Vk"
+ },
+ {
+ "OnlyAfterAttempts": 2,
+ "SkipVerify": true,
+ "URL": "aHR0cHM6Ly93d3cuYmxvZ3NmbWNhbmNlcmNpdGl6ZW4uY29tL3dlYi9tanI0LXAyM3ItcHV3bC9zZXJ2ZXJfbGlzdF9jb21wcmVzc2Vk"
+ }
+ ],
+ "ServerEntrySignaturePublicKey": "sHuUVTWaRyh5pZwy4UguSgkwmBe0EHtJJkoF5WrxmvA=",
+ "SponsorId": "1BC527D3D09985CF",
+ "UpgradeDownloadClientVersionHeader": "x-amz-meta-psiphon-client-version",
+ "UpgradeDownloadURLs": [
+ {
+ "OnlyAfterAttempts": 0,
+ "SkipVerify": false,
+ "URL": "aHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3BzaXBob24vd2ViL21qcjQtcDIzci1wdXdsL3BzaXBob24zLmV4ZS51cGdyYWRl"
+ },
+ {
+ "OnlyAfterAttempts": 2,
+ "SkipVerify": true,
+ "URL": "aHR0cHM6Ly93d3cuc3lzdGVtc2FmYXJpdW5pdmVyc2l0eWRlYnQuY29tL3dlYi9tanI0LXAyM3ItcHV3bA=="
+ },
+ {
+ "OnlyAfterAttempts": 2,
+ "SkipVerify": true,
+ "URL": "aHR0cHM6Ly93d3cueHlkaWFtb25kZGJleHBlcnQuY29tL3dlYi9tanI0LXAyM3ItcHV3bA=="
+ },
+ {
+ "OnlyAfterAttempts": 2,
+ "SkipVerify": true,
+ "URL": "aHR0cHM6Ly93d3cuYmxvZ3NmbWNhbmNlcmNpdGl6ZW4uY29tL3dlYi9tanI0LXAyM3ItcHV3bA=="
+ }
+ ],
+ "UpstreamProxyUrl": "",
+ "UseIndistinguishableTLS": true
+}
diff --git a/start_psiphon b/start_psiphon
new file mode 100644
index 0000000..d8b9b0b
--- /dev/null
+++ b/start_psiphon
@@ -0,0 +1,14 @@
+#/bin/sh
+
+export EUID=${PUID:-1000}
+export EGID=${PGID:-1000}
+addgroup -g $EGID psi
+adduser -u $EUID -G psi -D -H psi
+
+[[ ! -f /config/psiphon.config ]] && cp /psiphon/psiphon.config /config/
+[[ ! -d /config/osl ]] && mkdir /config/osl
+[[ ! -d /config/remote_server_list ]] && mkdir /config/remote_server_list
+
+chown -R psi:psi /config/
+
+su psi -c 'exec /psiphon/psiphon -config /config/psiphon.config'