📢 This article was translated by gemini-3-flash-preview
It took three months from the initial idea to full implementation (mostly because I was too lazy).
Installing Docker
Installed using APT (on Debian).
- Add packages for HTTPS transport and CA certificates.
1
2
3
4
5
6
7
8
9
10
| # Update first
sudo apt-get update
# Then install
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
|
- Add the GPG key for the software source to verify package legitimacy.
1
2
3
4
5
6
| # China mirror
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Official source
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
- Add the Docker repository to sources.list.
First, determine your Debian version name, then replace $(lsb_release -cs) in the command below.
You can find version names at
https://mirrors.aliyun.com/docker-ce/linux/debian/dists/
.
1
2
3
4
5
6
7
8
9
10
| # China mirror
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Official source
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
For example, Debian 10 is buster, and Debian 11 is bullseye.
1
2
3
4
| # This is for Debian 11
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian \
bullseye stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
The commands above add the stable Docker APT source. If you need the test version, change stable to test.
- Now install.
1
2
3
4
5
6
7
8
| # Update cache
sudo apt-get update
# Install docker
sudo apt-get install docker-ce docker-ce-cli containerd.io
# Install docker-compose
sudo apt-get install docker-compose
|
Alternatively, you can try the one-click installation script:
1
2
3
4
5
6
7
8
9
10
11
| # Test version
curl -fsSL test.docker.com -o get-docker.sh
# Stable version
curl -fsSL get.docker.com -o get-docker.sh
# Aliyun mirror
sudo sh get-docker.sh --mirror Aliyun
# Microsoft Azure China mirror
sudo sh get-docker.sh --mirror AzureChinaCloud
|
Starting Docker
1
2
| sudo systemctl enable docker
sudo systemctl start docker
|
Test if it’s running correctly with:
1
| docker run --rm hello-world
|
If you see output like this, the installation was successful:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:c77be1d3a47d0caf71a82dd893ee61ce01f32fc758031a6ec4cf1389248bb833
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
|
Blog 1: WordPress
Create a folder (e.g., /root/wordpress), then create a docker-compose.yml file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| version: '3.3'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
volumes:
- /root/wordpress/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
ports:
- 8000:80
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
|
Create an uploads.ini file:
1
2
3
4
5
| file_uploads = On
memory_limit = 256M
upload_max_filesize = 10M
post_max_size = 10M
max_execution_time = 600
|
Docker Container Operations
1
2
3
4
5
6
7
8
| # Run in background
docker-compose up -d
# Stop
docker-compose stop
# Stop and remove
docker-compose down
|
Blog 2: Typecho
Using image:
80x86/typecho
Create the folder and corresponding file:
1
2
3
4
5
6
7
8
9
10
11
12
13
| version: '3.0'
services:
typecho:
image: 80x86/typecho:latest
container_name: Typecho_Blog
volumes:
- /root/typecho/data:/data
ports:
- 8001:80
restart: always
environment:
PHP_TZ: Asia/Shanghai
PHP_MAX_EXECUTION_TIME: 600
|
Netdisk Site
Using project:
https://github.com/px-org/PanIndex
Official tutorial:
https://docs.noki.icu/
1
2
3
4
5
6
7
8
9
10
| version: "3.0"
services:
PanIndex:
restart: always
image: iicm/pan-index:latest
container_name: VRC_Pan
volumes:
- /root/pan/data:/app/data
ports:
- 8002:5238
|
Nginx and SSL Certificates
Using project:
https://github.com/0xJacky/nginx-ui
1
2
3
4
5
6
7
8
9
10
11
12
13
| version: '3.1'
services:
nginx-ui:
restart: always
image: uozi/nginx-ui:latest
container_name: nginx_UI
volumes:
- /root/nginx/nginx:/etc/nginx
- /root/nginx/nginx-ui:/etc/nginx-ui
- /root/nginx/www:/www
ports:
- 80:80
- 443:443
|
When proxying the host machine in the configuration, you can use the host IP as 172.17.0.1.
You can verify this with:
The GUI is straightforward.
Entering a Container
- Get the container ID:
- Enter:
1
| docker exec -i [ID] bash
|
Then you can use bash commands (though there is no bash prompt).
For Reference Only
Configuring Nginx and SSL manually took the longest and kept failing, so I switched to the GUI.
SSL Certificates
Used
neilpang/acme.sh
with DNS verification. For other methods, see
Run acme.sh in docker · acmesh-official/acme.sh Wiki (github.com)
.
Create folders and the file:
1
2
3
4
5
6
7
8
9
10
11
12
| version: '3.1'
services:
acme.sh:
image: neilpang/acme.sh
container_name: acme.sh
command: daemon
volumes:
- /root/acme/acme.sh:/acme.sh
- /root/acme/conf:/.acme.sh
environment:
- CF_Key="Your_CF_API_Key"
- CF_Email="Your_CF_Email"
|
For other DNS providers, refer to:
https://github.com/acmesh-official/acme.sh/wiki/dnsapi
Register an account:
Obtain certificate (using CF here):
1
| docker exec acme.sh --issue --dns dns_cf -d example.com -d www.example.com
|
The paths for the certificate and storage will be printed. Map this directory to the Nginx container.
You can set up a cron job to auto-renew certificates. Reference:
Linux Crontab Tasks - Runoob
References:
Docker obtaining Let’s Encrypt free SSL certificates - Tencent Cloud
ZeroSSL.com CA · acmesh-official/acme.sh Wiki (github.com)
Nginx
Create folder (e.g., /root/nginx), then create docker-compose.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
| version: '3.1'
services:
nginx:
restart: always
image: nginx
container_name: nginx
ports:
- 80:80
volumes:
- /root/docker/nginx/conf.d:/etc/nginx/conf.d
- /root/docker/nginx/www:/user/share/nfinx/html
- /root/docker/nginx/log:/var/log/nginx
- /root/acme/acme.sh:/ssl
|
After starting, you will find a conf.d folder. Create a new .conf file inside, such as default.conf:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| server {
listen 80;
listen [::]:80;
server_name <your_server_name>;
rewrite ^(.*)$ https://$host$1 permanent;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <your_server_name>;
# SSL cert location
ssl_certificate /path/to/ssl_cert;
# SSL key location
ssl_certificate_key /path/to/ssl_cert_key;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://172.17.0.1:9000/;
}
}
|
References:
Docker Nginx SSL and Host Proxy
Nginx SSL Configuration Detailed Guide - Aliyun
Docker Deploy Multiple Sites - CSDN
Let’s Encrypt HTTPS Tutorial - Diamond-Blog
Nginx Reverse Proxy Summary - Jianshu
Nginx Hide Port with Reverse Proxy - Blog Garden
References
Debian - Docker — Practice Guide (gitbook.io)
Install WordPress with Docker - Tencent Cloud
Solving WordPress upload_max_filesize in Docker - CSDN
Let’s Encrypt Could not bind to IPv4 or IPv6 - Liaosam
Let’s Encrypt Multi-domain and Wildcard Certs - Blog Garden
Docker Compose - Runoob
Nginx Config File Explained - Blog Garden
Using acme.sh in Docker for SSL - Moeelf
Installing Nginx with Docker and SSL configuration for Host Proxy